summaryrefslogtreecommitdiff
path: root/giscanner
diff options
context:
space:
mode:
authorMathieu Duponchelle <mathieu.duponchelle@opencreed.com>2015-07-15 13:11:45 +0200
committerMathieu Duponchelle <mathieu@centricular.com>2019-07-19 01:21:38 +0200
commit0f3efc9058e2f249e84c02840fd96b6a413a9201 (patch)
treeea4628119b6573901c3426a16a74fced1c9c7822 /giscanner
parenta62855702c3bc0b10370ef25d622a32e227283bd (diff)
downloadgobject-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.py10
-rw-r--r--giscanner/girparser.py18
-rw-r--r--giscanner/girwriter.py25
-rw-r--r--giscanner/maintransformer.py12
-rw-r--r--giscanner/scannerparser.y9
-rw-r--r--giscanner/sourcescanner.h1
-rw-r--r--giscanner/sourcescanner.py4
-rw-r--r--giscanner/transformer.py24
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: