[vala/switch-to-gir] girparser: Generalize symbols merging



commit 757f028f600e77f2f413a3e30990e2d6d5c002b0
Author: Luca Bruno <lethalman88 gmail com>
Date:   Fri Aug 27 16:46:17 2010 +0200

    girparser: Generalize symbols merging

 vala/valagirparser.vala |  215 +++++++++++++++++++++++++----------------------
 1 files changed, 116 insertions(+), 99 deletions(-)
---
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 99bf95e..de2e54c 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -37,7 +37,7 @@ using GLib;
  * - 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 parse+replace rather than a bunch of if-then-else
+ * - Prefer replace/merge after parse rather than a bunch of if-then-else and hardcoding
  * - Prefer postprocessing over hardcoding the parser
  */
 public class Vala.GirParser : CodeVisitor {
@@ -455,6 +455,11 @@ public class Vala.GirParser : CodeVisitor {
 		public UnresolvedSymbol gtype_struct_for;
 	}
 
+	class SymbolInfo {
+		public Symbol symbol;
+		public Metadata metadata;
+	}
+
 	static GLib.Regex type_from_string_regex;
 
 	MarkupReader reader;
@@ -474,6 +479,8 @@ public class Vala.GirParser : CodeVisitor {
 	ArrayList<Metadata> metadata_stack;
 	Metadata metadata;
 
+	HashMap<string,ArrayList<SymbolInfo>> current_symbols_info;
+
 	HashMap<UnresolvedSymbol,Symbol> symbols_map = new HashMap<UnresolvedSymbol,Symbol> (unresolved_symbol_hash, unresolved_symbol_equal);
 	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);
@@ -849,6 +856,91 @@ 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<SymbolInfo> ();
+			current_symbols_info[name] = colliding;
+		}
+		colliding.add (info);
+		return info;
+	}
+
+	bool merge (Symbol container, SymbolInfo info, ArrayList<SymbolInfo> colliding) {
+		bool merged = false;
+
+		if (info.symbol is Signal) {
+			foreach (var cinfo in colliding) {
+				var sym = cinfo.symbol;
+				if (sym is Property) {
+					// properties take precedence
+					merged = true;
+				}
+			}
+		} else if (info.symbol is Method) {
+			var method = (Method) info.symbol;
+			if (method.is_virtual) {
+				// virtual-method
+				foreach (var cinfo in colliding) {
+					var sym = cinfo.symbol;
+					if (sym is Signal) {
+						((Signal) sym).is_virtual = true;
+						merged = true;
+					} else if (sym is Property || sym is Field) {
+						// assume method is getter for property/field ignore method
+						merged = true;
+					}
+				}
+			} else {
+				// method
+				foreach (var cinfo in colliding) {
+					var sym = cinfo.symbol;
+					if (sym is Signal) {
+						((Signal) sym).has_emitter = true;
+						merged = true;
+					} else if (sym is Property || sym is Field) {
+						// assume method is getter for property/field ignore method
+						merged = true;
+					} else if (sym is Method && ((Method) sym).is_virtual) {
+						// assume method is wrapper for virtual method
+						merged = true;
+					}
+				}
+			}
+		} else if (info.symbol is Field) {
+			// fields have lowest priority
+			if (colliding.size > 1) {
+				merged = true;
+			}
+		}
+
+		return merged;
+	}
+
+	void merge_and_add (Symbol container) {
+		var add_list = new ArrayList<Symbol> ();
+		foreach (var name in current_symbols_info.get_keys ()) {
+			var colliding = current_symbols_info[name];
+			foreach (var info in colliding) {
+				if (!merge (container, info, colliding)) {
+					add_list.add (info.symbol);
+				}
+			}
+		}
+
+		foreach (var sym in add_list) {
+			add_symbol_to_container (container, sym);
+		}
+	}
+
 	void parse_repository () {
 		start_element ("repository");
 		next ();
@@ -1471,45 +1563,44 @@ public class Vala.GirParser : CodeVisitor {
 		}
 
 		next ();
-		var signals = new ArrayList<Signal> ();
-		var methods = new ArrayList<Method> ();
-		var vmethods = new ArrayList<Method> ();
-		var fields = new ArrayList<Field> ();
+		var old_symbols_info = current_symbols_info;
+		current_symbols_info = new HashMap<string,ArrayList<SymbolInfo>> (str_hash, str_equal);
 		while (current_token == MarkupTokenType.START_ELEMENT) {
 			if (!push_metadata ()) {
 				skip_element ();
 				continue;
 			}
 
+			Symbol sym = null;
 			if (reader.name == "implements") {
 				start_element ("implements");
 				cl.add_base_type (parse_type_from_gir_name (reader.get_attribute ("name")));
 				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));
@@ -1519,57 +1610,8 @@ public class Vala.GirParser : CodeVisitor {
 			pop_metadata ();
 		}
 
-		// 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));
-			}
-		}
-
-		// 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_and_add (cl);
+		current_symbols_info = old_symbols_info;
 
 		handle_async_methods (cl);
 
@@ -1589,8 +1631,8 @@ public class Vala.GirParser : CodeVisitor {
 		}
 
 		next ();
-		var methods = new ArrayList<Method> ();
-		var vmethods = new ArrayList<Method> ();
+		var old_symbols_info = current_symbols_info;
+		current_symbols_info = new HashMap<string,ArrayList<SymbolInfo>> (str_hash, str_equal);
 		while (current_token == MarkupTokenType.START_ELEMENT) {
 			if (!push_metadata ()) {
 				skip_element ();
@@ -1605,15 +1647,15 @@ 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));
@@ -1623,33 +1665,8 @@ public class Vala.GirParser : CodeVisitor {
 			pop_metadata ();
 		}
 
-		// 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_and_add (iface);
+		current_symbols_info = old_symbols_info;
 
 		handle_async_methods (iface);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]