aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Kelly <steveire@gmail.com>2017-01-13 18:06:28 +0000
committerStephen Kelly <steveire@gmail.com>2017-01-13 18:06:28 +0000
commit8cf274317b437717f7e114e463de0652b973841b (patch)
tree13a8aaad17182a5abd29a7774a3f55a093c600b6
parentaf9f502f9629766130e171632d2072d563661959 (diff)
downloadextra-cmake-modules-8cf274317b437717f7e114e463de0652b973841b.tar.gz
extra-cmake-modules-8cf274317b437717f7e114e463de0652b973841b.tar.bz2
Bindings: Add rules engine for typedefs
Currently this is rather simple, allowing only matching typedefs by name. If we need more later, we can extend the interface. This will make it possible to add bindings for the K18n framework.
-rw-r--r--find-modules/Qt5Ruleset.py7
-rwxr-xr-xfind-modules/rules_engine.py76
-rw-r--r--find-modules/sip_generator.py19
-rw-r--r--tests/GenerateSipBindings/cpplib.cpp7
-rw-r--r--tests/GenerateSipBindings/cpplib.h16
-rw-r--r--tests/GenerateSipBindings/rules_SipTest.py7
6 files changed, 126 insertions, 6 deletions
diff --git a/find-modules/Qt5Ruleset.py b/find-modules/Qt5Ruleset.py
index 8ce6f8da..9392ae18 100644
--- a/find-modules/Qt5Ruleset.py
+++ b/find-modules/Qt5Ruleset.py
@@ -104,6 +104,9 @@ def variable_rules():
[".*", "d", ".*Private.*", rules_engine.variable_discard],
]
+def typedef_rules():
+ return []
+
class RuleSet(rules_engine.RuleSet):
"""
SIP file generator rules. This is a set of (short, non-public) functions
@@ -113,6 +116,7 @@ class RuleSet(rules_engine.RuleSet):
self._container_db = rules_engine.ContainerRuleDb(container_rules)
self._fn_db = rules_engine.FunctionRuleDb(function_rules)
self._param_db = rules_engine.ParameterRuleDb(parameter_rules)
+ self._typedef_db = rules_engine.TypedefRuleDb(typedef_rules)
self._var_db = rules_engine.VariableRuleDb(variable_rules)
self._methodcode = rules_engine.MethodCodeDb({})
self._modulecode = rules_engine.ModuleCodeDb({})
@@ -126,6 +130,9 @@ class RuleSet(rules_engine.RuleSet):
def parameter_rules(self):
return self._param_db
+ def typedef_rules(self):
+ return self._typedef_db
+
def variable_rules(self):
return self._var_db
diff --git a/find-modules/rules_engine.py b/find-modules/rules_engine.py
index 3bd6ccfc..64ce1d97 100755
--- a/find-modules/rules_engine.py
+++ b/find-modules/rules_engine.py
@@ -386,6 +386,68 @@ class ParameterRuleDb(AbstractCompiledRuleDb):
return None
+class TypedefRuleDb(AbstractCompiledRuleDb):
+ """
+ THE RULES FOR TYPEDEFS.
+
+ These are used to customise the behaviour of the SIP generator by allowing
+ the declaration for any typedef to be customised, for example to add SIP
+ compiler annotations.
+
+ Each entry in the raw rule database must be a list with members as follows:
+
+ 0. A regular expression which matches the fully-qualified name of the
+ "container" enclosing the typedef.
+
+ 1. A regular expression which matches the typedef name.
+
+ 2. A function.
+
+ In use, the database is walked in order from the first entry. If the regular
+ expressions are matched, the function is called, and no further entries are
+ walked. The function is called with the following contract:
+
+ def typedef_xxx(container, typedef, sip, matcher):
+ '''
+ Return a modified declaration for the given function.
+
+ :param container: The clang.cindex.Cursor for the container.
+ :param typedef: The clang.cindex.Cursor for the typedef.
+ :param sip: A dict with the following keys:
+
+ name The name of the typedef.
+ annotations Any SIP annotations.
+
+ :param matcher: The re.Match object. This contains named
+ groups corresponding to the key names above
+ EXCEPT annotations.
+
+ :return: An updated set of sip.xxx values. Setting sip.name to the
+ empty string will cause the container to be suppressed.
+ '''
+
+ :return: The compiled form of the rules.
+ """
+ def __init__(self, db):
+ super(TypedefRuleDb, self).__init__(db, ["container", "typedef"])
+
+ def apply(self, container, typedef, sip):
+ """
+ Walk over the rules database for typedefs, applying the first matching transformation.
+
+ :param container: The clang.cindex.Cursor for the container.
+ :param typedef: The clang.cindex.Cursor for the typedef.
+ :param sip: The SIP dict.
+ """
+ parents = _parents(typedef)
+ matcher, rule = self._match(parents, sip["name"])
+ if matcher:
+ before = deepcopy(sip)
+ rule.fn(container, typedef, sip, matcher)
+ return rule.trace_result(parents, typedef, before, sip)
+ return None
+
+
class VariableRuleDb(AbstractCompiledRuleDb):
"""
THE RULES FOR VARIABLES.
@@ -727,6 +789,15 @@ class RuleSet(object):
raise NotImplemented(_("Missing subclass implementation"))
@abstractmethod
+ def typedef_rules(self):
+ """
+ Return a compiled list of rules for typedefs.
+
+ :return: A TypedefRuleDb instance
+ """
+ raise NotImplemented(_("Missing subclass implementation"))
+
+ @abstractmethod
def variable_rules(self):
"""
Return a compiled list of rules for variables.
@@ -761,7 +832,7 @@ class RuleSet(object):
else:
logger.warn(_("Rule {} was not used".format(rule)))
- for db in [self.container_rules(), self.function_rules(), self.parameter_rules(),
+ for db in [self.container_rules(), self.function_rules(), self.parameter_rules(), self.typedef_rules(),
self.variable_rules(), self.methodcode_rules(), self.modulecode_rules()]:
db.dump_usage(dumper)
@@ -808,6 +879,9 @@ def function_discard_impl(container, function, sip, matcher):
if function.extent.start.column == 1:
sip["name"] = ""
+def typedef_discard(container, typedef, sip, matcher):
+ sip["name"] = ""
+
def rules(project_rules):
"""
Constructor.
diff --git a/find-modules/sip_generator.py b/find-modules/sip_generator.py
index e5e807ed..a8c164b5 100644
--- a/find-modules/sip_generator.py
+++ b/find-modules/sip_generator.py
@@ -228,7 +228,7 @@ class SipGenerator(object):
elif member.kind == CursorKind.CXX_ACCESS_SPEC_DECL:
decl = self._get_access_specifier(member, level + 1)
elif member.kind == CursorKind.TYPEDEF_DECL:
- decl = self._typedef_get(member, level + 1)
+ decl = self._typedef_get(container, member, level + 1)
elif member.kind == CursorKind.CXX_BASE_SPECIFIER:
#
# Strip off the leading "class". Except for TypeKind.UNEXPOSED...
@@ -627,7 +627,7 @@ class SipGenerator(object):
return _get_param_value(text, parameterType)
return ""
- def _typedef_get(self, typedef, level):
+ def _typedef_get(self, container, typedef, level):
"""
Generate the translation for a typedef.
@@ -637,10 +637,19 @@ class SipGenerator(object):
:return: A string.
"""
- pad = " " * (level * 4)
+ sip = {
+ "name": typedef.displayname,
+ "annotations": set(),
+ }
+
+ self.rules.typedef_rules().apply(container, typedef, sip)
- decl = pad + "typedef {} {}".format(typedef.underlying_typedef_type.spelling, typedef.displayname)
- decl += ";\n"
+ pad = " " * (level * 4)
+ if sip["name"]:
+ decl = pad + "typedef {} {}".format(typedef.underlying_typedef_type.spelling, typedef.displayname)
+ decl += ";\n"
+ else:
+ decl = pad + "// Discarded {}\n".format(SipGenerator.describe(typedef))
return decl
def _var_get(self, container, variable, level):
diff --git a/tests/GenerateSipBindings/cpplib.cpp b/tests/GenerateSipBindings/cpplib.cpp
index 7eb15939..f996c998 100644
--- a/tests/GenerateSipBindings/cpplib.cpp
+++ b/tests/GenerateSipBindings/cpplib.cpp
@@ -161,3 +161,10 @@ int anotherCustomMethod(QList<int> const& nums)
{
return 0;
}
+
+void TypedefUser::setTagPattern(const QString &tagName,
+ SomeNS::TagFormatter formatter,
+ int leadingNewlines)
+{
+
+}
diff --git a/tests/GenerateSipBindings/cpplib.h b/tests/GenerateSipBindings/cpplib.h
index b69480ee..34167ad3 100644
--- a/tests/GenerateSipBindings/cpplib.h
+++ b/tests/GenerateSipBindings/cpplib.h
@@ -128,8 +128,24 @@ qreal useEnum(MyFlags flags = EnumValueOne);
int customMethod(QList<int> const& nums);
+typedef QString(*TagFormatter)(const QStringList &languages,
+ const QString &tagName,
+ const QHash<QString, QString> &attributes,
+ const QString &text,
+ const QStringList &tagPath,
+ SomeNS::MyFlagType format);
+
}
+class TypedefUser
+{
+public:
+
+ void setTagPattern(const QString &tagName,
+ SomeNS::TagFormatter formatter = NULL,
+ int leadingNewlines = 0);
+};
+
int anotherCustomMethod(QList<int> const& nums);
enum __attribute__((visibility("default"))) EnumWithAttributes {
diff --git a/tests/GenerateSipBindings/rules_SipTest.py b/tests/GenerateSipBindings/rules_SipTest.py
index 1331da41..73c5451b 100644
--- a/tests/GenerateSipBindings/rules_SipTest.py
+++ b/tests/GenerateSipBindings/rules_SipTest.py
@@ -9,6 +9,12 @@ def local_function_rules():
return [
["MyObject", "fwdDecl", ".*", ".*", ".*", rules_engine.function_discard],
["MyObject", "fwdDeclRef", ".*", ".*", ".*", rules_engine.function_discard],
+ ["TypedefUser", "setTagPattern", ".*", ".*", ".*", rules_engine.function_discard],
+ ]
+
+def local_typedef_rules():
+ return [
+ [".*", "TagFormatter", rules_engine.typedef_discard],
]
def methodGenerator(function, sip, entry):
@@ -23,6 +29,7 @@ class RuleSet(Qt5Ruleset.RuleSet):
def __init__(self):
Qt5Ruleset.RuleSet.__init__(self)
self._fn_db = rules_engine.FunctionRuleDb(lambda: local_function_rules() + Qt5Ruleset.function_rules())
+ self._typedef_db = rules_engine.TypedefRuleDb(lambda: local_typedef_rules() + Qt5Ruleset.typedef_rules())
self._modulecode = rules_engine.ModuleCodeDb({
"cpplib.h": {
"code": """