[vala/switch-to-gir] girparser: Add a MetadataParser to parse .metadata files



commit 1b0ca66abe0250561a805c7fdf0d1f4de5441130
Author: Luca Bruno <lethalman88 gmail com>
Date:   Tue Aug 24 17:05:20 2010 +0200

    girparser: Add a MetadataParser to parse .metadata files

 vala/valagirparser.vala |  266 ++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 229 insertions(+), 37 deletions(-)
---
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 40c7895..2350970 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -26,6 +26,226 @@ using GLib;
  * Code visitor parsing all Vala source files.
  */
 public class Vala.GirParser : CodeVisitor {
+	enum MetadataType {
+		GENERIC,
+		PROPERTY,
+		SIGNAL
+	}
+
+	class Metadata : Attribute {
+		public Metadata? parent;
+		public MetadataType type;
+		private ArrayList<Metadata> children = new ArrayList<Metadata> ();
+		public bool used = false;
+
+		public Metadata (string name, MetadataType type = MetadataType.GENERIC, SourceReference? source_reference = null) {
+			base (name, source_reference);
+			this.type = type;
+		}
+
+		public void add_child (Metadata metadata) {
+			if (get_child (metadata.name, metadata.type) != null) {
+				Report.error (metadata.source_reference, "duplicate metadata pattern `%s'".printf (metadata.to_string ()));
+			}
+
+			metadata.parent = this;
+			children.add (metadata);
+		}
+
+		public Metadata? get_child (string name, MetadataType type = MetadataType.GENERIC) {
+			foreach (var metadata in children) {
+				if (metadata.name == name && metadata.type == type) {
+					return metadata;
+				}
+			}
+			return null;
+		}
+
+		public override string to_string () {
+			if (parent.name == "") {
+				return name;
+			} else {
+				return "%s.%s".printf (parent.to_string (), name);
+			}
+		}
+	}
+
+	class MetadataParser {
+		/**
+		 * Grammar:
+		 * metadata ::= [ rule [ '\n' relativerule ]* ]
+		 * rule ::= pattern ' ' [ args ]
+		 * relativerule ::= [ access ] rule
+		 * pattern ::= identifier [ access identifier ]*
+		 * access ::= '.' | ':' | '::'
+		 */
+		private Metadata tree = new Metadata ("");
+		private Scanner scanner;
+		private SourceLocation begin;
+		private SourceLocation end;
+		private TokenType current;
+		private Metadata parent_metadata;
+
+		public MetadataParser () {
+			tree.used = true;
+		}
+
+		SourceReference get_current_src () {
+			return new SourceReference (scanner.source_file, begin.line, begin.column, end.line, end.column);
+		}
+
+		public Metadata? parse_metadata (SourceFile metadata_file) {
+			scanner = new Scanner (metadata_file);
+			next ();
+			while (current != TokenType.EOF) {
+				if (!parse_rule ()) {
+					return null;
+				}
+			}
+			return tree;
+		}
+
+		TokenType next () {
+			current = scanner.read_token (out begin, out end);
+			return current;
+		}
+
+		string get_string () {
+			return ((string) begin.pos).ndup ((end.pos - begin.pos));
+		}
+
+		MetadataType? parse_metadata_access () {
+			switch (current) {
+			case TokenType.DOT:
+				next ();
+				return MetadataType.GENERIC;
+			case TokenType.COLON:
+				if (next () == TokenType.COLON) {
+					next ();
+					return MetadataType.SIGNAL;
+				}
+				return MetadataType.PROPERTY;
+			default:
+				return null;
+			}
+		}
+
+		Metadata? parse_pattern () {
+			Metadata metadata;
+			MetadataType? type = MetadataType.GENERIC;
+			if (current == TokenType.IDENTIFIER) {
+				parent_metadata = tree;
+			} else {
+				// relative pattern
+				type = parse_metadata_access ();
+ 			}
+
+			if (type == null) {
+				Report.error (get_current_src (), "expected identifier, `.', `:' or `::'");
+				return null;
+			}
+
+			metadata = new Metadata (get_string (), type, get_current_src ());
+			if (parent_metadata == null) {
+				Report.error (get_current_src (), "cannot determinate parent namespace");
+				return null;
+			}
+			parent_metadata.add_child (metadata);
+
+			while (true) {
+				var old_end = end;
+				next ();
+				if (old_end.pos != begin.pos) {
+					// spaces in the middle
+					break;
+				}
+
+				type = parse_metadata_access ();
+				if (type == null) {
+					Report.error (get_current_src (), "expected `.', `:' or `::'");
+					return null;
+				}
+
+				if (current != TokenType.IDENTIFIER) {
+					Report.error (get_current_src (), "expected identifier");
+					return null;
+				}
+				var child = new Metadata (get_string (), type, get_current_src ());
+				metadata.add_child (child);
+				metadata = child;
+			}
+			parent_metadata = metadata;
+
+			return metadata;
+		}
+
+		Expression? parse_literal () {
+			var src = get_current_src ();
+			var type = current;
+			next ();
+			switch (type) {
+			case TokenType.TRUE:
+				return new BooleanLiteral (true, src);
+			case TokenType.FALSE:
+				return new BooleanLiteral (false, src);
+			case TokenType.INTEGER_LITERAL:
+				return new IntegerLiteral (get_string (), src);
+			case TokenType.REAL_LITERAL:
+				return new RealLiteral (get_string (), src);
+			case TokenType.STRING_LITERAL:
+				return new StringLiteral (get_string (), src);
+			default:
+				Report.error (src, "expected literal");
+				return null;
+			}
+		}
+
+		bool parse_args (Metadata metadata) {
+			var old_end = end;
+			if (current != TokenType.IDENTIFIER) {
+				Report.error (get_current_src (), "expected argument name");
+				return false;
+			}
+
+			do {
+				if (begin.line != old_end.line) {
+					// new line, new rule
+					break;
+				}
+
+				var id = get_string ();
+
+				if (next () != TokenType.ASSIGN) {
+					Report.error (get_current_src (), "expected `='");
+					return false;
+				}
+				next ();
+
+				Expression expr = parse_literal ();
+				if (expr == null) {
+					return false;
+				}
+				metadata.add_argument (id, expr);
+			} while (current == TokenType.IDENTIFIER);
+
+			return true;
+		}
+
+		bool parse_rule () {
+			var old_end = end;
+			var metadata = parse_pattern ();
+			if (metadata == null) {
+				return false;
+			}
+
+			if (old_end.line != end.line) {
+				// new line, new rule
+				return true;
+			}
+			return parse_args (metadata);
+		}
+	}
+
 	class Alias {
 		public SourceReference source_reference;
 		public string name;
@@ -46,7 +266,7 @@ public class Vala.GirParser : CodeVisitor {
 
 	string[] cheader_filenames;
 
-	HashMap<string,string> attributes_map = new HashMap<string,string> (str_hash, str_equal);
+	Metadata metadata;
 
 	HashMap<string,ArrayList<Method>> gtype_callbacks = new HashMap<string,ArrayList<Method>> (str_hash, str_equal);
 
@@ -87,7 +307,15 @@ public class Vala.GirParser : CodeVisitor {
 		}
 
 		if (source_file.filename.has_suffix (".gir")) {
+			string metadata_filename = "%s.metadata".printf (source_file.filename.ndup (source_file.filename.length - ".gir".length));
+			if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
+				var metadata_parser = new MetadataParser ();
+				metadata = metadata_parser.parse_metadata (new SourceFile (context, metadata_filename, true));
+			}
+
 			parse_file (source_file);
+
+			metadata = null;
 		}
 	}
 
@@ -1413,42 +1641,6 @@ public class Vala.GirParser : CodeVisitor {
 		return c;
 	}
 
-	public void parse_metadata (string metadata_filename) {
-		if (FileUtils.test (metadata_filename, FileTest.EXISTS)) {
-			try {
-				string metadata;
-				FileUtils.get_contents (metadata_filename, out metadata, null);
-				
-				foreach (string line in metadata.split ("\n")) {
-					if (line.has_prefix ("#")) {
-						// ignore comment lines
-						continue;
-					}
-
-					string[] tokens = line.split (" ", 2);
-
-					if (null == tokens[0]) {
-						continue;
-					}
-
-					foreach (string attribute in tokens[1].split (" ")) {
-						string[] pair = attribute.split ("=", 2);
-						if (pair[0] == null || pair[1] == null) {
-							continue;
-						}
-
-						string key = "%s/@%s".printf (tokens[0], pair[0]);
-						attributes_map.set (key, pair[1].substring (1, pair[1].length - 2));
-					}
-				}
-			} catch (FileError e) {
-				Report.error (null, "Unable to read metadata file: %s".printf (e.message));
-			}
-		} else {
-			Report.error (null, "Metadata file `%s' not found".printf (metadata_filename));
-		}
-	}
-
 	void resolve_gir_namespaces () {
 		foreach (var type in unresolved_namespaced_types) {
 			var name = type.unresolved_symbol.inner.name;



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