diff options
author | Mathieu Duponchelle <mathieu.duponchelle@opencreed.com> | 2015-07-15 13:11:45 +0200 |
---|---|---|
committer | Mathieu Duponchelle <mathieu@centricular.com> | 2019-07-19 01:21:38 +0200 |
commit | 0f3efc9058e2f249e84c02840fd96b6a413a9201 (patch) | |
tree | ea4628119b6573901c3426a16a74fced1c9c7822 /giscanner | |
parent | a62855702c3bc0b10370ef25d622a32e227283bd (diff) | |
download | gobject-introspection-0f3efc9058e2f249e84c02840fd96b6a413a9201.tar.gz |
scanner: parse and expose function macros
This is useful for documentation tools, and other utilities that
rely on full introspection of the C API of a given library.
Diffstat (limited to 'giscanner')
-rw-r--r-- | giscanner/ast.py | 10 | ||||
-rw-r--r-- | giscanner/girparser.py | 18 | ||||
-rw-r--r-- | giscanner/girwriter.py | 25 | ||||
-rw-r--r-- | giscanner/maintransformer.py | 12 | ||||
-rw-r--r-- | giscanner/scannerparser.y | 9 | ||||
-rw-r--r-- | giscanner/sourcescanner.h | 1 | ||||
-rw-r--r-- | giscanner/sourcescanner.py | 4 | ||||
-rw-r--r-- | giscanner/transformer.py | 24 |
8 files changed, 98 insertions, 5 deletions
diff --git a/giscanner/ast.py b/giscanner/ast.py index 2daccdfb..66fe0cf1 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -728,6 +728,14 @@ class Callable(Node): raise ValueError("Unknown argument %s" % (name, )) +class FunctionMacro(Node): + def __init__(self, name, parameters, symbol): + Node.__init__(self, name) + self.symbol = symbol + self.parameters = parameters + self.introspectable = False + + class Function(Callable): def __init__(self, name, retval, parameters, throws, symbol): @@ -868,7 +876,7 @@ class TypeContainer(Annotated): self.direction = direction if transfer is not None: self.transfer = transfer - elif typenode.is_const: + elif typenode and typenode.is_const: self.transfer = PARAM_TRANSFER_NONE else: self.transfer = None diff --git a/giscanner/girparser.py b/giscanner/girparser.py index 9ea408b4..7687c35c 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -142,6 +142,7 @@ class GIRParser(object): if not self._types_only: parser_methods[_corens('constant')] = self._parse_constant + parser_methods[_corens('function-macro')] = self._parse_function_macro parser_methods[_corens('function')] = self._parse_function for node in ns.getchildren(): @@ -310,6 +311,23 @@ class GIRParser(object): function = self._parse_function_common(node, ast.Function) self._namespace.append(function) + def _parse_function_macro(self, node): + name = node.attrib['name'] + symbol = node.attrib.get(_cns('identifier')) + parameters = [] + parameters_node = node.find(_corens('parameters')) + if (parameters_node is not None): + for paramnode in self._find_children(parameters_node, _corens('parameter')): + param = ast.Parameter(paramnode.attrib.get('name'), None) + parameters.append(param) + self._parse_generic_attribs(paramnode, param) + + func = ast.FunctionMacro(name, parameters, symbol) + self._parse_generic_attribs(node, func) + + self._namespace.track(func) + self._namespace.append(func) + def _parse_parameter(self, node): typeval = self._parse_type(node) param = ast.Parameter(node.attrib.get('name'), diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index 91875a2d..d1333cb7 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -90,6 +90,8 @@ class GIRWriter(XMLWriter): def _write_node(self, node): if isinstance(node, ast.Function): self._write_function(node) + elif isinstance(node, ast.FunctionMacro): + self._write_function_macro(node) elif isinstance(node, ast.Enum): self._write_enum(node) elif isinstance(node, ast.Bitfield): @@ -222,6 +224,15 @@ class GIRWriter(XMLWriter): attrs.append(('moved-to', func.moved_to)) self._write_callable(func, tag_name, attrs) + def _write_function_macro(self, macro): + attrs = [('name', macro.name), + ('c:identifier', macro.symbol)] + self._append_version(macro, attrs) + self._append_node_generic(macro, attrs) + with self.tagcontext('function-macro', attrs): + self._write_generic(macro) + self._write_untyped_parameters(macro) + def _write_method(self, method): self._write_function(method, tag_name='method') @@ -255,6 +266,20 @@ class GIRWriter(XMLWriter): for parameter in callable.parameters: self._write_parameter(callable, parameter) + def _write_untyped_parameters(self, macro): + if not macro.parameters: + return + with self.tagcontext('parameters'): + for parameter in macro.parameters: + self._write_untyped_parameter(macro, parameter) + + def _write_untyped_parameter(self, macro, parameter): + attrs = [] + if parameter.argname is not None: + attrs.append(('name', parameter.argname)) + with self.tagcontext('parameter', attrs): + self._write_generic(parameter) + def _write_parameter(self, parent, parameter, nodename='parameter'): attrs = [] if parameter.argname is not None: diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py index e1536b93..9468751d 100644 --- a/giscanner/maintransformer.py +++ b/giscanner/maintransformer.py @@ -176,6 +176,16 @@ class MainTransformer(object): block = self._blocks.get(node.symbol) self._apply_annotations_callable(node, chain, block) + def _apply_annotations_function_macro(self, node, chain): + block = self._blocks.get(node.symbol) + for param in node.parameters: + if block: + doc_param = block.params.get(param.argname) + if doc_param: + param.doc = doc_param.description + param.doc_position = doc_param.position + self._apply_annotations_annotated(node, block) + def _pass_read_annotations_early(self, node, chain): if isinstance(node, ast.Record): if node.ctype is not None: @@ -215,6 +225,8 @@ class MainTransformer(object): self._apply_annotations_alias(node, chain) if isinstance(node, ast.Function): self._apply_annotations_function(node, chain) + if isinstance(node, ast.FunctionMacro): + self._apply_annotations_function_macro(node, chain) if isinstance(node, ast.Callback): self._apply_annotations_callable(node, chain, block=self._get_block(node)) if isinstance(node, (ast.Class, ast.Interface, ast.Union, ast.Enum, diff --git a/giscanner/scannerparser.y b/giscanner/scannerparser.y index 29d98b41..6a2ffc1d 100644 --- a/giscanner/scannerparser.y +++ b/giscanner/scannerparser.y @@ -1500,6 +1500,15 @@ object_macro function_macro_define : function_macro '(' identifier_list ')' + { + GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_FUNCTION_MACRO, scanner->current_file, lineno); + GISourceType *func = gi_source_function_new (); + sym->ident = g_strdup ($1); + func->child_list = $3; + gi_source_symbol_merge_type (sym, func); + gi_source_scanner_add_symbol (scanner, sym); + gi_source_symbol_unref (sym); + } ; object_macro_define diff --git a/giscanner/sourcescanner.h b/giscanner/sourcescanner.h index a788abe9..40c5fc96 100644 --- a/giscanner/sourcescanner.h +++ b/giscanner/sourcescanner.h @@ -41,6 +41,7 @@ typedef enum CSYMBOL_TYPE_CONST, CSYMBOL_TYPE_OBJECT, CSYMBOL_TYPE_FUNCTION, + CSYMBOL_TYPE_FUNCTION_MACRO, CSYMBOL_TYPE_STRUCT, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_ENUM, diff --git a/giscanner/sourcescanner.py b/giscanner/sourcescanner.py index 471131c2..1632e1cb 100644 --- a/giscanner/sourcescanner.py +++ b/giscanner/sourcescanner.py @@ -41,11 +41,12 @@ ALL_EXTS = SOURCE_EXTS + HEADER_EXTS CSYMBOL_TYPE_CONST, CSYMBOL_TYPE_OBJECT, CSYMBOL_TYPE_FUNCTION, + CSYMBOL_TYPE_FUNCTION_MACRO, CSYMBOL_TYPE_STRUCT, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_TYPEDEF, - CSYMBOL_TYPE_MEMBER) = range(10) + CSYMBOL_TYPE_MEMBER) = range(11) (CTYPE_INVALID, CTYPE_VOID, @@ -90,6 +91,7 @@ def symbol_type_name(symbol_type): CSYMBOL_TYPE_CONST: 'const', CSYMBOL_TYPE_OBJECT: 'object', CSYMBOL_TYPE_FUNCTION: 'function', + CSYMBOL_TYPE_FUNCTION_MACRO: 'function_macro', CSYMBOL_TYPE_STRUCT: 'struct', CSYMBOL_TYPE_UNION: 'union', CSYMBOL_TYPE_ENUM: 'enum', diff --git a/giscanner/transformer.py b/giscanner/transformer.py index 9911de70..a3cf3126 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -31,7 +31,7 @@ from .sourcescanner import ( SourceSymbol, ctype_name, CTYPE_POINTER, CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF, CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT, - CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT, + CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_FUNCTION_MACRO, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT, CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT, CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST, TYPE_QUALIFIER_CONST, TYPE_QUALIFIER_VOLATILE) @@ -77,7 +77,11 @@ class Transformer(object): # handle #ifdef. But this introduces an arch-dependency in the .gir # file. So far this has only come up scanning glib - in theory, other # modules will just depend on that. - if isinstance(original, ast.Constant) and isinstance(node, ast.Constant): + if original and\ + (isinstance(original, ast.FunctionMacro) or isinstance(node, + ast.FunctionMacro)): + pass + elif isinstance(original, ast.Constant) and isinstance(node, ast.Constant): pass elif original is node: # Ignore attempts to add the same node to the namespace. This can @@ -368,6 +372,8 @@ raise ValueError.""" stype = symbol.type if stype == CSYMBOL_TYPE_FUNCTION: return self._create_function(symbol) + elif stype == CSYMBOL_TYPE_FUNCTION_MACRO: + return self._create_function_macro(symbol) elif stype == CSYMBOL_TYPE_TYPEDEF: return self._create_typedef(symbol) elif stype == CSYMBOL_TYPE_STRUCT: @@ -450,6 +456,15 @@ raise ValueError.""" func.add_symbol_reference(symbol) return func + def _create_function_macro(self, symbol): + if symbol.ident.startswith('_'): + return None + parameters = list(self._create_parameters(symbol, symbol.base_type)) + name = self._strip_symbol(symbol) + macro = ast.FunctionMacro(name, parameters, symbol.ident) + macro.add_symbol_reference(symbol) + return macro + def _create_source_type(self, source_type, is_parameter=False): assert source_type is not None if source_type.type == CTYPE_VOID: @@ -719,7 +734,10 @@ raise ValueError.""" if symbol.type == CSYMBOL_TYPE_ELLIPSIS: return ast.Parameter('...', ast.Varargs()) else: - ptype = self._create_type_from_base(symbol.base_type, is_parameter=True) + if symbol.base_type: + ptype = self._create_type_from_base(symbol.base_type, is_parameter=True) + else: + ptype = None if symbol.ident is None: if symbol.base_type and symbol.base_type.type != CTYPE_VOID: |