[vala/switch-to-gir] girparser: Add a MetadataParser to parse .metadata files
- From: Luca Bruno <lucabru src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/switch-to-gir] girparser: Add a MetadataParser to parse .metadata files
- Date: Tue, 24 Aug 2010 15:11:46 +0000 (UTC)
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]