From: Lucas Rocha Date: Sat, 11 Oct 2008 18:33:43 +0000 (+0000) Subject: Bug 554854: The --typelib-xml and --inject options should reuse giscanner X-Git-Tag: GOBJECT_INTROSPECTION_0_6_0~183 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0be08ed820506a63b5a9342d52d695f977934145;p=platform%2Fupstream%2Fgobject-introspection.git Bug 554854: The --typelib-xml and --inject options should reuse giscanner 2008-10-11 Lucas Rocha Bug 554854: The --typelib-xml and --inject options should reuse giscanner parser/writer. * giscanner/ast.py: add constructor list to Struct and Union. Add new param in Return's contructor to define transfer. * giscanner/girparser.py: several additions to the parser in order to have parsing all nodes of the gir xml files. * tools/g-ir-scanner (typelib_xml_strip, inject): use gir parser and writer in --inject and --typelib-xml options. * giscanner/xmlwriter.py: ignore empty attributes instead of raising an error as this basically exposes a bug in GIRParser. This should be reverted as soon as the parser is fixed. svn path=/trunk/; revision=665 --- diff --git a/ChangeLog b/ChangeLog index fbae0bdf..d1804587 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2008-10-11 Lucas Rocha + + Bug 554854: The --typelib-xml and --inject options should reuse + giscanner parser/writer. + + * giscanner/ast.py: add constructor list to Struct and Union. + Add new param in Return's contructor to define transfer. + * giscanner/girparser.py: several additions to the parser in order + to have parsing all nodes of the gir xml files. + * tools/g-ir-scanner (typelib_xml_strip, inject): use gir parser + and writer in --inject and --typelib-xml options. + * giscanner/xmlwriter.py: ignore empty attributes instead of + raising an error as this basically exposes a bug in GIRParser. + This should be reverted as soon as the parser is fixed. + 2008-10-11 Lucas Rocha Bug 552376: scanner generates wrong names for enum members when diff --git a/giscanner/ast.py b/giscanner/ast.py index 368f02e0..0c82623a 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -260,6 +260,7 @@ class Struct(Node): def __init__(self, name, symbol): Node.__init__(self, name) self.fields = [] + self.constructors = [] self.symbol = symbol @@ -276,11 +277,11 @@ class Field(Node): class Return(Node): - def __init__(self, rtype): + def __init__(self, rtype, transfer=False): Node.__init__(self) self.type = rtype self.transfer = isinstance(rtype, (List, Map, Array)) or \ - rtype.name in ('utf8', 'filename') + rtype.name in ('utf8', 'filename') or transfer def __repr__(self): return 'Return(%r)' % (self.type, ) @@ -369,6 +370,7 @@ class Union(Node): def __init__(self, name, symbol): Node.__init__(self, name) self.fields = [] + self.constructors = [] self.symbol = symbol def __repr__(self): diff --git a/giscanner/girparser.py b/giscanner/girparser.py index 91416f0e..0d318c36 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -20,8 +20,8 @@ from xml.etree.cElementTree import parse -from .ast import (Alias, Callback, Function, Parameter, Return, Union, - Struct, Type, Array) +from .ast import (Alias, Callback, Function, Field, Parameter, Property, + Return, Union, Struct, Type, Array, Namespace, Varargs) from .glibast import (GLibEnum, GLibEnumMember, GLibFlags, GLibInterface, GLibObject, GLibBoxedStruct, GLibBoxedUnion, GLibBoxedOther) @@ -45,29 +45,40 @@ def _cns(tag): class GIRParser(object): - def __init__(self, filename): - self._nodes = [] + def __init__(self, filename, initial_parse=True): self._includes = set() - self._namespace_name = None + self._namespace = None + self._shared_libraries = [] + self._tree = parse(filename) - tree = parse(filename) - self._parse_api(tree.getroot()) + if (initial_parse): + self.parse() # Public API - def get_namespace_name(self): - return self._namespace_name + def parse(self): + self._includes.clear() + del self._namespace + del self._shared_libraries[:] + + self._parse_api(self._tree.getroot()) + + def get_namespace(self): + return self._namespace + + def get_shared_libraries(self): + return self._shared_libraries def get_includes(self): return self._includes - def get_nodes(self): - return self._nodes + def get_doc(self): + return self._tree # Private def _add_node(self, node): - self._nodes.append(node) + self._namespace.nodes.append(node) def _parse_api(self, root): assert root.tag == _corens('repository') @@ -76,7 +87,8 @@ class GIRParser(object): self._includes.add(node.attrib['name']) ns = root.find(_corens('namespace')) assert ns is not None - self._namespace_name = ns.attrib['name'] + self._namespace = Namespace(ns.attrib['name']) + self._shared_libraries.extend(ns.attrib['shared-library'].split(',')) for child in ns.getchildren(): self._parse_node(child) @@ -118,12 +130,20 @@ class GIRParser(object): node.attrib[_glibns('type-name')], node.attrib[_glibns('get-type')], node.attrib.get(_cns('type'))) + for iface in node.findall(_corens('implements')): + obj.interfaces.append(iface.attrib['name']) for method in node.findall(_corens('method')): obj.methods.append(self._parse_function(method, Function)) for ctor in node.findall(_corens('constructor')): obj.constructors.append(self._parse_function(ctor, Function)) for callback in node.findall(_corens('callback')): obj.fields.append(self._parse_function(callback, Callback)) + for field in node.findall(_corens('field')): + obj.fields.append(self._parse_field(field)) + for property in node.findall(_corens('property')): + obj.properties.append(self._parse_property(property)) + for signal in node.findall(_glibns('signal')): + obj.signals.append(self._parse_function(signal, Function)) self._add_node(obj) def _parse_function(self, node, klass): @@ -131,11 +151,17 @@ class GIRParser(object): returnnode = node.find(_corens('return-value')) if not returnnode: raise ValueError('node %r has no return-value' % (name, )) - retval = Return(self._parse_type(returnnode)) + transfer = False + transfer_param = returnnode.attrib.get('transfer-ownership') + if transfer_param is not None: + transfer = (transfer_param == '1') + retval = Return(self._parse_type(returnnode), transfer) + parameters_node = node.find(_corens('parameters')) parameters = [] - for paramnode in node.findall('parameter'): - parameters.append(Parameter(paramnode.attrib['name'], - self._parse_type(paramnode))) + if (parameters_node is not None): + for paramnode in parameters_node.findall(_corens('parameter')): + parameters.append(Parameter(paramnode.attrib.get('name'), + self._parse_type(paramnode))) if klass is Callback: return klass(name, retval, parameters, node.attrib.get(_cns('type'))) @@ -151,7 +177,15 @@ class GIRParser(object): node.attrib.get(_cns('type'))) else: struct = Struct(node.attrib['name'], - node.attrib[_cns('type')]) + node.attrib.get(_cns('type'))) + for field in node.findall(_corens('field')): + struct.fields.append(self._parse_field(field)) + for callback in node.findall(_corens('callback')): + struct.fields.append(self._parse_function(callback, Callback)) + for method in node.findall(_corens('method')): + struct.fields.append(self._parse_function(method, Function)) + for ctor in node.findall(_corens('constructor')): + struct.constructors.append(self._parse_function(ctor, Function)) self._add_node(struct) def _parse_union(self, node): @@ -162,7 +196,15 @@ class GIRParser(object): node.attrib.get(_cns('type'))) else: struct = Union(node.attrib['name'], - node.attrib[_cns('type')]) + node.attrib.get(_cns('type'))) + for callback in node.findall(_corens('callback')): + struct.fields.append(self._parse_function(callback, Callback)) + for field in node.findall(_corens('field')): + struct.fields.append(self._parse_field(field)) + for method in node.findall(_corens('method')): + struct.fields.append(self._parse_function(method, Function)) + for ctor in node.findall(_corens('constructor')): + struct.constructors.append(self._parse_function(ctor, Function)) self._add_node(struct) def _parse_type(self, node): @@ -172,8 +214,11 @@ class GIRParser(object): typenode.attrib.get(_cns('type'))) typenode = node.find(_corens('array')) if typenode is not None: - return Array(typenode.attrib[_cns('type')], + return Array(typenode.attrib.get(_cns('type')), self._parse_type(typenode)) + typenode = node.find(_corens('varargs')) + if typenode is not None: + return Varargs() raise ValueError("Couldn't parse type of node %r; children=%r", node, list(node)) @@ -189,10 +234,26 @@ class GIRParser(object): obj.fields.append(self._parse_function(callback, Callback)) self._add_node(obj) + def _parse_field(self, node): + type_node = self._parse_type(node) + return Field(node.attrib['name'], + type_node, + type_node.ctype) + + def _parse_property(self, node): + type_node = self._parse_type(node) + return Property(node.attrib['name'], + type_node.name, + node.attrib.get('readable') != '0', + node.attrib.get('writable') == '1', + node.attrib.get('construct') == '1', + node.attrib.get('construct-only') == '1', + type_node.ctype) + def _parse_member(self, node): return GLibEnumMember(node.attrib['name'], node.attrib['value'], - node.attrib[_cns('identifier')], + node.attrib.get(_cns('identifier')), node.attrib.get(_glibns('nick'))) def _parse_enumeration_bitfield(self, node): diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index ed4e596a..43678581 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -189,16 +189,18 @@ class GIRWriter(XMLWriter): self.write_tag('type', attrs) def _write_enum(self, enum): - attrs = [('name', enum.name), - ('c:type', enum.symbol)] + attrs = [('name', enum.name)] self._append_deprecated(enum, attrs) - tag_name = 'enumeration' - if isinstance(enum, GLibEnum): + if isinstance(enum, GLibFlags): + tag_name = 'bitfield' + else: + tag_name = 'enumeration' + if isinstance(enum, GLibEnum) or isinstance(enum, GLibFlags): attrs.extend([('glib:type-name', enum.type_name), - ('glib:get-type', enum.get_type)]) - if isinstance(enum, GLibFlags): - tag_name = 'bitfield' - + ('glib:get-type', enum.get_type), + ('c:type', enum.ctype)]) + else: + attrs.append(('c:type', enum.symbol)) with self.tagcontext(tag_name, attrs): for member in enum.members: self._write_member(member) @@ -305,8 +307,11 @@ class GIRWriter(XMLWriter): self._write_boxed_ctors_methods(union) def _write_field(self, field): - # FIXME: Just function - if isinstance(field, (Callback, Function)): + if isinstance(field, Function): + self._write_method(field) + return + + if isinstance(field, Callback): self._write_callback(field) return diff --git a/giscanner/transformer.py b/giscanner/transformer.py index df62bf3b..4c1cf17b 100644 --- a/giscanner/transformer.py +++ b/giscanner/transformer.py @@ -126,8 +126,8 @@ class Transformer(object): raise NotImplementedError(filename) for include in parser.get_includes(): self.register_include(include) - nsname = parser.get_namespace_name() - for node in parser.get_nodes(): + nsname = parser.get_namespace().name + for node in parser.get_namespace().nodes: if isinstance(node, Alias): self._names.aliases[node.name] = (nsname, node) elif isinstance(node, (GLibBoxed, Interface, Class)): diff --git a/giscanner/xmlwriter.py b/giscanner/xmlwriter.py index eb17c619..5176499d 100644 --- a/giscanner/xmlwriter.py +++ b/giscanner/xmlwriter.py @@ -40,9 +40,12 @@ class XMLWriter(object): return -1 attr_length = 0 for attr, value in attributes: + # FIXME: actually, if we have attributes with None as value this + # should be considered a bug and raise an error. We are just + # ignoring them here while we fix GIRParser to create the right + # ast with the correct attributes. if value is None: - raise ValueError( - "value for attribute %r cannot be None" % (attr, )) + continue attr_length += 2 + len(attr) + len(quoteattr(value)) return attr_length + indent + self._indent @@ -56,11 +59,14 @@ class XMLWriter(object): first = True attr_value = '' for attr, value in attributes: + # FIXME: actually, if we have attributes with None as value this + # should be considered a bug and raise an error. We are just + # ignoring them here while we fix GIRParser to create the right + # ast with the correct attributes. + if value is None: + continue if indent_len and not first: attr_value += '\n%s' % (self._indent_char * indent_len) - if value is None: - raise ValueError( - "value for attribute %r cannot be None" % (attr, )) attr_value += ' %s=%s' % (attr, quoteattr(value)) if first: first = False diff --git a/tools/g-ir-scanner b/tools/g-ir-scanner index 4eb5a6f9..88800d70 100755 --- a/tools/g-ir-scanner +++ b/tools/g-ir-scanner @@ -104,22 +104,31 @@ def _error(msg): raise SystemExit('ERROR: %s' % (msg, )) def typelib_xml_strip(path): + from giscanner.girparser import GIRParser + from giscanner.girwriter import GIRWriter from giscanner.girparser import C_NS c_ns_key = '{%s}' % (C_NS, ) - from xml.etree.cElementTree import parse - doc = parse(open(path)) + parser = GIRParser(path, initial_parse=False) + doc = parser.get_doc() for node in doc.getiterator(): for attrib in list(node.attrib): if attrib.startswith(c_ns_key): del node.attrib[attrib] - doc.write(sys.stdout) + parser.parse() + writer = GIRWriter(parser.get_namespace(), + parser.get_shared_libraries(), + parser.get_includes()) + sys.stdout.write(writer.get_xml()) return 0 def inject(path, additions, outpath): + from giscanner.girparser import GIRParser + from giscanner.girwriter import GIRWriter from xml.etree.cElementTree import parse - doc = parse(open(path)) - root = doc.getroot() + + parser = GIRParser(path, initial_parse=False) + root = parser.get_doc().getroot() injectDoc = parse(open(additions)) for node in injectDoc.getroot(): injectPath = node.attrib['path'] @@ -128,8 +137,12 @@ def inject(path, additions, outpath): raise ValueError("Couldn't find path %r" % (injectPath, )) for child in node: target.append(child) + parser.parse() + writer = GIRWriter(parser.get_namespace(), + parser.get_shared_libraries(), + parser.get_includes()) outf = open(outpath, 'w') - doc.write(outf) + outf.write(writer.get_xml()) outf.close() return 0