summaryrefslogtreecommitdiff
path: root/vapigen
diff options
context:
space:
mode:
authorEvan Nemerson <evan@coeus-group.com>2010-11-10 01:33:02 -0800
committerEvan Nemerson <evan@coeus-group.com>2010-11-10 01:57:14 -0800
commit01ff99bc39f9c6bf3fef4e2a79508477599a6077 (patch)
tree82392af515c4e8bad345ff44986d5f7c6164be39 /vapigen
parent8d5cb8955010903a49d22dcba8c8e7d2e86bbb98 (diff)
downloadvala-01ff99bc39f9c6bf3fef4e2a79508477599a6077.tar.gz
vapigen: Improve type_name and type_arguments parsing
Diffstat (limited to 'vapigen')
-rw-r--r--vapigen/valagidlparser.vala224
1 files changed, 140 insertions, 84 deletions
diff --git a/vapigen/valagidlparser.vala b/vapigen/valagidlparser.vala
index d0c025d7d..c7519cd10 100644
--- a/vapigen/valagidlparser.vala
+++ b/vapigen/valagidlparser.vala
@@ -42,6 +42,8 @@ public class Vala.GIdlParser : CodeVisitor {
private Map<string,TypeSymbol> cname_type_map;
+ static GLib.Regex type_from_string_regex;
+
/**
* Parse all source files in the specified code context and build a
* code tree.
@@ -480,10 +482,7 @@ public class Vala.GIdlParser : CodeVisitor {
} else if (nv[0] == "deprecated_since") {
cb.deprecated_since = eval (nv[1]);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- return_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (return_type, eval (nv[1]));
} else if (nv[0] == "instance_pos") {
cb.cinstance_parameter_position = eval (nv[1]).to_double ();
} else if (nv[0] == "type_parameters") {
@@ -567,23 +566,13 @@ public class Vala.GIdlParser : CodeVisitor {
param_type.nullable = true;
}
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- param_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (param_type, eval (nv[1]));
} else if (nv[0] == "no_array_length") {
if (eval (nv[1]) == "1") {
p.no_array_length = true;
}
} else if (nv[0] == "type_name") {
- var sym = new UnresolvedSymbol (null, eval (nv[1]));
- if (param_type is UnresolvedType) {
- ((UnresolvedType) param_type).unresolved_symbol = sym;
- } else {
- // Overwrite old param_type, so "type_name" must be before any
- // other param type modifying metadata
- p.variable_type = param_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
- }
+ p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
}
}
}
@@ -1788,27 +1777,137 @@ public class Vala.GIdlParser : CodeVisitor {
return type;
}
- public DataType get_type_from_string (string type_arg) {
- bool is_unowned = false;
+ private 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;
+ }
- if (type_arg == "pointer") {
- return new PointerType (new VoidType ());
+ private 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;
+ }
+
+ private 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;
+ }
}
- if (type_arg.has_prefix ("unowned ")) {
- type_arg = type_arg.offset ("unowned ".length);
- is_unowned = true;
+ 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 = false;
+ } else {
+ Report.error (source_reference, "unexpected `unowned' keyword");
+ return null;
+ }
}
- foreach (unowned string s in type_arg.split (".")) {
- sym = new UnresolvedSymbol (sym, s);
+ 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;
+ }
}
- var arg_type = new UnresolvedType.from_symbol (sym);
- arg_type.value_owned = !is_unowned;
+ if (pointers_data != null) {
+ for (int i=0; i < pointers_data.length; i++) {
+ type = new PointerType (type);
+ }
+ }
- return arg_type;
+ if (array_data != null) {
+ type = new ArrayType (type, (int) array_data.length + 1, source_reference);
+ }
+
+ type.nullable = nullable;
+ type.value_owned = value_owned;
+ return type;
}
private Method? create_method (string name, string symbol, IdlNodeParam? res, GLib.List<IdlNodeParam>? parameters, bool is_constructor, bool is_interface) {
@@ -1912,19 +2011,9 @@ public class Vala.GIdlParser : CodeVisitor {
} else if (nv[0] == "array_length_type") {
m.array_length_type = eval (nv[1]);
} else if (nv[0] == "type_name") {
- var sym = new UnresolvedSymbol (null, eval (nv[1]));
- if (return_type is UnresolvedType) {
- ((UnresolvedType) return_type).unresolved_symbol = sym;
- } else {
- // Overwrite old return_type, so "type_name" must be before any
- // other return type modifying metadata
- m.return_type = return_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
- }
+ m.return_type = return_type = parse_type_from_string (eval (nv[1]), false);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- return_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (return_type, eval (nv[1]));
} else if (nv[0] == "deprecated") {
if (eval (nv[1]) == "1") {
m.deprecated = true;
@@ -2104,21 +2193,11 @@ public class Vala.GIdlParser : CodeVisitor {
set_delegate_target_pos = true;
delegate_target_pos = eval (nv[1]).to_double ();
} else if (nv[0] == "type_name") {
- var sym = new UnresolvedSymbol (null, eval (nv[1]));
- if (param_type is UnresolvedType) {
- ((UnresolvedType) param_type).unresolved_symbol = sym;
- } else {
- // Overwrite old param_type, so "type_name" must be before any
- // other param type modifying metadata
- p.variable_type = param_type = new UnresolvedType.from_symbol (sym, return_type.source_reference);
- }
+ p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
} else if (nv[0] == "ctype") {
p.ctype = eval (nv[1]);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- param_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (param_type, eval (nv[1]));
} else if (nv[0] == "default_value") {
var val = eval (nv[1]);
if (val == "null") {
@@ -2189,7 +2268,7 @@ public class Vala.GIdlParser : CodeVisitor {
if (suppress_throws == false && error_types != null) {
var type_args = eval (error_types).split (",");
foreach (string type_arg in type_args) {
- m.add_error_type (get_type_from_string (type_arg));
+ m.add_error_type (parse_type_from_string (type_arg, true));
}
}
@@ -2329,10 +2408,7 @@ public class Vala.GIdlParser : CodeVisitor {
return null;
}
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- prop.property_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
} else if (nv[0] == "deprecated") {
if (eval (nv[1]) == "1") {
prop.deprecated = true;
@@ -2350,7 +2426,7 @@ public class Vala.GIdlParser : CodeVisitor {
prop.get_accessor.value_type.value_owned = true;
}
} else if (nv[0] == "type_name") {
- prop.property_type = get_type_from_string (eval (nv[1]));
+ prop.property_type = parse_type_from_string (eval (nv[1]), false);
}
}
}
@@ -2437,12 +2513,9 @@ public class Vala.GIdlParser : CodeVisitor {
type.value_owned = true;
}
} else if (nv[0] == "type_name") {
- type = get_type_from_string (eval (nv[1]));
+ type = parse_type_from_string (eval (nv[1]), true);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (type, eval (nv[1]));
} else if (nv[0] == "deprecated") {
if (eval (nv[1]) == "1") {
deprecated = true;
@@ -2636,19 +2709,9 @@ public class Vala.GIdlParser : CodeVisitor {
} else if (nv[0] == "namespace_name") {
ns_name = eval (nv[1]);
} else if (nv[0] == "type_name") {
- var sym = new UnresolvedSymbol (null, eval (nv[1]));
- if (sig.return_type is UnresolvedType) {
- ((UnresolvedType) sig.return_type).unresolved_symbol = sym;
- } else {
- // Overwrite old return_type, so "type_name" must be before any
- // other return type modifying metadata
- sig.return_type = new UnresolvedType.from_symbol (sym, sig.return_type.source_reference);
- }
+ sig.return_type = parse_type_from_string (eval (nv[1]), false);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- sig.return_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
}
}
if (ns_name != null) {
@@ -2710,16 +2773,9 @@ public class Vala.GIdlParser : CodeVisitor {
param_type.value_owned = true;
}
} else if (nv[0] == "type_name") {
- if (!(param_type is UnresolvedType)) {
- param_type = new UnresolvedType ();
- p.variable_type = param_type;
- }
- ((UnresolvedType) param_type).unresolved_symbol = new UnresolvedSymbol (null, eval (nv[1]));
+ p.variable_type = param_type = parse_type_from_string (eval (nv[1]), false);
} else if (nv[0] == "type_arguments") {
- var type_args = eval (nv[1]).split (",");
- foreach (string type_arg in type_args) {
- p.variable_type.add_type_argument (get_type_from_string (type_arg));
- }
+ parse_type_arguments_from_string (p.variable_type, eval (nv[1]));
} else if (nv[0] == "namespace_name") {
ns_name = eval (nv[1]);
}