From: Luca Bruno Date: Sun, 29 Aug 2010 13:07:49 +0000 (+0200) Subject: girparser: Support symbol reparenting X-Git-Tag: 0.11.2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f6e2d413775b71616db74889f2a170efb08109ae;p=thirdparty%2Fvala.git girparser: Support symbol reparenting --- diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala index 5bef01659..2e1977372 100644 --- a/vala/valagirparser.vala +++ b/vala/valagirparser.vala @@ -24,6 +24,21 @@ using GLib; /** * Code visitor parsing all Vala source files. + * + * Pipeline: + * 1) Parse metadata + * 2) Parse GIR with metadata, track unresolved GIR symbols, create symbol mappings + * 3) Reconciliate the tree by mapping tracked symbols + * 4) Reparent nodes + * 5) Process callbacks/virtual + * 6) Process aliases + * + * Best hacking practices: + * - Keep GIR parsing bloat-free, it must contain the logic + * - Prefer being clean / short over performance + * - Try to make things common as much as possible + * - Prefer replace/merge after parse rather than a bunch of if-then-else and hardcoding + * - Prefer postprocessing over hardcoding the parser */ public class Vala.GirParser : CodeVisitor { enum MetadataType { @@ -505,6 +520,7 @@ public class Vala.GirParser : CodeVisitor { HashMap concrete_symbols_map = new HashMap (); ArrayList unresolved_gir_symbols = new ArrayList (); + HashMap> symbol_reparent_map = new HashMap> (unresolved_symbol_hash, unresolved_symbol_equal); HashMap> namespace_methods = new HashMap> (); HashMap> gtype_callbacks = new HashMap> (callback_scope_hash, callback_scope_equal); ArrayList aliases = new ArrayList (); @@ -522,6 +538,7 @@ public class Vala.GirParser : CodeVisitor { resolve_gir_symbols (); + postprocess_reparenting (); postprocess_gtype_callbacks (); postprocess_aliases (); postprocess_namespace_methods (); @@ -838,6 +855,24 @@ public class Vala.GirParser : CodeVisitor { } } + void postprocess_symbol (Symbol symbol, Metadata metadata) { + // mark to be reparented + if (metadata.has_argument (ArgumentType.PARENT)) { + var target_symbol = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT)); + var reparent_list = symbol_reparent_map[target_symbol]; + if (reparent_list == null) { + reparent_list = new ArrayList(); + symbol_reparent_map[target_symbol] = reparent_list; + } + reparent_list.add (symbol); + + // if referenceable, map unresolved references to point to the new place + if (symbol is Namespace || symbol is TypeSymbol) { + set_symbol_mapping (symbol, new UnresolvedSymbol (target_symbol, symbol.name)); + } + } + } + void merge_add_process (Symbol container) { var merged = new ArrayList (); foreach (var name in current_symbols_info.get_keys ()) { @@ -852,7 +887,10 @@ public class Vala.GirParser : CodeVisitor { if (merged.contains (info)) { continue; } - add_symbol_to_container (container, info.symbol); + if (!info.metadata.has_argument (ArgumentType.PARENT)) { + add_symbol_to_container (container, info.symbol); + } + postprocess_symbol (info.symbol, info.metadata); } } } @@ -2372,6 +2410,48 @@ public class Vala.GirParser : CodeVisitor { return null; } + void postprocess_reparenting () { + foreach (UnresolvedSymbol target_unresolved_symbol in symbol_reparent_map.get_keys ()) { + var target_symbol = resolve_symbol (context.root.scope, target_unresolved_symbol); + if (target_symbol == null) { + // create namespaces backward + var sym = target_unresolved_symbol; + var ns = new Namespace (sym.name, sym.source_reference); + var result = ns; + sym = sym.inner; + while (sym != null) { + var res = resolve_symbol (context.root.scope, sym); + if (res != null && !(res is Namespace)) { + result = null; + break; + } + var parent = res as Namespace; + if (res == null) { + parent = new Namespace (sym.name, sym.source_reference); + } + if (parent.scope.lookup (ns.name) == null) { + parent.add_namespace (ns); + } + ns = parent; + sym = sym.inner; + } + if (result != null && sym == null && context.root.scope.lookup (ns.name) == null) { + // a new root namespace, helpful for a possible non-gobject gir? + context.root.add_namespace (ns); + } + target_symbol = result; + } + if (target_symbol == null) { + Report.error (null, "unable to reparent into `%s'".printf (target_unresolved_symbol.to_string ())); + continue; + } + var symbols = symbol_reparent_map[target_unresolved_symbol]; + foreach (var symbol in symbols) { + add_symbol_to_container (target_symbol, symbol); + } + } + } + void postprocess_gtype_callbacks () { foreach (CallbackScope callback_scope in gtype_callbacks.get_keys ()) { var gtype = resolve_symbol (callback_scope.parent_namespace.scope, callback_scope.gtype_struct_for) as ObjectTypeSymbol;