[vala/switch-to-gir] girparser: Use Regex to parse vala types.



commit 4168fd84193dbde5fb4153745f9d733fc95f378a
Author: Luca Bruno <lethalman88 gmail com>
Date:   Thu Aug 26 16:42:15 2010 +0200

    girparser: Use Regex to parse vala types.
    
    Based on Evan Nemerson patch.

 vala/valagirparser.vala |  379 +++++++++++++++++++++++++++-------------------
 1 files changed, 222 insertions(+), 157 deletions(-)
---
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index a502152..b883c8b 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -36,7 +36,9 @@ public class Vala.GirParser : CodeVisitor {
 		HIDDEN,
 		TYPE,
 		CHEADER_FILENAME,
-		NAME;
+		NAME,
+		OWNED,
+		UNOWNED;
 
 		public static ArgumentType? from_string (string name) {
 			var enum_class = (EnumClass) typeof(ArgumentType).class_ref ();
@@ -52,14 +54,16 @@ public class Vala.GirParser : CodeVisitor {
 
 	class Argument {
 		public Expression expression;
-		public SourceLocation source_location;
+		public SourceLocation begin;
+		public SourceLocation end;
 		public SourceReference source_reference;
 
 		public bool used = false;
 
-		public Argument (Expression expression, SourceLocation source_location, SourceReference? source_reference = null) {
+		public Argument (Expression expression, SourceLocation begin, SourceLocation end, SourceReference? source_reference = null) {
 			this.expression = expression;
-			this.source_location = source_location;
+			this.begin = begin;
+			this.end = end;
 			this.source_reference = source_reference;
 		}
 	}
@@ -75,18 +79,16 @@ public class Vala.GirParser : CodeVisitor {
 		public string pattern;
 		public PatternSpec pattern_spec;
 		public MetadataType type;
-		public MetadataParser parser;
 		public SourceReference source_reference;
 
 		public bool used = false;
 		public Vala.Map<ArgumentType,Argument> args = new HashMap<ArgumentType,Argument> ();
 		public ArrayList<Metadata> children = new ArrayList<Metadata> ();
 
-		public Metadata (string pattern, MetadataType type = MetadataType.GENERIC, MetadataParser? parser = null, SourceReference? source_reference = null) {
+		public Metadata (string pattern, MetadataType type = MetadataType.GENERIC, SourceReference? source_reference = null) {
 			this.pattern = pattern;
 			this.pattern_spec = new PatternSpec (pattern);
 			this.type = type;
-			this.parser = parser;
 			this.source_reference = source_reference;
 		}
 
@@ -168,18 +170,6 @@ public class Vala.GirParser : CodeVisitor {
 
 			return false;
 		}
-
-		public DataType? get_data_type (ArgumentType arg, bool owned_by_default) {
-			var type_arg = args.get (arg);
-			if (type_arg != null && type_arg.expression is StringLiteral) {
-				type_arg.used = true;
-				var location = SourceLocation (type_arg.source_location.pos + 1, type_arg.source_location.line, type_arg.source_location.column + 1);
-				parser.seek (location);
-				var type = parser.parse_type (owned_by_default);
-				return type;
-			}
-			return null;
-		}
 	}
 
 	class MetadataParser {
@@ -222,70 +212,6 @@ public class Vala.GirParser : CodeVisitor {
 			return tree;
 		}
 
-		public DataType? parse_type (bool owned_by_default) {
-			// sync with valaparser.vala
-			var begin = this.begin;
-	
-			if (accept (TokenType.VOID)) {
-				DataType type = new VoidType (get_src (begin));
-				while (accept (TokenType.STAR)) {
-					type = new PointerType (type);
-				}
-				return type;
-			}
-
-			bool value_owned = owned_by_default;
-
-			if (owned_by_default && accept (TokenType.UNOWNED)) {
-				value_owned = false;
-			} else if (!owned_by_default) {
-				value_owned = accept (TokenType.OWNED);
-			}
-
-			var sym = parse_symbol_name ();
-			if (sym == null) {
-				return null;
-			}
-			List<DataType> type_arg_list = parse_type_argument_list ();
-
-			DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
-			if (type_arg_list != null) {
-				foreach (DataType type_arg in type_arg_list) {
-					type.add_type_argument (type_arg);
-				}
-			}
-
-			while (accept (TokenType.STAR)) {
-				type = new PointerType (type, get_src (begin));
-			}
-
-			if (!(type is PointerType)) {
-				type.nullable = accept (TokenType.INTERR);
-			}
-
-			while (accept (TokenType.OPEN_BRACKET)) {
-				if (current != TokenType.CLOSE_BRACKET) {
-					Report.error (get_current_src (), "expected `]'");
-					return null;
-				}
-
-				type.value_owned = true;
-			
-				var array_type = new ArrayType (type, 0, get_src (begin));
-				array_type.nullable = accept (TokenType.INTERR);
-
-				type = array_type;
-			}
-
-			type.value_owned = value_owned;
-			return type;
-		}
-
-		public void seek (SourceLocation location) {
-			scanner.seek (location);
-			next ();
-		}
-
 		TokenType next () {
 			old_end = end;
 			current = scanner.read_token (out begin, out end);
@@ -328,26 +254,33 @@ public class Vala.GirParser : CodeVisitor {
 			}
 		}
 
-		string? parse_glob (out SourceReference source_reference) {
-			if (current != TokenType.IDENTIFIER && current != TokenType.STAR) {
-				return null;
-			}
-
+		string? parse_identifier (out SourceReference source_reference, bool is_glob) {
 			var begin = this.begin;
 			var builder = new StringBuilder ();
 			do {
-				if (current == TokenType.IDENTIFIER) {
-					builder.append (get_string ());
-					source_reference = get_src (begin);
-					next ();
-				} else if (current == TokenType.STAR) {
+				if (is_glob && current == TokenType.STAR) {
 					builder.append_c ('*');
-					source_reference = get_src (begin);
-					next ();
 				} else {
-					break;
+					if (current == TokenType.IDENTIFIER) {
+						builder.append (get_string ());
+					} else if (current == TokenType.UNOWNED) {
+						builder.append ("unowned");
+					} else {
+						break;
+					}
 				}
+				source_reference = get_src (begin);
+				next ();
 			} while (!has_space ());
+
+			if (builder.str == "") {
+				if (is_glob) {
+					Report.error (get_src (begin), "expected pattern");
+				} else {
+					Report.error (get_src (begin), "expected identifier");
+				}
+				return null;
+			}
 			return builder.str;
 		}
 
@@ -375,13 +308,13 @@ public class Vala.GirParser : CodeVisitor {
 			}
 
 			SourceReference src;
-			var pattern = parse_glob (out src);
+			var pattern = parse_identifier (out src, true);
 			if (pattern == null) {
 				return null;
 			}
 			metadata = parent_metadata.get_child (pattern, type);
 			if (metadata == null) {
-				metadata = new Metadata (pattern, type, this, src);
+				metadata = new Metadata (pattern, type, src);
 				parent_metadata.add_child (metadata);
 			}
 
@@ -392,13 +325,13 @@ public class Vala.GirParser : CodeVisitor {
 					return null;
 				}
 
-				pattern = parse_glob (out src);
+				pattern = parse_identifier (out src, true);
 				if (pattern == null) {
 					return null;
 				}
 				var child = metadata.get_child (pattern, type);
 				if (child == null) {
-					child = new Metadata (pattern, type, this, src);
+					child = new Metadata (pattern, type, src);
 					metadata.add_child (child);
 				}
 				metadata = child;
@@ -410,7 +343,7 @@ public class Vala.GirParser : CodeVisitor {
 			return metadata;
 		}
 
-		Expression? parse_literal () {
+		Expression? parse_literal (out SourceLocation end) {
 			var src = get_current_src ();
 			Expression expr = null;
 
@@ -434,67 +367,37 @@ public class Vala.GirParser : CodeVisitor {
 				Report.error (src, "expected literal");
 				break;
 			}
+			end = this.end;
 			next ();
 			return expr;
 		}
 
-		UnresolvedSymbol? parse_symbol_name () {
-			// sync with valaparser.vala
-			var begin = this.begin;
-			UnresolvedSymbol sym = null;
-			do {
-				if (current != TokenType.IDENTIFIER) {
-					Report.error (get_current_src (), "expected identifier");
-					return null;
-				}
-				string name = get_string ();
-				sym = new UnresolvedSymbol (sym, name, get_src (begin));
-				next ();
-			} while (accept (TokenType.DOT));
-			return sym;
-		}
-
-		List<DataType>? parse_type_argument_list () {
-			if (accept (TokenType.OP_LT)) {
-				var list = new ArrayList<DataType> ();
-				do {
-					var type = parse_type (true);
-					list.add (type);
-				} while (accept (TokenType.COMMA));
-				if (current != TokenType.OP_GT) {
-					Report.error (get_current_src (), "expected `>'");
-					return null;
-				}
-				return list;
-			}
-			return null;
-		}
-
 		bool parse_args (Metadata metadata) {
 			while (current != TokenType.EOF && !has_newline ()) {
-				if (current != TokenType.IDENTIFIER) {
-					Report.error (get_current_src (), "expected argument name");
+				SourceReference src;
+				var id = parse_identifier (out src, false);
+				if (id == null) {
 					return false;
 				}
-				var id = ArgumentType.from_string (get_string ());
-				var arg_src = get_current_src ();
-				if (id == null) {
-					Report.error (arg_src, "unknown argument");
+				var arg_type = ArgumentType.from_string (id);
+				if (arg_type == null) {
+					Report.error (src, "unknown argument");
 					return false;
 				}
 
-				if (next () != TokenType.ASSIGN) {
+				if (current != TokenType.ASSIGN) {
 					Report.error (get_current_src (), "expected `='");
 					return false;
 				}
 				next ();
 
-				var expr_begin = this.begin;
-				Expression expr = parse_literal ();
+				SourceLocation begin = this.begin;
+				SourceLocation end;
+				Expression expr = parse_literal (out end);
 				if (expr == null) {
 					return false;
 				}
-				metadata.add_argument (id, new Argument (expr, expr_begin, arg_src));
+				metadata.add_argument (arg_type, new Argument (expr, begin, end, src));
 			}
 
 			return true;
@@ -522,6 +425,8 @@ public class Vala.GirParser : CodeVisitor {
 		public Namespace parent_namespace;
 	}
 
+	static GLib.Regex type_from_string_regex;
+
 	MarkupReader reader;
 
 	CodeContext context;
@@ -676,15 +581,173 @@ public class Vala.GirParser : CodeVisitor {
 		metadata_stack.remove_at (metadata_stack.size - 1);
 	}
 
-	DataType? element_get_data_type (ArgumentType arg_type, string attribute_name, bool owned_by_default) {
-		var type = metadata.get_data_type (arg_type, owned_by_default);
-		if (type == null) {
-			type = parse_type_from_gir_name (reader.get_attribute (attribute_name));
+	UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
+		UnresolvedSymbol? sym = null;
+		foreach (unowned string s in symbol_string.split (".")) {
+			sym = new UnresolvedSymbol (sym, s, source_reference);
+		}
+		if (sym == null) {
+			Report.error (source_reference, "a symbol must be specified");
+		}
+		return sym;
+	}
+
+	bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
+		int type_arguments_length = (int) type_arguments.length;
+		GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
+
+		int depth = 0;
+		for (var c = 0 ; c < type_arguments_length ; c++) {
+			if (type_arguments[c] == '<' || type_arguments[c] == '[') {
+				depth++;
+				current.append_unichar (type_arguments[c]);
+			} else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
+				depth--;
+				current.append_unichar (type_arguments[c]);
+			} else if (type_arguments[c] == ',') {
+				if (depth == 0) {
+					var dt = parse_type_from_string (current.str, true, source_reference);
+					if (dt == null) {
+						return false;
+					}
+					parent_type.add_type_argument (dt);
+					current.truncate ();
+				} else {
+					current.append_unichar (type_arguments[c]);
+				}
+			} else {
+				current.append_unichar (type_arguments[c]);
+			}
+		}
+ 
+		var dt = parse_type_from_string (current.str, true, source_reference);
+		if (dt == null) {
+			return false;
+		}
+		parent_type.add_type_argument (dt);
+
+		return true;
+	}
+
+	DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
+		if (type_from_string_regex == null) {
+			try {
+				type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[(,*)?\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
+			} catch (GLib.RegexError e) {
+				GLib.error ("Unable to compile regex: %s", e.message);
+			}
+		}
+
+		GLib.MatchInfo match;
+		if (!type_from_string_regex.match (type_string, 0, out match)) {
+			Report.error (source_reference, "unable to parse type");
+			return null;
+		}
+
+		DataType? type = null;
+
+		var ownership_data = match.fetch (1);
+		var type_name = match.fetch (2);
+		var type_arguments_data = match.fetch (3);
+		var pointers_data = match.fetch (4);
+		var array_data = match.fetch (5);
+		var nullable_data = match.fetch (6);
+
+		var nullable = nullable_data != null && nullable_data.length > 0;
+
+		if (ownership_data == null && type_name == "void") {
+			if (array_data == null && !nullable) {
+				type = new VoidType (source_reference);
+				if (pointers_data != null) {
+					for (int i=0; i < pointers_data.length; i++) {
+						type = new PointerType (type);
+					}
+				}
+				return type;
+			} else {
+				Report.error (source_reference, "invalid void type");
+				return null;
+			}
+		}
+
+		bool value_owned = owned_by_default;
+
+		if (ownership_data == "owned") {
+			if (owned_by_default) {
+				Report.error (source_reference, "unexpected `owned' keyword");
+			} else {
+				value_owned = true;
+			}
+		} else if (ownership_data == "unowned") {
+			if (owned_by_default) {
+				value_owned = true;
+			} else {
+				Report.error (source_reference, "unexpected `unowned' keyword");
+				return null;
+			}
+		}
+
+		var sym = parse_symbol_from_string (type_name, source_reference);
+		if (sym == null) {
+			return null;
+		}
+		type = new UnresolvedType.from_symbol (sym, source_reference);
+
+		if (type_arguments_data != null && type_arguments_data.length > 0) {
+			if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
+				return null;
+			}
+		}
+ 
+		if (pointers_data != null) {
+			for (int i=0; i < pointers_data.length; i++) {
+				type = new PointerType (type);
+			}
+		}
+
+		if (array_data != null) {
+			type = new ArrayType (type, (int) array_data.length + 1, null);
+		}
+
+		type.nullable = nullable;
+		return type;
+	}
+
+	DataType? element_get_type (DataType type, bool owned_by_default, out bool changed = null, ArgumentType arg_type = ArgumentType.TYPE) {
+		if (&changed != null) {
+			changed = false;
+		}
+
+		if (metadata.has_argument (arg_type)) {
+			var src = metadata.args.get (arg_type).expression.source_reference;
+			var new_type = parse_type_from_string (metadata.get_string (arg_type), owned_by_default, src);
+			if (&changed != null) {
+				changed = true;
+			}
+			return new_type;
+		}
+
+		if (!(type is VoidType)) {
+			if (owned_by_default) {
+				if (metadata.has_argument (ArgumentType.UNOWNED)) {
+					type.value_owned = !metadata.get_bool (ArgumentType.UNOWNED);
+					if (&changed != null) {
+						changed = true;
+					}
+				}
+			} else {
+				if (metadata.has_argument (ArgumentType.OWNED)) {
+					type.value_owned = metadata.get_bool (ArgumentType.OWNED);
+					if (&changed != null) {
+						changed = true;
+					}
+				}
+			}
 		}
 		return type;
 	}
 
-	string? element_get_string (ArgumentType arg_type, string attribute_name) {
+	string? element_get_string (string attribute_name, ArgumentType arg_type) {
 		var str = metadata.get_string (arg_type);
 		if (str == null) {
 			str = reader.get_attribute (attribute_name);
@@ -898,7 +961,7 @@ public class Vala.GirParser : CodeVisitor {
 		var alias = new Alias ();
 		alias.source_reference = get_current_src ();
 		alias.name = reader.get_attribute ("name");
-		alias.base_type = element_get_data_type (ArgumentType.TYPE, "target", true);
+		alias.base_type = element_get_type (parse_type_from_gir_name (reader.get_attribute ("target")), true);
 		alias.parent_namespace = current_namespace;
 		next ();
 		end_element ("alias");
@@ -1115,10 +1178,9 @@ public class Vala.GirParser : CodeVisitor {
 		} else {
 			string ctype;
 			var type = parse_type (out ctype, out array_length_idx, transfer == "full");
-			if (metadata.has_argument (ArgumentType.TYPE)) {
-				// keep the parsed ctype
-				type = metadata.get_data_type (ArgumentType.TYPE, false);
-			} else {
+			bool changed;
+			type = element_get_type (type, false, out changed);
+			if (!changed) {
 				// discard ctype, duplicated information
 				ctype = null;
 			}
@@ -1495,7 +1557,7 @@ public class Vala.GirParser : CodeVisitor {
 
 	Interface parse_interface () {
 		start_element ("interface");
-		var iface = new Interface (element_get_string (ArgumentType.NAME, "name"), get_current_src ());
+		var iface = new Interface (element_get_string ("name", ArgumentType.NAME), get_current_src ());
 		iface.access = SymbolAccessibility.PUBLIC;
 		iface.external = true;
 
@@ -1682,7 +1744,7 @@ public class Vala.GirParser : CodeVisitor {
 
 	Method parse_constructor (string? parent_ctype = null) {
 		start_element ("constructor");
-		string name = element_get_string (ArgumentType.NAME, "name");
+		string name = element_get_string ("name", ArgumentType.NAME);
 		string throws_string = reader.get_attribute ("throws");
 		next ();
 
@@ -1736,17 +1798,19 @@ public class Vala.GirParser : CodeVisitor {
 
 	Symbol parse_function (string element_name) {
 		start_element (element_name);
-		string name = element_get_string (ArgumentType.NAME, "name");
+		string name = element_get_string ("name", ArgumentType.NAME);
 		string cname = reader.get_attribute ("c:identifier");
 		string throws_string = reader.get_attribute ("throws");
 		string invoker = reader.get_attribute ("invoker");
 		next ();
 		DataType return_type;
+
 		if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
 			return_type = parse_return_value ();
 		} else {
 			return_type = new VoidType ();
 		}
+		return_type = element_get_type (return_type, true);
 
 		Symbol s;
 
@@ -1787,6 +1851,7 @@ public class Vala.GirParser : CodeVisitor {
 
 			while (current_token == MarkupTokenType.START_ELEMENT) {
 				if (!push_metadata ()) {
+					skip_element ();
 					continue;
 				}
 
@@ -2061,7 +2126,7 @@ public class Vala.GirParser : CodeVisitor {
 			var arg = metadata.args[arg_type];
 			if (!arg.used) {
 				// if metadata is used and argument is not, then it's a unexpected argument
-				Report.error (arg.source_reference, "unexpected argument in this context");
+				Report.warning (arg.source_reference, "argument not used in this context");
 			}
 		}
 



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