From: Luca Bruno Date: Sun, 31 Oct 2010 22:16:32 +0000 (-0700) Subject: girparser: Add metadata stack while parsing the gir, generalize merging X-Git-Tag: 0.11.2~26 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c1bc467f0aa37d21c27a97099cd747f0c050aeb1;p=thirdparty%2Fvala.git girparser: Add metadata stack while parsing the gir, generalize merging --- diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala index 1592b8a01..da303b263 100644 --- a/vala/valagirparser.vala +++ b/vala/valagirparser.vala @@ -463,6 +463,11 @@ public class Vala.GirParser : CodeVisitor { } } + class SymbolInfo { + public Symbol symbol; + public Metadata metadata; + } + class CallbackScope { public Namespace parent_namespace; public UnresolvedSymbol gtype_struct_for; @@ -489,6 +494,11 @@ public class Vala.GirParser : CodeVisitor { string[] cheader_filenames; + ArrayList metadata_stack; + Metadata metadata; + + HashMap> current_symbols_info; + HashMap unresolved_symbols_map = new HashMap (unresolved_symbol_hash, unresolved_symbol_equal); HashMap concrete_symbols_map = new HashMap (); @@ -541,6 +551,17 @@ public class Vala.GirParser : CodeVisitor { } public void parse_file (SourceFile source_file) { + // load metadata + metadata_stack = new ArrayList (); + metadata = Metadata.empty; + string metadata_filename = "%s.metadata".printf (source_file.filename.ndup (source_file.filename.length - ".gir".length)); + if (FileUtils.test (metadata_filename, FileTest.EXISTS)) { + var metadata_parser = new MetadataParser (); + var metadata_file = new SourceFile (context, source_file.file_type, metadata_filename); + context.add_source_file (metadata_file); + metadata = metadata_parser.parse_metadata (metadata_file); + } + this.current_source_file = source_file; reader = new MarkupReader (source_file.filename); @@ -728,6 +749,149 @@ public class Vala.GirParser : CodeVisitor { } } + SymbolInfo? add_symbol_info (Symbol symbol) { + var name = symbol.name; + if (symbol is CreationMethod && name == null) { + name = ".new"; + } + + var info = new SymbolInfo (); + info.symbol = symbol; + info.metadata = metadata; + var colliding = current_symbols_info[name]; + if (colliding == null) { + colliding = new ArrayList (); + current_symbols_info[name] = colliding; + } + colliding.add (info); + return info; + } + + void merge (SymbolInfo info, ArrayList colliding, ArrayList merged) { + if (info.symbol is Property) { + foreach (var cinfo in colliding) { + var sym = cinfo.symbol; + if (sym is Signal || sym is Field) { + // properties take precedence + merged.add (cinfo); + } else if (sym is Method) { + // assume method is getter + merged.add (cinfo); + } + } + var getter_name = "get_%s".printf (info.symbol.name); + if (current_symbols_info.contains (getter_name)) { + ((Property) info.symbol).no_accessor_method = false; + } + } else if (info.symbol is Signal) { + var sig = (Signal) info.symbol; + foreach (var cinfo in colliding) { + var sym = cinfo.symbol; + if (sym is Method) { + var method = (Method) sym; + if (method.is_virtual) { + sig.is_virtual = true; + } else { + sig.has_emitter = true; + } + assume_parameter_names (sig, method); + merged.add (cinfo); + } else if (sym is Field) { + merged.add (cinfo); + } + } + } else if (info.symbol is Method && !(info.symbol is CreationMethod)) { + var method = (Method) info.symbol; + foreach (var cinfo in colliding) { + var sym = cinfo.symbol; + if (sym != method && method.is_virtual && sym is Method) { + // assume method is wrapper + merged.add (cinfo); + } + } + } else if (info.symbol is Field) { + foreach (var cinfo in colliding) { + var sym = cinfo.symbol; + if (sym is Method) { + // assume method is getter + merged.add (cinfo); + } + } + + var field = (Field) info.symbol; + if (field.variable_type is ArrayType) { + SymbolInfo array_length = null; + if (current_symbols_info.contains ("n_%s".printf (field.name))) { + array_length = current_symbols_info.get ("n_%s".printf (field.name)).get (0); + } else if (current_symbols_info.contains ("%s_length".printf (field.name))) { + array_length = current_symbols_info.get ("%s_length".printf (field.name)).get (0); + } + if (array_length != null) { + // array has length + field.set_array_length_cname (array_length.symbol.name); + field.no_array_length = false; + merged.add (array_length); + } + } + } + } + + void merge_add_process (Symbol container) { + var merged = new ArrayList (); + foreach (var name in current_symbols_info.get_keys ()) { + var colliding = current_symbols_info[name]; + foreach (var info in colliding) { + merge (info, colliding, merged); + } + } + + foreach (var infos in current_symbols_info.get_values ()) { + foreach (var info in infos) { + if (merged.contains (info)) { + continue; + } + add_symbol_to_container (container, info.symbol); + } + } + } + + Metadata get_current_metadata () { + var name = reader.name; + var child_name = reader.get_attribute ("name"); + if (child_name == null) { + return Metadata.empty; + } + + var type = MetadataType.GENERIC; + if (name == "glib:signal") { + type = MetadataType.SIGNAL; + } else if (name == "property") { + type = MetadataType.PROPERTY; + } + + return metadata.match_child (child_name, type); + } + + bool push_metadata () { + // skip? + if (reader.get_attribute ("introspectable") == "0") { + return false; + } + var new_metadata = get_current_metadata (); + if (new_metadata.get_bool (ArgumentType.SKIP)) { + return false; + } + + metadata_stack.add (metadata); + metadata = new_metadata; + return true; + } + + void pop_metadata () { + metadata = metadata_stack[metadata_stack.size - 1]; + metadata_stack.remove_at (metadata_stack.size - 1); + } + void parse_repository () { start_element ("repository"); if (reader.get_attribute ("version") != GIR_VERSION) { @@ -756,7 +920,7 @@ public class Vala.GirParser : CodeVisitor { } else { // error Report.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader.name)); - break; + skip_element (); } } end_element ("repository"); @@ -853,72 +1017,60 @@ public class Vala.GirParser : CodeVisitor { current_namespace_methods = new ArrayList (); namespace_methods[ns] = current_namespace_methods; } + var old_symbols_info = current_symbols_info; + current_symbols_info = new HashMap> (str_hash, str_equal); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } - Symbol sym = null; if (reader.name == "alias") { var alias = parse_alias (); aliases.add (alias); } else if (reader.name == "enumeration") { if (reader.get_attribute ("glib:error-quark") != null) { - sym = parse_error_domain (); + add_symbol_info (parse_error_domain ()); } else { - sym = parse_enumeration (); + add_symbol_info (parse_enumeration ()); } } else if (reader.name == "bitfield") { - sym = parse_bitfield (); + add_symbol_info (parse_bitfield ()); } else if (reader.name == "function") { current_namespace_methods.add (parse_method ("function")); } else if (reader.name == "callback") { - sym = parse_callback (); + add_symbol_info (parse_callback ()); } else if (reader.name == "record") { if (reader.get_attribute ("glib:get-type") != null) { - sym = parse_boxed (); + add_symbol_info (parse_boxed ()); } else { - sym = parse_record (); + var record = parse_record (); + if (record != null) { + add_symbol_info (record); + } } } else if (reader.name == "class") { - sym = parse_class (); + add_symbol_info (parse_class ()); } else if (reader.name == "interface") { - sym = parse_interface (); + add_symbol_info (parse_interface ()); } else if (reader.name == "glib:boxed") { - sym = parse_boxed (); + add_symbol_info (parse_boxed ()); } else if (reader.name == "union") { - sym = parse_union (); + add_symbol_info (parse_union ()); } else if (reader.name == "constant") { - sym = parse_constant (); + add_symbol_info (parse_constant ()); } else { // error Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name)); - break; + skip_element (); } - if (sym is Class) { - ns.add_class ((Class) sym); - } else if (sym is Interface) { - ns.add_interface ((Interface) sym); - } else if (sym is Struct) { - ns.add_struct ((Struct) sym); - } else if (sym is Enum) { - ns.add_enum ((Enum) sym); - } else if (sym is ErrorDomain) { - ns.add_error_domain ((ErrorDomain) sym); - } else if (sym is Delegate) { - ns.add_delegate ((Delegate) sym); - } else if (sym is Method) { - ns.add_method ((Method) sym); - } else if (sym is Constant) { - ns.add_constant ((Constant) sym); - } else if (sym == null) { - continue; - } + pop_metadata (); } end_element ("namespace"); + merge_add_process (ns); + current_symbols_info = old_symbols_info; current_namespace = old_namespace; if (!new_namespace) { @@ -975,7 +1127,7 @@ public class Vala.GirParser : CodeVisitor { string common_prefix = null; while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -986,8 +1138,11 @@ public class Vala.GirParser : CodeVisitor { calculate_common_prefix (ref common_prefix, ev.get_cname ()); } else { // error - break; + Report.error (get_current_src (), "unknown child element `%s' in `enumaration'".printf (reader.name)); + skip_element (); } + + pop_metadata (); } en.set_cprefix (common_prefix); @@ -1012,7 +1167,7 @@ public class Vala.GirParser : CodeVisitor { string common_prefix = null; while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1023,8 +1178,11 @@ public class Vala.GirParser : CodeVisitor { calculate_common_prefix (ref common_prefix, ec.get_cname ()); } else { // error - break; + Report.error (get_current_src (), "unknown child element `%s' in `enumeration'".printf (reader.name)); + skip_element (); } + + pop_metadata (); } ed.set_cprefix (common_prefix); @@ -1039,7 +1197,7 @@ public class Vala.GirParser : CodeVisitor { en.access = SymbolAccessibility.PUBLIC; next (); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1048,8 +1206,11 @@ public class Vala.GirParser : CodeVisitor { en.add_value (parse_enumeration_member ()); } else { // error - break; + Report.error (get_current_src (), "unknown child element `%s' in `bitfield'".printf (reader.name)); + skip_element (); } + + pop_metadata (); } end_element ("bitfield"); return en; @@ -1298,7 +1459,7 @@ public class Vala.GirParser : CodeVisitor { st.access = SymbolAccessibility.PUBLIC; next (); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1320,8 +1481,10 @@ public class Vala.GirParser : CodeVisitor { } else { // error Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name)); - break; + skip_element (); } + + pop_metadata (); } end_element ("record"); @@ -1351,12 +1514,10 @@ public class Vala.GirParser : CodeVisitor { } next (); - var signals = new ArrayList (); - var methods = new ArrayList (); - var vmethods = new ArrayList (); - var fields = new ArrayList (); + var old_symbols_info = current_symbols_info; + current_symbols_info = new HashMap> (str_hash, str_equal); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1367,87 +1528,40 @@ public class Vala.GirParser : CodeVisitor { next (); end_element ("implements"); } else if (reader.name == "constant") { - cl.add_constant (parse_constant ()); + add_symbol_info (parse_constant ()); } else if (reader.name == "field") { - fields.add (parse_field ()); + add_symbol_info (parse_field ()); } else if (reader.name == "property") { - cl.add_property (parse_property ()); + add_symbol_info (parse_property ()); } else if (reader.name == "constructor") { - cl.add_method (parse_constructor (cname)); + add_symbol_info (parse_constructor (cname)); } else if (reader.name == "function") { - methods.add (parse_method ("function")); + add_symbol_info (parse_method ("function")); } else if (reader.name == "method") { - methods.add (parse_method ("method")); + add_symbol_info (parse_method ("method")); } else if (reader.name == "virtual-method") { - vmethods.add (parse_method ("virtual-method")); + add_symbol_info (parse_method ("virtual-method")); } else if (reader.name == "union") { Struct s = parse_union (); var s_fields = s.get_fields (); foreach (var f in s_fields) { f.set_cname (s.get_cname () + "." + f.get_cname ()); f.name = s.name + "_" + f.name; - fields.add (f); + add_symbol_info (f); } } else if (reader.name == "glib:signal") { - signals.add (parse_signal ()); + add_symbol_info (parse_signal ()); } else { // error Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name)); - break; + skip_element (); } - } - // signal merging - foreach (Signal sig in signals) { - var symbol = cl.scope.lookup (sig.name); - if (symbol == null) { - cl.add_signal (sig); - } else if (symbol is Property) { - // properties take precedence - } else { - Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (sig.name, cl.name)); - } + pop_metadata (); } - // virtual method merging - foreach (Method m in vmethods) { - var symbol = cl.scope.lookup (m.name); - if (symbol == null) { - cl.add_method (m); - } else if (symbol is Signal) { - var sig = (Signal) symbol; - sig.is_virtual = true; - } else if (symbol is Property || symbol is Field) { - // assume method is getter for property/field ignore method - } else { - Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, cl.name)); - } - } - - // method merging - foreach (Method m in methods) { - var symbol = cl.scope.lookup (m.name); - if (symbol == null) { - cl.add_method (m); - } else if (symbol is Signal) { - var sig = (Signal) symbol; - sig.has_emitter = true; - } else if (symbol is Property || symbol is Field) { - // assume method is getter for property/field ignore method - } else if (symbol is Method) { - // assume method is wrapper for virtual method - } else { - Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, cl.name)); - } - } - - // fields have lowest priority - foreach (Field f in fields) { - var symbol = cl.scope.lookup (f.name); - if (symbol == null) { - cl.add_field (f); - } - } + merge_add_process (cl); + current_symbols_info = old_symbols_info; handle_async_methods (cl); @@ -1467,10 +1581,10 @@ public class Vala.GirParser : CodeVisitor { } next (); - var methods = new ArrayList (); - var vmethods = new ArrayList (); + var old_symbols_info = current_symbols_info; + current_symbols_info = new HashMap> (str_hash, str_equal); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1483,20 +1597,22 @@ public class Vala.GirParser : CodeVisitor { } else if (reader.name == "field") { parse_field (); } else if (reader.name == "property") { - iface.add_property (parse_property ()); + add_symbol_info (parse_property ()); } else if (reader.name == "virtual-method") { - vmethods.add (parse_method ("virtual-method")); + add_symbol_info (parse_method ("virtual-method")); } else if (reader.name == "function") { - methods.add (parse_method ("function")); + add_symbol_info (parse_method ("function")); } else if (reader.name == "method") { - methods.add (parse_method ("method")); + add_symbol_info (parse_method ("method")); } else if (reader.name == "glib:signal") { - iface.add_signal (parse_signal ()); + add_symbol_info (parse_signal ()); } else { // error Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name)); - break; + skip_element (); } + + pop_metadata (); } // ensure we have at least one instantiable prerequisite (GLib.Object) @@ -1511,33 +1627,8 @@ public class Vala.GirParser : CodeVisitor { if (!has_instantiable_prereq) iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object"))); - // virtual method merging - foreach (Method m in vmethods) { - var symbol = iface.scope.lookup (m.name); - if (symbol == null) { - iface.add_method (m); - } else if (symbol is Signal) { - var sig = (Signal) symbol; - sig.is_virtual = true; - } else { - Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, iface.name)); - } - } - - // method merging - foreach (Method m in methods) { - var symbol = iface.scope.lookup (m.name); - if (symbol == null) { - iface.add_method (m); - } else if (symbol is Signal) { - var sig = (Signal) symbol; - sig.has_emitter = true; - } else if (symbol is Method) { - // assume method is wrapper for virtual method - } else { - Report.error (get_current_src (), "duplicate member `%s' in `%s'".printf (m.name, iface.name)); - } - } + merge_add_process (iface); + current_symbols_info = old_symbols_info; handle_async_methods (iface); @@ -1617,6 +1708,7 @@ public class Vala.GirParser : CodeVisitor { } var field = new Field (name, type, null, get_current_src ()); field.access = SymbolAccessibility.PUBLIC; + field.no_array_length = true; if (allow_none == "1") { type.nullable = true; } @@ -1635,6 +1727,7 @@ public class Vala.GirParser : CodeVisitor { var type = parse_type (); var prop = new Property (name, type, null, null, get_current_src ()); prop.access = SymbolAccessibility.PUBLIC; + prop.no_accessor_method = true; if (readable != "0") { prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null); } @@ -1677,7 +1770,14 @@ public class Vala.GirParser : CodeVisitor { start_element ("parameters"); next (); while (current_token == MarkupTokenType.START_ELEMENT) { + if (!push_metadata ()) { + skip_element (); + continue; + } + m.add_parameter (parse_parameter ()); + + pop_metadata (); } end_element ("parameters"); } @@ -1759,6 +1859,11 @@ public class Vala.GirParser : CodeVisitor { next (); while (current_token == MarkupTokenType.START_ELEMENT) { + if (!push_metadata ()) { + skip_element (); + continue; + } + int array_length_idx, closure_idx, destroy_idx; string scope; string default_param_name = null; @@ -1788,6 +1893,7 @@ public class Vala.GirParser : CodeVisitor { } parameters.add (info); + pop_metadata (); } end_element ("parameters"); } @@ -1895,7 +2001,14 @@ public class Vala.GirParser : CodeVisitor { start_element ("parameters"); next (); while (current_token == MarkupTokenType.START_ELEMENT) { + if (!push_metadata ()) { + skip_element (); + continue; + } + sig.add_parameter (parse_parameter ()); + + pop_metadata (); } end_element ("parameters"); } @@ -1925,7 +2038,7 @@ public class Vala.GirParser : CodeVisitor { next (); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1939,8 +2052,10 @@ public class Vala.GirParser : CodeVisitor { } else { // error Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name)); - break; + skip_element (); } + + pop_metadata (); } if (current_token != MarkupTokenType.END_ELEMENT) { @@ -1959,7 +2074,7 @@ public class Vala.GirParser : CodeVisitor { next (); while (current_token == MarkupTokenType.START_ELEMENT) { - if (reader.get_attribute ("introspectable") == "0") { + if (!push_metadata ()) { skip_element (); continue; } @@ -1981,8 +2096,10 @@ public class Vala.GirParser : CodeVisitor { } else { // error Report.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader.name)); - break; + skip_element (); } + + pop_metadata (); } end_element ("union"); diff --git a/vapigen/valavapigen.vala b/vapigen/valavapigen.vala index 055765f5d..2968b0ae1 100644 --- a/vapigen/valavapigen.vala +++ b/vapigen/valavapigen.vala @@ -160,8 +160,16 @@ class Vala.VAPIGen : Object { // interface writer ignores external packages foreach (SourceFile file in context.get_source_files ()) { - if (!file.filename.has_suffix (".vapi") && file.filename in sources) { + if (file.filename.has_suffix (".vapi")) { + continue; + } + if (file.filename in sources) { file.file_type = SourceFileType.SOURCE; + } else if (file.filename.has_suffix (".metadata")) { + string gir_filename = "%s.gir".printf (file.filename.ndup (file.filename.length - ".metadata".length)); + if (gir_filename in sources) { + file.file_type = SourceFileType.SOURCE; + } } }