[vala] girparser: Refactoring, create GIR nodes to improve the tree analysis
- From: Luca Bruno <lucabru src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala] girparser: Refactoring, create GIR nodes to improve the tree analysis
- Date: Tue, 26 Apr 2011 20:12:10 +0000 (UTC)
commit 996e51c1c92a5b865d2daf7b9ba4b804c090de43
Author: Luca Bruno <lucabru src gnome org>
Date: Sun Apr 24 14:57:48 2011 +0200
girparser: Refactoring, create GIR nodes to improve the tree analysis
vala/valagirparser.vala | 2058 ++++++++++++++++++++++++-----------------------
1 files changed, 1044 insertions(+), 1014 deletions(-)
---
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index b7168ff..3864d2b 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -25,26 +25,19 @@
using GLib;
/**
- * Code visitor parsing all Vala source files.
+ * Code visitor parsing all GIR source files.
*
* Pipeline:
* 1) Parse metadata
- * 2) Parse GIR with metadata, track unresolved GIR symbols, create symbol mappings
+ * 2) Parse GIR with metadata, track unresolved GIR symbols, create Vala symbols
* 3) Reconciliate the tree by mapping tracked symbols
- * 4) Reparent nodes
- * 5) Process callbacks/virtual
- * 6) Process aliases
- * 7) Autoreparent static methods
- * 8) Process callables
- *
- * 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
+ * 4) Process the tree
*/
public class Vala.GirParser : CodeVisitor {
+ /*
+ * Metadata parser
+ */
+
enum ArgumentType {
SKIP,
HIDDEN,
@@ -469,19 +462,327 @@ public class Vala.GirParser : CodeVisitor {
}
}
- class SymbolInfo {
- public Symbol symbol;
- public Metadata metadata;
- // additional information from GIR
- public Map<string,string> girdata;
- }
+ /*
+ * GIR parser
+ */
- class Alias {
+ class Node {
+ public static ArrayList<Node> new_namespaces = new ArrayList<Node> ();
+
+ public weak Node parent;
+ public string element_type;
public string name;
- public string cname;
+ public Map<string,string> girdata = null;
+ public Metadata metadata = Metadata.empty;
+ public SourceReference source_reference = null;
+ public ArrayList<Node> members = new ArrayList<Node> (); // guarantees fields order
+ public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>> (str_hash, str_equal);
+
+ public Symbol symbol;
+ public bool new_symbol;
+ public bool merged;
+ public bool processed;
+
+ // function-specific
+ public List<ParameterInfo> parameters;
+ public ArrayList<int> array_length_parameters;
+ public ArrayList<int> closure_parameters;
+ public ArrayList<int> destroy_parameters;
+ // alias-specific
public DataType base_type;
- public Symbol parent_symbol;
- public SourceReference source_reference;
+
+ public Node (string? name) {
+ this.name = name;
+ }
+
+ public void add_member (Node node) {
+ var nodes = scope[node.name];
+ if (nodes == null) {
+ nodes = new ArrayList<Node> ();
+ scope[node.name] = nodes;
+ }
+ nodes.add (node);
+ members.add (node);
+ node.parent = this;
+ }
+
+ public Node? lookup (string name, bool create_namespace = false, SourceReference? source_reference = null) {
+ var nodes = scope[name];
+ Node node = null;
+ if (nodes != null) {
+ node = nodes[0];
+ }
+ if (node == null) {
+ Symbol sym = null;
+ if (symbol != null) {
+ sym = symbol.scope.lookup (name);
+ }
+ if (sym != null || create_namespace) {
+ node = new Node (name);
+ node.symbol = sym;
+ node.new_symbol = node.symbol == null;
+ node.source_reference = source_reference;
+ add_member (node);
+
+ if (sym == null) {
+ new_namespaces.add (node);
+ }
+ }
+ }
+ return node;
+ }
+
+ public ArrayList<Node>? lookup_all (string name) {
+ return scope[name];
+ }
+
+ public UnresolvedSymbol get_unresolved_symbol () {
+ if (parent.name == null) {
+ return new UnresolvedSymbol (null, name);
+ } else {
+ return new UnresolvedSymbol (parent.get_unresolved_symbol (), name);
+ }
+ }
+
+ public void process (GirParser parser) {
+ if (processed) {
+ return;
+ }
+
+ // process children allowing node removals
+ for (int i=0; i < members.size; i++) {
+ var node = members[i];
+ node.process (parser);
+ if (i < members.size && members[i] != node) {
+ // node removed in the middle
+ i--;
+ }
+ }
+
+ if (girdata != null) {
+ // GIR node processing
+ if (symbol is Method) {
+ var m = (Method) symbol;
+ parser.process_callable (this);
+
+ var colliding = parent.lookup_all (name);
+ foreach (var node in colliding) {
+ var sym = node.symbol;
+ if (sym is Field && !(m.return_type is VoidType) && m.get_parameters().size == 0) {
+ // assume method is getter
+ merged = true;
+ } else if (sym is Signal) {
+ var sig = (Signal) sym;
+ if (m.is_virtual) {
+ sig.is_virtual = true;
+ } else {
+ sig.has_emitter = true;
+ }
+ parser.assume_parameter_names (sig, m, false);
+ merged = true;
+ } else if (sym is Method && !(sym is CreationMethod) && node != this) {
+ if (m.is_virtual) {
+ bool different_invoker = false;
+ foreach (var attr in m.attributes) {
+ if (attr.name == "NoWrapper") {
+ /* no invoker but this method has the same name,
+ most probably the invoker has a different name
+ and g-ir-scanner missed it */
+ var invoker = parser.find_invoker (this);
+ if (invoker != null) {
+ m.vfunc_name = m.name;
+ m.name = invoker.symbol.name;
+ m.attributes.remove (attr);
+ invoker.processed = true;
+ invoker.merged = true;
+ different_invoker = true;
+ }
+ }
+ }
+ if (!different_invoker) {
+ node.processed = true;
+ node.merged = true;
+ }
+ }
+ }
+ }
+ if (!(m is CreationMethod)) {
+ // merge custom vfunc
+ if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
+ var vfunc = parent.lookup (metadata.get_string (ArgumentType.VFUNC_NAME));
+ if (vfunc != null && vfunc != this) {
+ vfunc.processed = true;
+ vfunc.merged = true;
+ }
+ }
+ }
+ if (m.coroutine) {
+ parser.process_async_method (this);
+ }
+ } else if (symbol is Property) {
+ var getter = parent.lookup ("get_%s".printf (name));
+ var setter = parent.lookup ("set_%s".printf (name));
+ var colliding = parent.lookup_all (name);
+ foreach (var node in colliding) {
+ if (node.symbol is Signal) {
+ // properties take precedence
+ node.processed = true;
+ node.merged = true;
+ } else if (node.symbol is Method) {
+ // try assuming it's the getter
+ getter = node;
+ }
+ }
+ var prop = (Property) symbol;
+ if (prop.no_accessor_method) {
+ // property getter and setter must be matched both, otherwise it's NoAccessorMethod
+ prop.no_accessor_method = false;
+ if (prop.get_accessor != null) {
+ var m = getter != null ? getter.symbol as Method : null;
+ if (m != null) {
+ getter.process (parser);
+ if (m.return_type is VoidType || m.get_parameters().size != 0) {
+ prop.no_accessor_method = true;
+ } else {
+ if (getter.name == name) {
+ getter.merged = true;
+ }
+ prop.get_accessor.value_type.value_owned = m.return_type.value_owned;
+ }
+ } else {
+ prop.no_accessor_method = true;
+ }
+ }
+ if (!prop.no_accessor_method && prop.set_accessor != null && prop.set_accessor.writable) {
+ var m = setter != null ? setter.symbol as Method : null;
+ if (m != null) {
+ setter.process (parser);
+ if (!(m.return_type is VoidType) || m.get_parameters().size != 1) {
+ prop.no_accessor_method = true;
+ }
+ } else {
+ prop.no_accessor_method = true;
+ }
+ }
+ }
+ } else if (symbol is Field) {
+ var field = (Field) symbol;
+ var colliding = parent.lookup_all (name);
+ if (colliding.size > 1) {
+ // whatelse has precedence over the field
+ merged = true;
+ }
+
+ var gtype_struct_for = parent.girdata["glib:is-gtype-struct-for"];
+ if (field.variable_type is DelegateType && gtype_struct_for != null) {
+ // virtual method field
+ var d = ((DelegateType) field.variable_type).delegate_symbol;
+ parser.process_virtual_method_field (this, d, parser.parse_symbol_from_string (gtype_struct_for, d.source_reference));
+ merged = true;
+ } else if (field.variable_type is ArrayType) {
+ var array_length = parent.lookup ("n_%s".printf (field.name));
+ if (array_length == null) {
+ array_length = parent.lookup ("%s_length".printf (field.name));
+ }
+ if (array_length != null) {
+ // array has length
+ field.set_array_length_cname (array_length.symbol.name);
+ field.no_array_length = false;
+ field.array_null_terminated = false;
+ array_length.processed = true;
+ array_length.merged = true;
+ }
+ }
+ } else if (symbol is Signal || symbol is Delegate) {
+ parser.process_callable (this);
+ } else if (symbol is Interface) {
+ parser.process_interface (this);
+ } else if (element_type == "alias") {
+ parser.process_alias (this);
+ } else if (symbol is Struct) {
+ if (parent.symbol is Struct) {
+ // nested struct
+ var st = (Struct) parent.symbol;
+ foreach (var fn in members) {
+ var f = fn.symbol as Field;
+ if (f != null) {
+ f.set_cname (st.get_cname () + "." + f.get_cname ());
+ f.name = symbol.name + "_" + f.name;
+ fn.name = f.name;
+ parent.add_member (fn);
+ }
+ }
+ merged = true;
+ } else {
+ // record for a gtype
+ var gtype_struct_for = girdata["glib:is-gtype-struct-for"];
+ if (gtype_struct_for != null) {
+ var iface = parser.resolve_symbol (parent, parser.parse_symbol_from_string (gtype_struct_for, source_reference)) as Interface;
+ if (iface != null) {
+ // set the interface struct name
+ iface.set_type_cname (((Struct) symbol).get_cname ());
+ }
+ merged = true;
+ }
+ }
+ }
+
+ // deprecation
+ symbol.replacement = metadata.get_string (ArgumentType.REPLACEMENT);
+ symbol.deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
+ if (symbol.deprecated_since == null) {
+ symbol.deprecated_since = girdata.get ("deprecated-version");
+ }
+ symbol.deprecated = metadata.get_bool (ArgumentType.DEPRECATED) || symbol.replacement != null || symbol.deprecated_since != null;
+
+ // cheader filename
+ var cheader_filename = metadata.get_string (ArgumentType.CHEADER_FILENAME);
+ if (cheader_filename != null) {
+ foreach (string filename in cheader_filename.split (",")) {
+ symbol.add_cheader_filename (filename);
+ }
+ }
+ }
+
+ var ns = symbol as Namespace;
+ if (!(new_symbol && merged) && is_container (symbol)) {
+ foreach (var node in members) {
+ if (node.new_symbol && !node.merged && !metadata.get_bool (ArgumentType.HIDDEN) && !(ns != null && node.symbol is Method)) {
+ add_symbol_to_container (symbol, node.symbol);
+ }
+ }
+
+ var cl = symbol as Class;
+ if (cl != null && cl.default_construction_method == null) {
+ // always provide constructor in generated bindings
+ // to indicate that implicit Object () chainup is allowed
+ var cm = new CreationMethod (null, null, cl.source_reference);
+ cm.has_construct_function = false;
+ cm.access = SymbolAccessibility.PROTECTED;
+ cl.add_method (cm);
+ } else if (symbol is Namespace) {
+ // postprocess namespace methods
+ foreach (var nodes in scope.get_values ()) {
+ foreach (var node in nodes) {
+ var m = node.symbol as Method;
+ if (m != null) {
+ parser.process_namespace_method (ns, m);
+ }
+ }
+ }
+ }
+ }
+
+ processed = true;
+ }
+
+ public string to_string () {
+ if (parent.name == null) {
+ return name;
+ } else {
+ return "%s.%s".printf (parent.to_string (), name);
+ }
+ }
}
static GLib.Regex type_from_string_regex;
@@ -492,9 +793,8 @@ public class Vala.GirParser : CodeVisitor {
Namespace glib_ns;
SourceFile current_source_file;
- Symbol current_symbol;
+ Node root;
- string current_gtype_struct_for;
SourceLocation begin;
SourceLocation end;
MarkupTokenType current_token;
@@ -503,22 +803,12 @@ public class Vala.GirParser : CodeVisitor {
ArrayList<Metadata> metadata_stack;
Metadata metadata;
- ArrayList<Map<string,string>> girdata_stack;
- Map<string,string> girdata;
-
- ArrayList<SymbolInfo> current_symbols_info;
+ ArrayList<Node> tree_stack;
+ Node current;
+ Node old_current;
HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol> (unresolved_symbol_hash, unresolved_symbol_equal);
- HashMap<Symbol,Symbol> concrete_symbols_map = new HashMap<Symbol,Symbol> ();
-
ArrayList<UnresolvedSymbol> unresolved_gir_symbols = new ArrayList<UnresolvedSymbol> ();
- HashMap<UnresolvedSymbol,ArrayList<Symbol>> symbol_reparent_map = new HashMap<UnresolvedSymbol,ArrayList<Symbol>> (unresolved_symbol_hash, unresolved_symbol_equal);
- ArrayList<CallableInfo> callable_info_list = new ArrayList<CallableInfo> ();
- HashMap<Namespace,ArrayList<Method>> namespace_methods = new HashMap<Namespace,ArrayList<Method>> ();
- ArrayList<Alias> aliases = new ArrayList<Alias> ();
- ArrayList<Interface> interfaces = new ArrayList<Interface> ();
-
- HashMap<UnresolvedSymbol,ArrayList<Delegate>> gtype_callbacks;
/**
* Parses all .gir source files in the specified code
@@ -529,15 +819,22 @@ public class Vala.GirParser : CodeVisitor {
public void parse (CodeContext context) {
this.context = context;
glib_ns = context.root.scope.lookup ("GLib") as Namespace;
+
+ root = new Node (null);
+ root.symbol = context.root;
+ tree_stack = new ArrayList<Node> ();
+ current = root;
+
context.accept (this);
resolve_gir_symbols ();
+ create_new_namespaces ();
- postprocess_interfaces ();
- postprocess_reparenting ();
- postprocess_aliases ();
- postprocess_namespace_methods ();
- postprocess_callables ();
+ root.process (this);
+
+ foreach (var node in root.members) {
+ report_unused_metadata (node.metadata);
+ }
}
public override void visit_source_file (SourceFile source_file) {
@@ -568,7 +865,6 @@ public class Vala.GirParser : CodeVisitor {
public void parse_file (SourceFile source_file) {
metadata_stack = new ArrayList<Metadata> ();
metadata = Metadata.empty;
- girdata_stack = new ArrayList<HashMap<string,string>> ();
// load metadata, first look into metadata directories then in the same directory of the .gir.
string? metadata_filename = context.get_metadata_path (source_file.filename);
@@ -622,16 +918,7 @@ public class Vala.GirParser : CodeVisitor {
const string GIR_VERSION = "1.2";
- void add_symbol_to_container (Symbol container, Symbol sym) {
- var name = sym.name;
- if (name == null && sym is CreationMethod) {
- name = ".new";
- }
- if (container.scope.lookup (name) != null) {
- // overridden by -custom.vala
- return;
- }
-
+ static void add_symbol_to_container (Symbol container, Symbol sym) {
if (container is Class) {
unowned Class cl = (Class) container;
@@ -720,11 +1007,23 @@ public class Vala.GirParser : CodeVisitor {
} else if (sym is Property) {
st.add_property ((Property) sym);
}
+ } else if (container is ErrorDomain) {
+ unowned ErrorDomain ed = (ErrorDomain) container;
+
+ if (sym is ErrorCode) {
+ ed.add_code ((ErrorCode) sym);
+ } else if (sym is Method) {
+ ed.add_method ((Method) sym);
+ }
} else {
- Report.error (sym.source_reference, "impossible to add to container `%s'".printf (container.name));
+ Report.error (sym.source_reference, "impossible to add `%s' to container `%s'".printf (sym.name, container.name));
}
}
+ static bool is_container (Symbol sym) {
+ return sym is ObjectTypeSymbol || sym is Struct || sym is Namespace || sym is ErrorDomain || sym is Enum;
+ }
+
UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
UnresolvedSymbol? sym = null;
foreach (unowned string s in symbol_string.split (".")) {
@@ -736,26 +1035,10 @@ public class Vala.GirParser : CodeVisitor {
return sym;
}
- UnresolvedSymbol get_unresolved_symbol (Symbol symbol) {
- if (symbol is UnresolvedSymbol) {
- return (UnresolvedSymbol) symbol;
- }
- var sym = new UnresolvedSymbol (null, symbol.name);
- var result = sym;
- var cur = symbol.parent_node as Symbol;
- while (cur != null && cur.name != null) {
- sym = new UnresolvedSymbol (sym, cur.name);
- cur = cur.parent_node as Symbol;
- }
- return result;
- }
-
- void set_symbol_mapping (Symbol map_from, Symbol map_to) {
+ void set_symbol_mapping (UnresolvedSymbol map_from, Symbol map_to) {
// last mapping is the most up-to-date
if (map_from is UnresolvedSymbol) {
unresolved_symbols_map[(UnresolvedSymbol) map_from] = map_to;
- } else {
- concrete_symbols_map[map_from] = map_to;
}
}
@@ -783,318 +1066,35 @@ 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;
- info.girdata = girdata;
- current_symbols_info.add (info);
- return info;
- }
-
- ArrayList<SymbolInfo> get_colliding_symbols_info (SymbolInfo info) {
- var name = info.symbol.name;
- if (name == null && info.symbol is CreationMethod) {
- name = ".new";
- }
- var result = new ArrayList<SymbolInfo> ();
- foreach (var cinfo in current_symbols_info) {
- if (cinfo.symbol.name == name) {
- result.add (cinfo);
- }
- }
- return result;
- }
-
- SymbolInfo? get_current_first_symbol_info (string name) {
- foreach (var info in current_symbols_info) {
- if (info.symbol.name == name) {
- return info;
- }
- }
- return null;
- }
-
- Symbol? get_current_first_symbol (string name) {
- var info = get_current_first_symbol_info (name);
- if (info != null) {
- return info.symbol;
- }
- return null;
- }
-
- SymbolInfo? find_invoker (Method method) {
+ Node? find_invoker (Node node) {
/* most common use case is invoker has at least the given method prefix
and the same parameter names */
- var prefix = "%s_".printf (method.name);
- foreach (var info in current_symbols_info) {
- if (!info.symbol.name.has_prefix (prefix)) {
+ var m = (Method) node.symbol;
+ var prefix = "%s_".printf (m.name);
+ foreach (var n in node.parent.members) {
+ if (!n.symbol.name.has_prefix (prefix)) {
continue;
}
- Method? invoker = info.symbol as Method;
- if (invoker == null || (method.get_parameters ().size != invoker.get_parameters ().size)) {
+ Method? invoker = n.symbol as Method;
+ if (invoker == null || (m.get_parameters().size != invoker.get_parameters().size)) {
continue;
}
var iter = invoker.get_parameters ().iterator ();
- foreach (var param in method.get_parameters ()) {
+ foreach (var param in m.get_parameters ()) {
assert (iter.next ());
- if (param.name != iter.get ().name) {
+ if (param.name != iter.get().name) {
invoker = null;
break;
}
}
if (invoker != null) {
- return info;
+ return n;
}
}
return null;
}
- void merge (SymbolInfo info, ArrayList<SymbolInfo> colliding, HashSet<SymbolInfo> merged) {
- if (info.symbol is Struct) {
- var gtype_struct_for = info.girdata["glib:is-gtype-struct-for"];
- if (gtype_struct_for != null) {
- var iface = get_current_first_symbol (gtype_struct_for) as Interface;
- if (iface != null) {
- // set the interface struct name
- iface.set_type_cname (((Struct) info.symbol).get_cname ());
- }
- merged.add (info);
- }
- } else if (info.symbol is Property) {
- var prop = (Property) info.symbol;
- var getter_name = "get_%s".printf (prop.name);
- var setter_name = "set_%s".printf (prop.name);
- 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);
- getter_name = sym.name;
- }
- }
- if (prop.get_accessor != null) {
- var getter_method = get_current_first_symbol (getter_name) as Method;
- if (getter_method != null) {
- prop.no_accessor_method = false;
- prop.get_accessor.value_type.value_owned = getter_method.return_type.value_owned;
- }
- } else if (prop.set_accessor != null && get_current_first_symbol_info (setter_name) != null) {
- prop.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, false);
- merged.add (cinfo);
- } else if (sym is Field) {
- merged.add (cinfo);
- }
- }
- } else if (info.symbol is Method && !(info.symbol is CreationMethod)) {
- var m = (Method) info.symbol;
- foreach (var cinfo in colliding) {
- var sym = cinfo.symbol;
- if (sym != m && m.is_virtual && sym is Method) {
- bool different_invoker = false;
- foreach (var attr in m.attributes) {
- if (attr.name == "NoWrapper") {
- /* no invoker but this method has the same name,
- most probably the invoker has a different name
- and g-ir-scanner missed it */
- var invoker = find_invoker (m);
- if (invoker != null) {
- m.vfunc_name = m.name;
- m.name = invoker.symbol.name;
- m.attributes.remove (attr);
- merged.add (invoker);
- different_invoker = true;
- }
- break;
- }
- }
- if (!different_invoker) {
- merged.add (cinfo);
- }
- }
- }
- // merge custom vfunc
- if (info.metadata.has_argument (ArgumentType.VFUNC_NAME)) {
- var vfunc = get_current_first_symbol_info (info.metadata.get_string (ArgumentType.VFUNC_NAME));
- if (vfunc != null && vfunc != info) {
- merged.add (vfunc);
- }
- }
- if (m.coroutine) {
- // handle async methods
- string finish_method_base;
- if (m.name.has_suffix ("_async")) {
- finish_method_base = m.name.substring (0, m.name.length - "_async".length);
- } else {
- finish_method_base = m.name;
- }
- var finish_method_info = get_current_first_symbol_info (finish_method_base + "_finish");
-
- // check if the method is using non-standard finish method name
- if (finish_method_info == null) {
- var method_cname = m.get_finish_cname ();
- foreach (var minfo in current_symbols_info) {
- if (minfo.symbol is Method && ((Method) minfo.symbol).get_cname () == method_cname) {
- finish_method_info = minfo;
- break;
- }
- }
- }
-
- if (finish_method_info != null && finish_method_info.symbol is Method) {
- var finish_method = (Method) finish_method_info.symbol;
- Method method;
- if (finish_method is CreationMethod) {
- method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
- method.access = m.access;
- method.binding = m.binding;
- method.external = true;
- method.coroutine = true;
- method.has_construct_function = finish_method.has_construct_function;
- method.attributes = m.attributes.copy ();
- method.set_cname (m.get_cname ());
- if (finish_method_base == "new") {
- method.name = null;
- } else if (finish_method_base.has_prefix ("new_")) {
- method.name = m.name.substring ("new_".length);
- }
- foreach (var param in m.get_parameters ()) {
- method.add_parameter (param);
- }
- info.symbol = method;
- } else {
- method = m;
- }
- method.return_type = finish_method.return_type.copy ();
- method.no_array_length = finish_method.no_array_length;
- method.array_null_terminated = finish_method.array_null_terminated;
- foreach (var param in finish_method.get_parameters ()) {
- if (param.direction == ParameterDirection.OUT) {
- var async_param = param.copy ();
- if (method.scope.lookup (param.name) != null) {
- // parameter name conflict
- async_param.name += "_out";
- }
- method.add_parameter (async_param);
- }
- }
- foreach (DataType error_type in finish_method.get_error_types ()) {
- method.add_error_type (error_type.copy ());
- }
- merged.add (finish_method_info);
- }
- }
- } 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) {
- var array_length = get_current_first_symbol_info ("n_%s".printf (field.name));
- if (array_length == null) {
- array_length = get_current_first_symbol_info ("%s_length".printf (field.name));
- }
- if (array_length != null) {
- // array has length
- field.set_array_length_cname (array_length.symbol.name);
- field.no_array_length = false;
- field.array_null_terminated = false;
- merged.add (array_length);
- }
- }
- }
- }
-
- void postprocess_symbol (Symbol sym, Metadata metadata, Map<string,string> girdata) {
- // deprecation
- sym.replacement = metadata.get_string (ArgumentType.REPLACEMENT);
- sym.deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
- if (sym.deprecated_since == null) {
- sym.deprecated_since = girdata.get ("deprecated-version");
- }
- sym.deprecated = metadata.get_bool (ArgumentType.DEPRECATED) || sym.replacement != null || sym.deprecated_since != null;
-
- // cheader filename
- var cheader_filename = metadata.get_string (ArgumentType.CHEADER_FILENAME);
- if (cheader_filename != null) {
- foreach (string filename in cheader_filename.split (",")) {
- sym.add_cheader_filename (filename);
- }
- }
-
- // 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>();
- symbol_reparent_map[target_symbol] = reparent_list;
- }
- reparent_list.add (sym);
-
- // if referenceable, map unresolved references to point to the new place
- if (sym is Namespace || sym is TypeSymbol) {
- set_symbol_mapping (sym, new UnresolvedSymbol (target_symbol, sym.name));
- }
- }
-
- if (sym is Class) {
- var cl = (Class) sym;
- if (cl.default_construction_method == null) {
- // always provide constructor in generated bindings
- // to indicate that implicit Object () chainup is allowed
- var cm = new CreationMethod (null, null, cl.source_reference);
- cm.has_construct_function = false;
- cm.access = SymbolAccessibility.PROTECTED;
- cl.add_method (cm);
- }
- }
- }
-
- void merge_add_process (Symbol container) {
- var merged = new HashSet<SymbolInfo> ();
- foreach (var info in current_symbols_info) {
- merge (info, get_colliding_symbols_info (info), merged);
- }
-
- foreach (var info in current_symbols_info) {
- if (merged.contains (info) || info.metadata.get_bool (ArgumentType.HIDDEN)) {
- continue;
- }
- if (!(current_symbol is Namespace && info.symbol is Method) && !info.metadata.has_argument (ArgumentType.PARENT)) {
- add_symbol_to_container (container, info.symbol);
- }
- postprocess_symbol (info.symbol, info.metadata, info.girdata);
- }
- }
-
Metadata get_current_metadata () {
var selector = reader.name;
var child_name = reader.get_attribute ("name");
@@ -1124,8 +1124,6 @@ public class Vala.GirParser : CodeVisitor {
metadata_stack.add (metadata);
metadata = new_metadata;
- girdata_stack.add (girdata);
- girdata = reader.get_attributes ();
return true;
}
@@ -1133,8 +1131,6 @@ public class Vala.GirParser : CodeVisitor {
void pop_metadata () {
metadata = metadata_stack[metadata_stack.size - 1];
metadata_stack.remove_at (metadata_stack.size - 1);
- girdata = girdata_stack[girdata_stack.size - 1];
- girdata_stack.remove_at (girdata_stack.size - 1);
}
bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
@@ -1310,9 +1306,11 @@ public class Vala.GirParser : CodeVisitor {
return type;
}
- string? element_get_name (bool remap = false) {
- var name = reader.get_attribute ("name");
- var orig_name = name;
+ string? element_get_name (string? gir_name = null) {
+ var name = gir_name;
+ if (name == null) {
+ name = reader.get_attribute ("name");
+ }
var pattern = metadata.get_string (ArgumentType.NAME);
if (pattern != null) {
try {
@@ -1336,9 +1334,6 @@ public class Vala.GirParser : CodeVisitor {
name = name.substring (0, name.length - "Enum".length);
}
}
- if (name != orig_name && remap) {
- set_symbol_mapping (parse_symbol_from_string (orig_name), parse_symbol_from_string (name));
- }
return name;
}
@@ -1355,16 +1350,16 @@ public class Vala.GirParser : CodeVisitor {
param.carray_length_parameter_position = info.vala_idx;
param.set_array_length_cname (info.param.name);
}
- if (info.param.variable_type.to_qualified_string () != "int") {
- var unresolved_type = (UnresolvedType) info.param.variable_type;
- var resolved_struct = resolve_symbol (glib_ns.scope, unresolved_type.unresolved_symbol) as Struct;
- if (resolved_struct != null) {
+ var type_name = info.param.variable_type.to_qualified_string ();
+ if (type_name != "int") {
+ var st = context.root.scope.lookup (type_name) as Struct;
+ if (st != null) {
if (sym is Method) {
var m = (Method) sym;
- m.array_length_type = resolved_struct.get_cname ();
+ m.array_length_type = st.get_cname ();
} else {
var param = (Parameter) sym;
- param.array_length_type = resolved_struct.get_cname ();
+ param.array_length_type = st.get_cname ();
}
}
}
@@ -1379,10 +1374,7 @@ public class Vala.GirParser : CodeVisitor {
next ();
while (current_token == MarkupTokenType.START_ELEMENT) {
if (reader.name == "namespace") {
- var ns = parse_namespace ();
- if (ns != null) {
- context.root.add_namespace (ns);
- }
+ parse_namespace ();
} else if (reader.name == "include") {
parse_include ();
} else if (reader.name == "package") {
@@ -1402,8 +1394,6 @@ public class Vala.GirParser : CodeVisitor {
}
}
end_element ("repository");
-
- report_unused_metadata (metadata);
}
void parse_include () {
@@ -1451,38 +1441,97 @@ public class Vala.GirParser : CodeVisitor {
}
}
- Namespace? parse_namespace () {
+ Node? resolve_node (Node parent_scope, UnresolvedSymbol unresolved_sym, bool create_namespace = false) {
+ if (unresolved_sym.inner == null) {
+ var scope = parent_scope;
+ while (scope != null) {
+ var node = scope.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
+ if (node != null) {
+ return node;
+ }
+ scope = scope.parent;
+ }
+ } else {
+ var inner = resolve_node (parent_scope, unresolved_sym.inner, create_namespace);
+ if (inner != null) {
+ return inner.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
+ }
+ }
+ return null;
+ }
+
+ Symbol? resolve_symbol (Node parent_scope, UnresolvedSymbol unresolved_sym) {
+ var node = resolve_node (parent_scope, unresolved_sym);
+ if (node != null) {
+ return node.symbol;
+ }
+ return null;
+ }
+
+ void push_node (string name, bool merge) {
+ var parent = current;
+ if (metadata.has_argument (ArgumentType.PARENT)) {
+ var target = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT));
+ parent = resolve_node (root, target, true);
+ }
+
+ var node = parent.lookup (name);
+ if (node == null || (node.symbol != null && !merge)) {
+ node = new Node (name);
+ node.new_symbol = true;
+ }
+ node.element_type = reader.name;
+ node.girdata = reader.get_attributes ();
+ node.metadata = metadata;
+ node.source_reference = get_current_src ();
+ parent.add_member (node);
+
+ var gir_name = node.girdata["name"];
+ if (gir_name == null) {
+ gir_name = node.girdata["glib:name"];
+ }
+ if (parent != current || gir_name != name) {
+ set_symbol_mapping (new UnresolvedSymbol (null, gir_name), node.get_unresolved_symbol ());
+ }
+
+ tree_stack.add (current);
+ current = node;
+ }
+
+ void pop_node () {
+ old_current = current;
+ current = tree_stack[tree_stack.size - 1];
+ tree_stack.remove_at (tree_stack.size - 1);
+ }
+
+ void parse_namespace () {
start_element ("namespace");
- bool new_namespace = false;
string? cprefix = reader.get_attribute ("c:identifier-prefixes");
- string namespace_name = cprefix;
+ string vala_namespace = cprefix;
string gir_namespace = reader.get_attribute ("name");
string gir_version = reader.get_attribute ("version");
- if (namespace_name == null) {
- namespace_name = gir_namespace;
- }
- current_source_file.gir_namespace = gir_namespace;
- current_source_file.gir_version = gir_version;
var ns_metadata = metadata.match_child (gir_namespace);
if (ns_metadata.has_argument (ArgumentType.NAME)) {
- namespace_name = ns_metadata.get_string (ArgumentType.NAME);
+ vala_namespace = ns_metadata.get_string (ArgumentType.NAME);
}
-
- var ns = context.root.scope.lookup (namespace_name) as Namespace;
- if (ns == null) {
- ns = new Namespace (namespace_name, get_current_src ());
- new_namespace = true;
- } else {
- if (ns.external_package) {
- ns.attributes = null;
- ns.source_reference = get_current_src ();
- }
+ if (vala_namespace == null) {
+ vala_namespace = gir_namespace;
}
- if (gir_namespace != ns.name) {
- set_symbol_mapping (new UnresolvedSymbol (null, gir_namespace), ns);
+ current_source_file.gir_namespace = gir_namespace;
+ current_source_file.gir_version = gir_version;
+
+ Namespace ns;
+ push_node (vala_namespace, true);
+ if (current.new_symbol) {
+ ns = new Namespace (vala_namespace, current.source_reference);
+ current.symbol = ns;
+ } else {
+ ns = (Namespace) current.symbol;
+ ns.attributes = null;
+ ns.source_reference = current.source_reference;
}
if (cprefix != null) {
@@ -1502,16 +1551,6 @@ public class Vala.GirParser : CodeVisitor {
}
next ();
- var current_namespace_methods = namespace_methods[ns];
- if (current_namespace_methods == null) {
- current_namespace_methods = new ArrayList<Method> ();
- namespace_methods[ns] = current_namespace_methods;
- }
- var old_symbols_info = current_symbols_info;
- var old_symbol = current_symbol;
- current_symbols_info = new ArrayList<SymbolInfo> ();
- current_symbol = ns;
- gtype_callbacks = new HashMap<UnresolvedSymbol,ArrayList<Delegate>> (unresolved_symbol_hash, unresolved_symbol_equal);
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -1519,44 +1558,39 @@ public class Vala.GirParser : CodeVisitor {
}
if (reader.name == "alias") {
- var alias = parse_alias ();
- aliases.add (alias);
+ parse_alias ();
} else if (reader.name == "enumeration") {
if (reader.get_attribute ("glib:error-quark") != null) {
- add_symbol_info (parse_error_domain ());
+ parse_error_domain ();
} else {
- add_symbol_info (parse_enumeration ());
+ parse_enumeration ();
}
} else if (reader.name == "bitfield") {
- add_symbol_info (parse_bitfield ());
+ parse_bitfield ();
} else if (reader.name == "function") {
- var method = parse_method ("function");
- add_symbol_info (method);
- current_namespace_methods.add (method);
+ parse_method ("function");
} else if (reader.name == "callback") {
- add_symbol_info (parse_callback ());
+ parse_callback ();
} else if (reader.name == "record") {
if (reader.get_attribute ("glib:get-type") != null && !metadata.get_bool (ArgumentType.STRUCT)) {
- add_symbol_info (parse_boxed ("record"));
+ parse_boxed ("record");
} else {
if (!reader.get_attribute ("name").has_suffix ("Private")) {
- add_symbol_info (parse_record ());
+ parse_record ();
} else {
skip_element ();
}
}
} else if (reader.name == "class") {
- add_symbol_info (parse_class ());
+ parse_class ();
} else if (reader.name == "interface") {
- var iface = parse_interface ();
- add_symbol_info (iface);
- interfaces.add (iface);
+ parse_interface ();
} else if (reader.name == "glib:boxed") {
- add_symbol_info (parse_boxed ("glib:boxed"));
+ parse_boxed ("glib:boxed");
} else if (reader.name == "union") {
- add_symbol_info (parse_union ());
+ parse_union ();
} else if (reader.name == "constant") {
- add_symbol_info (parse_constant ());
+ parse_constant ();
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name));
@@ -1565,34 +1599,20 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
+ pop_node ();
end_element ("namespace");
-
- merge_add_process (ns);
- current_symbols_info = old_symbols_info;
- current_symbol = old_symbol;
- postprocess_gtype_callbacks (ns);
-
- if (!new_namespace) {
- ns = null;
- }
-
- return ns;
}
- Alias parse_alias () {
- // alias has no type information
+ void parse_alias () {
start_element ("alias");
- var alias = new Alias ();
- alias.source_reference = get_current_src ();
- alias.name = reader.get_attribute ("name");
- alias.cname = reader.get_attribute ("c:type");
- alias.parent_symbol = current_symbol;
- next ();
+ push_node (element_get_name (), true);
+ // not enough information, symbol will be created while processing the tree
- alias.base_type = element_get_type (parse_type (null, null, true), true);
+ next ();
+ current.base_type = element_get_type (parse_type (null, null, true), true);
+ pop_node ();
end_element ("alias");
- return alias;
}
private void calculate_common_prefix (ref string common_prefix, string cname) {
@@ -1614,19 +1634,26 @@ public class Vala.GirParser : CodeVisitor {
}
}
- Symbol parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
+ void parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
start_element (element_name);
+ push_node (element_get_name (), true);
Symbol sym;
- if (error_domain) {
- sym = new ErrorDomain (element_get_name (true), get_current_src ());
- } else {
- var en = new Enum (element_get_name (), get_current_src ());
- if (element_name == "bitfield") {
- en.is_flags = true;
+ if (current.new_symbol) {
+ if (error_domain) {
+ sym = new ErrorDomain (current.name, current.source_reference);
+ } else {
+ var en = new Enum (current.name, current.source_reference);
+ if (element_name == "bitfield") {
+ en.is_flags = true;
+ }
+ sym = en;
}
- sym = en;
+ current.symbol = sym;
+ } else {
+ sym = current.symbol;
}
+ sym.external = true;
sym.access = SymbolAccessibility.PUBLIC;
string cname = reader.get_attribute ("c:type");
@@ -1634,8 +1661,6 @@ public class Vala.GirParser : CodeVisitor {
next ();
- var old_symbol = current_symbol;
- current_symbol = sym;
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -1644,12 +1669,10 @@ public class Vala.GirParser : CodeVisitor {
if (reader.name == "member") {
if (error_domain) {
- ErrorCode ec = parse_error_member ();
- ((ErrorDomain) sym).add_code (ec);
+ var ec = parse_error_member ();
calculate_common_prefix (ref common_prefix, ec.get_cname ());
} else {
var ev = parse_enumeration_member ();
- ((Enum) sym).add_value (ev);
calculate_common_prefix (ref common_prefix, ev.get_cname ());
}
} else {
@@ -1671,48 +1694,61 @@ public class Vala.GirParser : CodeVisitor {
}
}
+ pop_node ();
end_element (element_name);
- current_symbol = old_symbol;
- return sym;
}
- ErrorDomain parse_error_domain () {
- return parse_enumeration ("enumeration", true) as ErrorDomain;
+ void parse_error_domain () {
+ parse_enumeration ("enumeration", true);
}
- Enum parse_bitfield () {
- return parse_enumeration ("bitfield") as Enum;
+ void parse_bitfield () {
+ parse_enumeration ("bitfield");
}
EnumValue parse_enumeration_member () {
start_element ("member");
- var ev = new EnumValue (reader.get_attribute ("name").up ().replace ("-", "_"), null, get_current_src ());
- ev.set_cname (reader.get_attribute ("c:identifier"));
+ push_node (element_get_name().up().replace ("-", "_"), false);
+
+ var ev = new EnumValue (current.name, metadata.get_expression (ArgumentType.DEFAULT), current.source_reference);
+ var cname = reader.get_attribute ("c:identifier");
+ if (cname != null) {
+ ev.set_cname (cname);
+ }
+ current.symbol = ev;
next ();
+
+ pop_node ();
end_element ("member");
return ev;
}
ErrorCode parse_error_member () {
start_element ("member");
+ push_node (element_get_name().up().replace ("-", "_"), false);
ErrorCode ec;
- string name = reader.get_attribute ("name").up ().replace ("-", "_");
string value = reader.get_attribute ("value");
if (value != null) {
- ec = new ErrorCode.with_value (name, new IntegerLiteral (value));
+ ec = new ErrorCode.with_value (current.name, new IntegerLiteral (value));
} else {
- ec = new ErrorCode (name);
+ ec = new ErrorCode (current.name);
+ }
+ current.symbol = ec;
+ var cname = reader.get_attribute ("c:identifier");
+ if (cname != null) {
+ ec.set_cname (cname);
}
- ec.set_cname (reader.get_attribute ("c:identifier"));
-
next ();
+
+ pop_node ();
end_element ("member");
return ec;
}
DataType parse_return_value (out string? ctype = null) {
start_element ("return-value");
+
string transfer = reader.get_attribute ("transfer-ownership");
string allow_none = reader.get_attribute ("allow-none");
next ();
@@ -1841,8 +1877,8 @@ public class Vala.GirParser : CodeVisitor {
return new ArrayType (element_type, 1, null);
}
} else if (reader.name == "callback"){
- var callback = parse_callback ();
- return new DelegateType (callback);
+ parse_callback ();
+ return new DelegateType ((Delegate) old_current.symbol);
} else {
start_element ("type");
}
@@ -1967,23 +2003,27 @@ public class Vala.GirParser : CodeVisitor {
return type;
}
- Struct parse_record () {
+ void parse_record () {
start_element ("record");
- var st = new Struct (reader.get_attribute ("name"), get_current_src ());
- st.external = true;
- st.access = SymbolAccessibility.PUBLIC;
+ push_node (element_get_name (), true);
- string cname = reader.get_attribute ("c:type");
- if (cname != null) {
- st.set_cname (cname);
+ Struct st;
+ if (current.new_symbol) {
+ st = new Struct (reader.get_attribute ("name"), current.source_reference);
+ var cname = reader.get_attribute ("c:type");
+ if (cname != null) {
+ st.set_cname (cname);
+ }
+ current.symbol = st;
+ } else {
+ st = (Struct) current.symbol;
}
- current_gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
+ st.external = true;
+ st.access = SymbolAccessibility.PUBLIC;
+ var gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
+ bool first_field = true;
next ();
- var old_symbols_info = current_symbols_info;
- var old_symbol = current_symbol;
- current_symbols_info = new ArrayList<SymbolInfo> ();
- current_symbol = st;
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -1991,23 +2031,18 @@ public class Vala.GirParser : CodeVisitor {
}
if (reader.name == "field") {
- if (reader.get_attribute ("name") != "priv") {
- add_symbol_info (parse_field ());
+ if (reader.get_attribute ("name") != "priv" && !(first_field && gtype_struct_for != null)) {
+ parse_field ();
} else {
skip_element ();
}
+ first_field = false;
} else if (reader.name == "constructor") {
parse_constructor ();
} else if (reader.name == "method") {
- add_symbol_info (parse_method ("method"));
+ parse_method ("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;
- st.add_field (f);
- }
+ parse_union ();
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name));
@@ -2016,43 +2051,37 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
- end_element ("record");
-
- merge_add_process (st);
- current_symbols_info = old_symbols_info;
- current_symbol = old_symbol;
- current_gtype_struct_for = null;
- return st;
+ pop_node ();
+ end_element ("record");
}
- Class parse_class () {
+ void parse_class () {
start_element ("class");
- var name = element_get_name ();
- string cname = reader.get_attribute ("c:type");
- string parent = reader.get_attribute ("parent");
- var cl = current_symbol.scope.lookup (name) as Class;
- if (cl == null) {
- cl = new Class (name, get_current_src ());
- cl.access = SymbolAccessibility.PUBLIC;
- cl.external = true;
-
+ push_node (element_get_name (), true);
+
+ Class cl;
+ var parent = reader.get_attribute ("parent");
+ if (current.new_symbol) {
+ cl = new Class (current.name, current.source_reference);
+ cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
+ var cname = reader.get_attribute ("c:type");
if (cname != null) {
cl.set_cname (cname);
}
- }
- if (parent != null) {
- cl.add_base_type (parse_type_from_gir_name (parent));
- }
- cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
+ if (parent != null) {
+ cl.add_base_type (parse_type_from_gir_name (parent));
+ }
+ current.symbol = cl;
+ } else {
+ cl = (Class) current.symbol;
+ }
+ cl.access = SymbolAccessibility.PUBLIC;
+ cl.external = true;
next ();
var first_field = true;
- var old_symbol = current_symbol;
- var old_symbols_info = current_symbols_info;
- current_symbols_info = new ArrayList<SymbolInfo> ();
- current_symbol = cl;
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -2065,39 +2094,33 @@ public class Vala.GirParser : CodeVisitor {
next ();
end_element ("implements");
} else if (reader.name == "constant") {
- add_symbol_info (parse_constant ());
+ parse_constant ();
} else if (reader.name == "field") {
if (first_field && parent != null) {
// first field is guaranteed to be the parent instance
skip_element ();
} else {
if (reader.get_attribute ("name") != "priv") {
- add_symbol_info (parse_field ());
+ parse_field ();
} else {
skip_element ();
}
}
first_field = false;
} else if (reader.name == "property") {
- add_symbol_info (parse_property ());
+ parse_property ();
} else if (reader.name == "constructor") {
- add_symbol_info (parse_constructor ());
+ parse_constructor ();
} else if (reader.name == "function") {
- add_symbol_info (parse_method ("function"));
+ parse_method ("function");
} else if (reader.name == "method") {
- add_symbol_info (parse_method ("method"));
+ parse_method ("method");
} else if (reader.name == "virtual-method") {
- add_symbol_info (parse_method ("virtual-method"));
+ 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;
- add_symbol_info (f);
- }
+ parse_union ();
} else if (reader.name == "glib:signal") {
- add_symbol_info (parse_signal ());
+ parse_signal ();
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
@@ -2107,31 +2130,36 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
- merge_add_process (cl);
- current_symbols_info = old_symbols_info;
- current_symbol = old_symbol;
-
+ pop_node ();
end_element ("class");
- return cl;
}
- Interface parse_interface () {
+ void parse_interface () {
start_element ("interface");
- var iface = new Interface (element_get_name (), get_current_src ());
+ push_node (element_get_name (), true);
+
+ Interface iface;
+ if (current.new_symbol) {
+ iface = new Interface (current.name, current.source_reference);
+ var cname = reader.get_attribute ("c:type");
+ if (cname != null) {
+ iface.set_cname (cname);
+ }
+ var typeid = reader.get_attribute ("glib:get-type");
+ if (typeid != null) {
+ iface.set_type_id ("%s ()".printf (typeid));
+ }
+
+ current.symbol = iface;
+ } else {
+ iface = (Interface) current.symbol;
+ }
+
iface.access = SymbolAccessibility.PUBLIC;
iface.external = true;
- string cname = reader.get_attribute ("c:type");
- if (cname != null) {
- iface.set_cname (cname);
- }
- iface.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
next ();
- var old_symbol = current_symbol;
- var old_symbols_info = current_symbols_info;
- current_symbol = iface;
- current_symbols_info = new ArrayList<SymbolInfo> ();
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -2144,17 +2172,17 @@ public class Vala.GirParser : CodeVisitor {
next ();
end_element ("prerequisite");
} else if (reader.name == "field") {
- add_symbol_info (parse_field ());
+ parse_field ();
} else if (reader.name == "property") {
- add_symbol_info (parse_property ());
+ parse_property ();
} else if (reader.name == "virtual-method") {
- add_symbol_info (parse_method ("virtual-method"));
+ parse_method ("virtual-method");
} else if (reader.name == "function") {
- add_symbol_info (parse_method ("function"));
+ parse_method ("function");
} else if (reader.name == "method") {
- add_symbol_info (parse_method ("method"));
+ parse_method ("method");
} else if (reader.name == "glib:signal") {
- add_symbol_info (parse_signal ());
+ parse_signal ();
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name));
@@ -2164,45 +2192,36 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
- merge_add_process (iface);
- current_symbol = old_symbol;
- current_symbols_info = old_symbols_info;
-
+ pop_node ();
end_element ("interface");
- return iface;
}
- Field parse_field () {
+ void parse_field () {
start_element ("field");
- string name = reader.get_attribute ("name");
+ push_node (element_get_name (), false);
+
string allow_none = reader.get_attribute ("allow-none");
next ();
var type = parse_type ();
type = element_get_type (type, true);
- if (type is DelegateType && current_gtype_struct_for != null) {
- // virtual
- var gtype_struct_for = parse_symbol_from_string (current_gtype_struct_for);
- ArrayList<Delegate> callbacks = gtype_callbacks.get (gtype_struct_for);
- if (callbacks == null) {
- callbacks = new ArrayList<Delegate> ();
- gtype_callbacks.set (gtype_struct_for, callbacks);
- }
- callbacks.add (((DelegateType) type).delegate_symbol);
- }
- var field = new Field (name, type, null, get_current_src ());
+
+ var field = new Field (current.name, type, null, current.source_reference);
field.access = SymbolAccessibility.PUBLIC;
field.no_array_length = true;
field.array_null_terminated = true;
if (allow_none == "1") {
type.nullable = true;
}
+ current.symbol = field;
+
+ pop_node ();
end_element ("field");
- return field;
}
Property parse_property () {
start_element ("property");
- string name = reader.get_attribute ("name").replace ("-", "_");
+ push_node (element_get_name().replace ("-", "_"), false);
+
string readable = reader.get_attribute ("readable");
string writable = reader.get_attribute ("writable");
string construct_ = reader.get_attribute ("construct");
@@ -2211,7 +2230,7 @@ public class Vala.GirParser : CodeVisitor {
bool no_array_length;
bool array_null_terminated;
var type = parse_type (null, null, false, out no_array_length, out array_null_terminated);
- var prop = new Property (name, type, null, null, get_current_src ());
+ var prop = new Property (current.name, type, null, null, current.source_reference);
prop.access = SymbolAccessibility.PUBLIC;
prop.external = true;
prop.no_accessor_method = true;
@@ -2224,32 +2243,19 @@ public class Vala.GirParser : CodeVisitor {
if (writable == "1" || construct_only == "1") {
prop.set_accessor = new PropertyAccessor (false, (construct_only != "1") && (writable == "1"), (construct_only == "1") || (construct_ == "1"), prop.property_type.copy (), null, null);
}
+ current.symbol = prop;
+
+ pop_node ();
end_element ("property");
return prop;
}
- Delegate parse_callback () {
- return this.parse_function ("callback") as Delegate;
- }
-
- CreationMethod parse_constructor () {
- return parse_function ("constructor") as CreationMethod;
+ void parse_callback () {
+ parse_function ("callback");
}
- class CallableInfo {
- public Symbol symbol;
- public List<ParameterInfo> parameters;
- public Metadata metadata;
-
- public ArrayList<int> array_length_parameters = new ArrayList<int> ();
- public ArrayList<int> closure_parameters = new ArrayList<int> ();
- public ArrayList<int> destroy_parameters = new ArrayList<int> ();
-
- public CallableInfo (Symbol symbol, List<ParameterInfo> parameters, Metadata metadata) {
- this.symbol = symbol;
- this.parameters = parameters;
- this.metadata = metadata;
- }
+ void parse_constructor () {
+ parse_function ("constructor");
}
class ParameterInfo {
@@ -2270,10 +2276,11 @@ public class Vala.GirParser : CodeVisitor {
public bool keep;
}
- Symbol parse_function (string element_name) {
+ void parse_function (string element_name) {
start_element (element_name);
- // replace is needed for signal names
- string name = element_get_name ().replace ("-", "_");
+ push_node (element_get_name (reader.get_attribute ("invoker")).replace ("-", "_"), false);
+
+ string name = current.name;
string cname = reader.get_attribute ("c:identifier");
string throws_string = reader.get_attribute ("throws");
string invoker = reader.get_attribute ("invoker");
@@ -2291,28 +2298,28 @@ public class Vala.GirParser : CodeVisitor {
Symbol s;
if (element_name == "callback") {
- s = new Delegate (name, return_type, get_current_src ());
+ s = new Delegate (name, return_type, current.source_reference);
} else if (element_name == "constructor") {
if (name == "new") {
name = null;
} else if (name.has_prefix ("new_")) {
name = name.substring ("new_".length);
}
- var m = new CreationMethod (null, name, get_current_src ());
+ var m = new CreationMethod (null, name, current.source_reference);
m.has_construct_function = false;
string parent_ctype = null;
- if (current_symbol is Class) {
- parent_ctype = ((Class) current_symbol).get_cname ();
+ if (current.parent.symbol is Class) {
+ parent_ctype = ((Class) current.parent.symbol).get_cname ();
}
if (return_ctype != null && (parent_ctype == null || return_ctype != parent_ctype + "*")) {
m.custom_return_type_cname = return_ctype;
}
s = m;
} else if (element_name == "glib:signal") {
- s = new Signal (name, return_type, get_current_src ());
+ s = new Signal (name, return_type, current.source_reference);
} else {
- s = new Method (name, return_type, get_current_src ());
+ s = new Method (name, return_type, current.source_reference);
}
s.access = SymbolAccessibility.PUBLIC;
@@ -2333,10 +2340,6 @@ public class Vala.GirParser : CodeVisitor {
s.attributes.append (new Attribute ("NoWrapper", s.source_reference));
}
}
-
- if (invoker != null) {
- s.name = invoker;
- }
} else if (element_name == "function") {
((Method) s).binding = MemberBinding.STATIC;
}
@@ -2360,9 +2363,12 @@ public class Vala.GirParser : CodeVisitor {
s.add_error_type (new ErrorType (null, null));
}
+ current.symbol = s;
+
var parameters = new ArrayList<ParameterInfo> ();
- var callable = new CallableInfo (s, parameters, metadata);
- callable_info_list.add (callable);
+ current.array_length_parameters = new ArrayList<int> ();
+ current.closure_parameters = new ArrayList<int> ();
+ current.destroy_parameters = new ArrayList<int> ();
if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
start_element ("parameters");
next ();
@@ -2379,13 +2385,13 @@ public class Vala.GirParser : CodeVisitor {
default_param_name = "arg%d".printf (parameters.size);
var param = parse_parameter (out array_length_idx, out closure_idx, out destroy_idx, out scope, default_param_name);
if (array_length_idx != -1) {
- callable.array_length_parameters.add (array_length_idx);
+ current.array_length_parameters.add (array_length_idx);
}
if (closure_idx != -1) {
- callable.closure_parameters.add (closure_idx);
+ current.closure_parameters.add (closure_idx);
}
if (destroy_idx != -1) {
- callable.destroy_parameters.add (destroy_idx);
+ current.destroy_parameters.add (destroy_idx);
}
var info = new ParameterInfo (param, array_length_idx, closure_idx, destroy_idx);
@@ -2404,44 +2410,51 @@ public class Vala.GirParser : CodeVisitor {
}
end_element ("parameters");
}
+ current.parameters = parameters;
+ pop_node ();
end_element (element_name);
- return s;
}
- Method parse_method (string element_name) {
- return this.parse_function (element_name) as Method;
+ void parse_method (string element_name) {
+ parse_function (element_name);
}
- Signal parse_signal () {
- return this.parse_function ("glib:signal") as Signal;
+ void parse_signal () {
+ parse_function ("glib:signal");
}
- Class parse_boxed (string element_name) {
+ void parse_boxed (string element_name) {
start_element (element_name);
string name = reader.get_attribute ("name");
if (name == null) {
name = reader.get_attribute ("glib:name");
}
- var cl = new Class (name, get_current_src ());
- cl.access = SymbolAccessibility.PUBLIC;
- cl.external = true;
- cl.is_compact = true;
+ push_node (element_get_name (name), true);
- string cname = reader.get_attribute ("c:type");
- if (cname != null) {
- cl.set_cname (cname);
- }
+ Class cl;
+ if (current.new_symbol) {
+ cl = new Class (current.name, current.source_reference);
+ cl.is_compact = true;
+ var cname = reader.get_attribute ("c:type");
+ if (cname != null) {
+ cl.set_cname (reader.get_attribute ("c:type"));
+ }
+ var typeid = reader.get_attribute ("glib:get-type");
+ if (typeid != null) {
+ cl.set_type_id ("%s ()".printf (typeid));
+ }
+ cl.set_free_function ("g_boxed_free");
+ cl.set_dup_function ("g_boxed_copy");
- cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
- cl.set_free_function ("g_boxed_free");
- cl.set_dup_function ("g_boxed_copy");
+ current.symbol = cl;
+ } else {
+ cl = (Class) current.symbol;
+ }
+ cl.access = SymbolAccessibility.PUBLIC;
+ cl.external = true;
next ();
- var old_symbols_info = current_symbols_info;
- var old_symbol = current_symbol;
- current_symbols_info = new ArrayList<SymbolInfo> ();
- current_symbol = cl;
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -2449,11 +2462,11 @@ public class Vala.GirParser : CodeVisitor {
}
if (reader.name == "field") {
- add_symbol_info (parse_field ());
+ parse_field ();
} else if (reader.name == "constructor") {
- add_symbol_info (parse_constructor ());
+ parse_constructor ();
} else if (reader.name == "method") {
- add_symbol_info (parse_method ("method"));
+ parse_method ("method");
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
@@ -2462,24 +2475,26 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
- end_element (element_name);
- merge_add_process (cl);
- current_symbols_info = old_symbols_info;
- current_symbol = old_symbol;
-
- return cl;
+ pop_node ();
+ end_element (element_name);
}
- Struct parse_union () {
+ void parse_union () {
start_element ("union");
- var st = new Struct (reader.get_attribute ("name"), get_current_src ());
+ push_node (element_get_name (), true);
+
+ Struct st;
+ if (current.new_symbol) {
+ st = new Struct (reader.get_attribute ("name"), current.source_reference);
+ current.symbol = st;
+ } else {
+ st = (Struct) current.symbol;
+ }
st.access = SymbolAccessibility.PUBLIC;
st.external = true;
- next ();
- var old_symbol = current_symbol;
- current_symbol = st;
+ next ();
while (current_token == MarkupTokenType.START_ELEMENT) {
if (!push_metadata ()) {
skip_element ();
@@ -2487,19 +2502,13 @@ public class Vala.GirParser : CodeVisitor {
}
if (reader.name == "field") {
- st.add_field (parse_field ());
+ parse_field ();
} else if (reader.name == "constructor") {
parse_constructor ();
} else if (reader.name == "method") {
- st.add_method (parse_method ("method"));
+ parse_method ("method");
} else if (reader.name == "record") {
- Struct s = parse_record ();
- var fs = s.get_fields ();
- foreach (var f in fs) {
- f.set_cname (s.get_cname () + "." + f.get_cname ());
- f.name = s.name + "_" + f.name;
- st.add_field (f);
- }
+ parse_record ();
} else {
// error
Report.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader.name));
@@ -2509,22 +2518,23 @@ public class Vala.GirParser : CodeVisitor {
pop_metadata ();
}
+ pop_node ();
end_element ("union");
- current_symbol = old_symbol;
-
- return st;
}
- Constant parse_constant () {
+ void parse_constant () {
start_element ("constant");
- string name = element_get_name ();
+ push_node (element_get_name (), false);
+
next ();
var type = parse_type ();
- var c = new Constant (name, type, null, get_current_src ());
+ var c = new Constant (current.name, type, null, current.source_reference);
+ current.symbol = c;
c.access = SymbolAccessibility.PUBLIC;
c.external = true;
+
+ pop_node ();
end_element ("constant");
- return c;
}
/* Reporting */
@@ -2558,11 +2568,6 @@ public class Vala.GirParser : CodeVisitor {
/* Post-parsing */
void resolve_gir_symbols () {
- // we are remapping unresolved symbols, so create them from concrete symbols
- foreach (var map_from in concrete_symbols_map.get_keys ()) {
- unresolved_symbols_map[get_unresolved_symbol(map_from)] = concrete_symbols_map[map_from];
- }
-
// gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
foreach (var map_from in unresolved_gir_symbols) {
while (map_from != null) {
@@ -2592,184 +2597,231 @@ public class Vala.GirParser : CodeVisitor {
}
}
- Symbol? resolve_symbol (Scope parent_scope, UnresolvedSymbol unresolved_symbol) {
- // simple symbol resolver, enough for gir
- if (unresolved_symbol.inner == null) {
- var scope = parent_scope;
- while (scope != null) {
- var sym = scope.lookup (unresolved_symbol.name);
- if (sym != null) {
- return sym;
- }
- scope = scope.parent_scope;
- }
- } else {
- var inner = resolve_symbol (parent_scope, unresolved_symbol.inner);
- if (inner != null) {
- return inner.scope.lookup (unresolved_symbol.name);
+ void create_new_namespaces () {
+ foreach (var node in Node.new_namespaces) {
+ if (node.symbol == null) {
+ node.symbol = new Namespace (node.name, node.source_reference);
}
}
- return null;
}
- void postprocess_interfaces () {
- foreach (var iface in interfaces) {
- /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
- ensure we have at least one instantiable prerequisite */
- bool has_instantiable_prereq = false;
- foreach (DataType prereq in iface.get_prerequisites ()) {
- Symbol sym = null;
- if (prereq is UnresolvedType) {
- var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
- sym = resolve_symbol (iface.parent_symbol.scope, unresolved_symbol);
- } else {
- sym = prereq.data_type;
- }
- if (sym is Class) {
- has_instantiable_prereq = true;
- break;
- }
+ void process_interface (Node iface_node) {
+ /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
+ ensure we have at least one instantiable prerequisite */
+ Interface iface = (Interface) iface_node.symbol;
+ bool has_instantiable_prereq = false;
+ foreach (DataType prereq in iface.get_prerequisites ()) {
+ Symbol sym = null;
+ if (prereq is UnresolvedType) {
+ var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
+ sym = resolve_symbol (iface_node.parent, unresolved_symbol);
+ } else {
+ sym = prereq.data_type;
}
-
- if (!has_instantiable_prereq) {
- iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object")));
+ if (sym is Class) {
+ has_instantiable_prereq = true;
+ break;
}
}
- }
- 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);
- }
+ if (!has_instantiable_prereq) {
+ iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object")));
}
}
- void postprocess_gtype_callbacks (Namespace ns) {
- foreach (UnresolvedSymbol gtype_struct_for in gtype_callbacks.get_keys ()) {
- // parent symbol is the record, therefore use parent of parent symbol
- var gtype = resolve_symbol (ns.scope, gtype_struct_for) as ObjectTypeSymbol;
- if (gtype == null) {
- Report.error (null, "unknown symbol `%s' while postprocessing callbacks".printf (gtype_struct_for.name));
- continue;
+ void process_alias (Node alias) {
+ /* this is unfortunate because <alias> tag has no type information, thus we have
+ to guess it from the base type */
+ DataType base_type = null;
+ Symbol type_sym = null;
+ bool simple_type = false;
+ if (alias.base_type is UnresolvedType) {
+ base_type = alias.base_type;
+ type_sym = resolve_symbol (alias.parent, ((UnresolvedType) base_type).unresolved_symbol);
+ } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
+ // gpointer, if it's a struct make it a simpletype
+ simple_type = true;
+ } else {
+ base_type = alias.base_type;
+ type_sym = base_type.data_type;
+ }
+
+ if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
+ simple_type = true;
+ }
+
+ if (base_type == null || type_sym == null || type_sym is Struct) {
+ var st = new Struct (alias.name, alias.source_reference);
+ st.access = SymbolAccessibility.PUBLIC;
+ if (base_type != null) {
+ // threat target="none" as a new struct
+ st.base_type = base_type;
}
- ArrayList<Delegate> callbacks = gtype_callbacks.get (gtype_struct_for);
- foreach (Delegate d in callbacks) {
- var symbol = gtype.scope.lookup (d.name);
- if (symbol == null) {
- continue;
- } else if (symbol is Method) {
- var meth = (Method) symbol;
- if (gtype is Class) {
- meth.is_virtual = true;
- } else if (gtype is Interface) {
- meth.is_abstract = true;
+ st.external = true;
+ st.set_cname (alias.girdata["c:type"]);
+ if (simple_type) {
+ st.set_simple_type (true);
+ }
+ alias.symbol = st;
+ } else if (type_sym is Class) {
+ var cl = new Class (alias.name, alias.source_reference);
+ cl.access = SymbolAccessibility.PUBLIC;
+ if (base_type != null) {
+ cl.add_base_type (base_type);
+ }
+ cl.external = true;
+ cl.set_cname (alias.girdata["c:type"]);
+ alias.symbol = cl;
+ }
+ }
+
+ void process_callable (Node node) {
+ var s = node.symbol;
+ List<ParameterInfo> parameters = node.parameters;
+ Metadata metadata = node.metadata;
+
+ DataType return_type = null;
+ if (s is Method) {
+ return_type = ((Method) s).return_type;
+ } else if (s is Delegate) {
+ return_type = ((Delegate) s).return_type;
+ } else if (s is Signal) {
+ return_type = ((Signal) s).return_type;
+ }
+
+ var array_length_idx = -1;
+ if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
+ array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
+ parameters[array_length_idx].keep = false;
+ node.array_length_parameters.add (array_length_idx);
+ } else if (return_type is VoidType && parameters.size > 0) {
+ int n_out_parameters = 0;
+ foreach (var info in parameters) {
+ if (info.param.direction == ParameterDirection.OUT) {
+ n_out_parameters++;
+ }
+ }
+
+ if (n_out_parameters == 1) {
+ ParameterInfo last_param = parameters[parameters.size-1];
+ if (last_param.param.direction == ParameterDirection.OUT) {
+ // use last out real-non-null-struct parameter as return type
+ if (last_param.param.variable_type is UnresolvedType) {
+ var st = resolve_symbol (node.parent, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
+ if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
+ last_param.keep = false;
+ return_type = last_param.param.variable_type.copy ();
+ }
}
- } else if (symbol is Signal) {
- var sig = (Signal) symbol;
- sig.is_virtual = true;
- assume_parameter_names (sig, d, true);
- } else if (symbol is Property) {
- var prop = (Property) symbol;
- prop.is_virtual = true;
- } else {
- Report.error (get_current_src (), "unknown member type `%s' in `%s'".printf (d.name, gtype.name));
}
}
}
- }
- void postprocess_aliases () {
- /* this is unfortunate because <alias> tag has no type information, thus we have
- to guess it from the base type */
- foreach (var alias in aliases) {
- DataType base_type = null;
- Symbol type_sym = null;
- bool simple_type = false;
- if (alias.base_type is UnresolvedType) {
- base_type = alias.base_type;
- type_sym = resolve_symbol (alias.parent_symbol.scope, ((UnresolvedType) base_type).unresolved_symbol);
- } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
- // gpointer, if it's a struct make it a simpletype
- simple_type = true;
+ int i = 0, j=1;
+
+ int last = -1;
+ foreach (ParameterInfo info in parameters) {
+ if (s is Delegate && info.closure_idx == i) {
+ var d = (Delegate) s;
+ d.has_target = true;
+ d.cinstance_parameter_position = (float) j - 0.1;
+ info.keep = false;
+ } else if (info.keep
+ && !node.array_length_parameters.contains (i)
+ && !node.closure_parameters.contains (i)
+ && !node.destroy_parameters.contains (i)) {
+ info.vala_idx = (float) j;
+ info.keep = true;
+
+ /* interpolate for vala_idx between this and last*/
+ float last_idx = 0.0F;
+ if (last != -1) {
+ last_idx = parameters[last].vala_idx;
+ }
+ for (int k=last+1; k < i; k++) {
+ parameters[k].vala_idx = last_idx + (((j - last_idx) / (i-last)) * (k-last));
+ }
+ last = i;
+ j++;
} else {
- base_type = alias.base_type;
- type_sym = base_type.data_type;
+ info.keep = false;
+ // make sure that vala_idx is always set
+ // the above if branch does not set vala_idx for
+ // hidden parameters at the end of the parameter list
+ info.vala_idx = (j - 1) + (i - last) * 0.1F;
}
+ i++;
+ }
- if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
- simple_type = true;
- }
+ foreach (ParameterInfo info in parameters) {
+ if (info.keep) {
- if (base_type == null || type_sym == null || type_sym is Struct) {
- var st = new Struct (alias.name, alias.source_reference);
- st.access = SymbolAccessibility.PUBLIC;
- if (base_type != null) {
- // threat target="none" as a new struct
- st.base_type = base_type;
- }
- st.external = true;
- if (alias.cname != null) {
- st.set_cname (alias.cname);
+ /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
+ so do it first*/
+ if (s is Method) {
+ ((Method) s).add_parameter (info.param);
+ } else if (s is Delegate) {
+ ((Delegate) s).add_parameter (info.param);
+ } else if (s is Signal) {
+ ((Signal) s).add_parameter (info.param);
}
- if (simple_type) {
- st.set_simple_type (true);
+
+ if (info.array_length_idx != -1) {
+ if ((info.array_length_idx) >= parameters.size) {
+ Report.error (get_current_src (), "invalid array_length index");
+ continue;
+ }
+ set_array_ccode (info.param, parameters[info.array_length_idx]);
}
- add_symbol_to_container (alias.parent_symbol, st);
- } else if (type_sym is Class) {
- var cl = new Class (alias.name, alias.source_reference);
- cl.access = SymbolAccessibility.PUBLIC;
- if (base_type != null) {
- cl.add_base_type (base_type);
+
+ if (info.closure_idx != -1) {
+ if ((info.closure_idx) >= parameters.size) {
+ Report.error (get_current_src (), "invalid closure index");
+ continue;
+ }
+ info.param.cdelegate_target_parameter_position = parameters[info.closure_idx].vala_idx;
}
- cl.external = true;
- if (alias.cname != null) {
- cl.set_cname (alias.cname);
+ if (info.destroy_idx != -1) {
+ if (info.destroy_idx >= parameters.size) {
+ Report.error (get_current_src (), "invalid destroy index");
+ continue;
+ }
+ info.param.cdestroy_notify_parameter_position = parameters[info.destroy_idx].vala_idx;
}
- add_symbol_to_container (alias.parent_symbol, cl);
}
}
+ if (array_length_idx != -1) {
+ if (array_length_idx >= parameters.size) {
+ Report.error (get_current_src (), "invalid array_length index");
+ } else {
+ set_array_ccode (s, parameters[array_length_idx]);
+ }
+ } else if (return_type is ArrayType) {
+ if (s is Method) {
+ var m = (Method) s;
+ m.no_array_length = true;
+ m.array_null_terminated = true;
+ } else if (s is Delegate) {
+ var d = (Delegate) s;
+ d.no_array_length = true;
+ d.array_null_terminated = true;
+ }
+ }
+
+ if (s is Method) {
+ ((Method) s).return_type = return_type;
+ } else if (s is Delegate) {
+ ((Delegate) s).return_type = return_type;
+ } else if (s is Signal) {
+ ((Signal) s).return_type = return_type;
+ }
}
- void find_static_method_parent (string cname, Symbol current, ref Symbol best, ref double match, double match_char) {
+ void find_static_method_parent (string cname, Symbol current, ref Symbol best, ref int match, int match_char) {
var old_best = best;
- if (current.scope.get_symbol_table () != null) {
+ if (current is Namespace && current.scope.get_symbol_table () != null) {
foreach (var child in current.scope.get_symbol_table().get_values ()) {
- if (child is Struct || child is ObjectTypeSymbol || child is Namespace) {
+ if (is_container (child) && cname.has_prefix (child.get_lower_case_cprefix ())) {
find_static_method_parent (cname, child, ref best, ref match, match_char);
}
}
@@ -2779,207 +2831,185 @@ public class Vala.GirParser : CodeVisitor {
return;
}
- var current_cprefix = current.get_lower_case_cprefix ();
- if (cname.has_prefix (current_cprefix)) {
- var current_match = match_char * current_cprefix.length;
- if (current_match > match) {
- match = current_match;
- best = current;
- }
+ var current_match = match_char * current.get_lower_case_cprefix().length;
+ if (current_match > match) {
+ match = current_match;
+ best = current;
}
}
- void postprocess_callables () {
- foreach (var callable in callable_info_list) {
- var s = callable.symbol;
- List<ParameterInfo> parameters = callable.parameters;
- Metadata metadata = callable.metadata;
-
- DataType return_type = null;
- if (s is Method) {
- return_type = ((Method) s).return_type;
- } else if (s is Delegate) {
- return_type = ((Delegate) s).return_type;
- } else if (s is Signal) {
- return_type = ((Signal) s).return_type;
- }
-
- var array_length_idx = -1;
- if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
- array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
- parameters[array_length_idx].keep = false;
- callable.array_length_parameters.add (array_length_idx);
- } else if (return_type is VoidType && parameters.size > 0) {
- int n_out_parameters = 0;
- foreach (var info in parameters) {
- if (info.param.direction == ParameterDirection.OUT) {
- n_out_parameters++;
- }
- }
-
- if (n_out_parameters == 1) {
- ParameterInfo last_param = parameters[parameters.size-1];
- if (last_param.param.direction == ParameterDirection.OUT) {
- // use last out real-non-null-struct parameter as return type
- if (last_param.param.variable_type is UnresolvedType) {
- var st = resolve_symbol (s.parent_symbol.scope, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
- if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
- last_param.keep = false;
- return_type = last_param.param.variable_type.copy ();
- }
- }
- }
+ void process_namespace_method (Namespace ns, Method method) {
+ /* transform static methods into instance methods if possible.
+ In most of cases this is a .gir fault we are going to fix */
+ var ns_cprefix = ns.get_lower_case_cprefix ();
+ var cname = method.get_cname ();
+
+ Parameter first_param = null;
+ if (method.get_parameters ().size > 0) {
+ first_param = method.get_parameters()[0];
+ }
+ if (first_param != null && first_param.variable_type is UnresolvedType) {
+ // check if it's a missed instance method (often happens for structs)
+ var sym = ((UnresolvedType) first_param.variable_type).unresolved_symbol;
+ Symbol parent = ns;
+ if (sym.inner != null) {
+ parent = context.root.scope.lookup (sym.inner.name);
+ }
+ // ensure we don't get out of the GIR namespace
+ if (parent == ns) {
+ parent = parent.scope.lookup (sym.name);
+ }
+ if (parent != null && is_container (parent) && cname.has_prefix (parent.get_lower_case_cprefix ())) {
+ // instance method
+ var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
+ if (parent.scope.lookup (new_name) == null) {
+ method.name = new_name;
+ method.get_parameters().remove_at (0);
+ method.binding = MemberBinding.INSTANCE;
+ add_symbol_to_container (parent, method);
+ } else {
+ ns.add_method (method);
}
+ return;
}
+ }
- int i = 0, j=1;
-
- int last = -1;
- foreach (ParameterInfo info in parameters) {
- if (s is Delegate && info.closure_idx == i) {
- var d = (Delegate) s;
- d.has_target = true;
- d.cinstance_parameter_position = (float) j - 0.1;
- info.keep = false;
- } else if (info.keep
- && !callable.array_length_parameters.contains (i)
- && !callable.closure_parameters.contains (i)
- && !callable.destroy_parameters.contains (i)) {
- info.vala_idx = (float) j;
- info.keep = true;
-
- /* interpolate for vala_idx between this and last*/
- float last_idx = 0.0F;
- if (last != -1) {
- last_idx = parameters[last].vala_idx;
- }
- for (int k=last+1; k < i; k++) {
- parameters[k].vala_idx = last_idx + (((j - last_idx) / (i-last)) * (k-last));
- }
- last = i;
- j++;
- } else {
- info.keep = false;
- // make sure that vala_idx is always set
- // the above if branch does not set vala_idx for
- // hidden parameters at the end of the parameter list
- info.vala_idx = (j - 1) + (i - last) * 0.1F;
- }
- i++;
- }
-
- foreach (ParameterInfo info in parameters) {
- if (info.keep) {
-
- /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
- so do it first*/
- if (s is Method) {
- ((Method) s).add_parameter (info.param);
- } else if (s is Delegate) {
- ((Delegate) s).add_parameter (info.param);
- } else if (s is Signal) {
- ((Signal) s).add_parameter (info.param);
- }
-
- if (info.array_length_idx != -1) {
- if ((info.array_length_idx) >= parameters.size) {
- Report.error (get_current_src (), "invalid array_length index");
- continue;
- }
- set_array_ccode (info.param, parameters[info.array_length_idx]);
- }
+ int match = 0;
+ Symbol parent = ns;
+ find_static_method_parent (cname, ns, ref parent, ref match, cname.length);
+ var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
+ if (parent.scope.lookup (new_name) == null) {
+ method.name = new_name;
+ add_symbol_to_container (parent, method);
+ } else {
+ ns.add_method (method);
+ }
+ }
- if (info.closure_idx != -1) {
- if ((info.closure_idx) >= parameters.size) {
- Report.error (get_current_src (), "invalid closure index");
- continue;
- }
- info.param.cdelegate_target_parameter_position = parameters[info.closure_idx].vala_idx;
- }
- if (info.destroy_idx != -1) {
- if (info.destroy_idx >= parameters.size) {
- Report.error (get_current_src (), "invalid destroy index");
- continue;
- }
- info.param.cdestroy_notify_parameter_position = parameters[info.destroy_idx].vala_idx;
- }
- }
+ void process_virtual_method_field (Node node, Delegate d, UnresolvedSymbol gtype_struct_for) {
+ var gtype_node = resolve_node (node.parent, gtype_struct_for);
+ if (gtype_node == null || !(gtype_node.symbol is ObjectTypeSymbol)) {
+ Report.error (gtype_struct_for.source_reference, "Unknown symbol `%s' for virtual method field `%s'".printf (gtype_struct_for.to_string (), node.to_string ()));
+ }
+ var gtype = (ObjectTypeSymbol) gtype_node.symbol;
+ var nodes = gtype_node.lookup_all (d.name);
+ if (nodes == null) {
+ return;
+ }
+ foreach (var n in nodes) {
+ if (node != n) {
+ n.process (this);
}
- if (array_length_idx != -1) {
- if (array_length_idx >= parameters.size) {
- Report.error (get_current_src (), "invalid array_length index");
- } else {
- set_array_ccode (s, parameters[array_length_idx]);
- }
- } else if (return_type is ArrayType) {
- if (s is Method) {
- var m = (Method) s;
- m.no_array_length = true;
- m.array_null_terminated = true;
- } else if (s is Delegate) {
- var d = (Delegate) s;
- d.no_array_length = true;
- d.array_null_terminated = true;
- }
+ }
+ foreach (var n in nodes) {
+ if (n.merged) {
+ continue;
}
-
- if (s is Method) {
- ((Method) s).return_type = return_type;
- } else if (s is Delegate) {
- ((Delegate) s).return_type = return_type;
- } else if (s is Signal) {
- ((Signal) s).return_type = return_type;
+ var sym = n.symbol;
+ if (sym is Signal) {
+ var sig = (Signal) sym;
+ sig.is_virtual = true;
+ assume_parameter_names (sig, d, true);
+ } else if (sym is Property) {
+ var prop = (Property) sym;
+ prop.is_virtual = true;
+ } else if (sym is Method) {
+ var meth = (Method) sym;
+ if (gtype is Class) {
+ meth.is_virtual = true;
+ } else if (gtype is Interface) {
+ meth.is_abstract = true;
+ }
+ } else {
+ Report.error (get_current_src (), "Unknown type for member `%s'".printf (node.to_string ()));
}
}
}
- void postprocess_namespace_methods () {
- /* transform static methods into instance methods if possible.
- In most of cases this is a .gir fault we are going to fix */
- foreach (var ns in namespace_methods.get_keys ()) {
- var ns_cprefix = ns.get_lower_case_cprefix ();
- var methods = namespace_methods[ns];
- foreach (var method in methods) {
- if (method.parent_symbol != null) {
- // fixed earlier by metadata
- continue;
+ void process_async_method (Node node) {
+ var m = (Method) node.symbol;
+ string finish_method_base;
+ if (m.name.has_suffix ("_async")) {
+ finish_method_base = m.name.substring (0, m.name.length - "_async".length);
+ } else {
+ finish_method_base = m.name;
+ }
+ var finish_method_node = node.parent.lookup (finish_method_base + "_finish");
+
+ // check if the method is using non-standard finish method name
+ if (finish_method_node == null) {
+ var method_cname = m.get_finish_cname ();
+ foreach (var n in node.parent.members) {
+ if (n.symbol is Method && ((Method) n.symbol).get_cname () == method_cname) {
+ finish_method_node = n;
+ break;
}
+ }
+ }
- var cname = method.get_cname ();
-
- Parameter first_param = null;
- if (method.get_parameters ().size > 0) {
- first_param = method.get_parameters()[0];
- }
- if (first_param != null && first_param.variable_type is UnresolvedType) {
- // check if it's a missed instance method (often happens for structs)
- var parent = resolve_symbol (ns.scope, ((UnresolvedType) first_param.variable_type).unresolved_symbol);
- if (parent != null && (parent is Struct || parent is ObjectTypeSymbol || parent is Namespace)
- && cname.has_prefix (parent.get_lower_case_cprefix ())) {
- // instance method
- var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
- if (parent.scope.lookup (new_name) == null) {
- method.name = new_name;
- method.get_parameters().remove_at (0);
- method.binding = MemberBinding.INSTANCE;
- add_symbol_to_container (parent, method);
- } else {
- ns.add_method (method);
+ if (finish_method_node != null && finish_method_node.symbol is Method) {
+ finish_method_node.process (this);
+ var finish_method = (Method) finish_method_node.symbol;
+ Method method;
+ if (finish_method is CreationMethod) {
+ method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
+ method.access = m.access;
+ method.binding = m.binding;
+ method.external = true;
+ method.coroutine = true;
+ method.has_construct_function = finish_method.has_construct_function;
+ method.attributes = m.attributes.copy ();
+ method.set_cname (m.get_cname ());
+ if (finish_method_base == "new") {
+ method.name = null;
+ } else if (finish_method_base.has_prefix ("new_")) {
+ method.name = m.name.substring ("new_".length);
+ }
+ foreach (var param in m.get_parameters ()) {
+ method.add_parameter (param);
+ }
+ node.symbol = method;
+ } else {
+ method = m;
+ method.return_type = finish_method.return_type.copy ();
+ method.no_array_length = finish_method.no_array_length;
+ method.array_null_terminated = finish_method.array_null_terminated;
+ // put cancellable as last parameter
+ Parameter cancellable = null;
+ foreach (var param in method.get_parameters ()) {
+ if (param.name == "cancellable" && param.variable_type.to_qualified_string () == "GLib.Cancellable?" && param.direction == ParameterDirection.IN) {
+ cancellable = param;
+ cancellable.initializer = new NullLiteral (param.source_reference);
+ } else if (cancellable != null) {
+ param.cparameter_position--;
+ param.carray_length_parameter_position--;
+ param.cdelegate_target_parameter_position--;
+ param.cdestroy_notify_parameter_position--;
+ }
+ }
+ if (cancellable != null) {
+ method.get_parameters().remove (cancellable);
+ method.scope.remove (cancellable.name);
+ }
+ foreach (var param in finish_method.get_parameters ()) {
+ if (param.direction == ParameterDirection.OUT) {
+ var async_param = param.copy ();
+ if (method.scope.lookup (param.name) != null) {
+ // parameter name conflict
+ async_param.name += "_out";
}
- continue;
+ method.add_parameter (async_param);
}
}
+ if (cancellable != null) {
+ method.add_parameter (cancellable);
+ }
- double match = 0;
- Symbol parent = ns;
- find_static_method_parent (cname, ns, ref parent, ref match, 1.0/cname.length);
- var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
- if (parent.scope.lookup (new_name) == null) {
- method.name = new_name;
- add_symbol_to_container (parent, method);
- } else {
- ns.add_method (method);
+ foreach (DataType error_type in finish_method.get_error_types ()) {
+ method.add_error_type (error_type.copy ());
}
+ finish_method_node.processed = true;
+ finish_method_node.merged = true;
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]