summaryrefslogtreecommitdiff
path: root/codegen
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2022-02-09 00:05:24 +0100
committerRico Tzschichholz <ricotz@ubuntu.com>2022-02-09 08:49:08 +0100
commit0d3ff97a2832f1d35d2d8eb488ecede4c7d7ca65 (patch)
tree9c349e88c17bcbb3c7754db5667d89c221a29ce9 /codegen
parenta1a8b3f80e9e764ceb2795285c20e18d25b6be97 (diff)
downloadvala-0d3ff97a2832f1d35d2d8eb488ecede4c7d7ca65.tar.gz
gtkmodule: Improve UI parsing and handling of nested objects and properties
Don't restrict GtkCallback to instance methods
Diffstat (limited to 'codegen')
-rw-r--r--codegen/valagtkmodule.vala134
1 files changed, 102 insertions, 32 deletions
diff --git a/codegen/valagtkmodule.vala b/codegen/valagtkmodule.vala
index c0d98631c..ae316cada 100644
--- a/codegen/valagtkmodule.vala
+++ b/codegen/valagtkmodule.vala
@@ -23,6 +23,27 @@
public class Vala.GtkModule : GSignalModule {
+
+ class InvalidClass : Class {
+ public InvalidClass (string name) {
+ base (name, null, null);
+ error = true;
+ }
+ public override bool check (CodeContext context) {
+ return false;
+ }
+ }
+
+ class InvalidProperty : Property {
+ public InvalidProperty (string name) {
+ base (name, null, null, null);
+ error = true;
+ }
+ public override bool check (CodeContext context) {
+ return false;
+ }
+ }
+
/* C type-func name to Vala class mapping */
private HashMap<string, Class> type_id_to_vala_map = null;
/* C class name to Vala class mapping */
@@ -31,7 +52,7 @@ public class Vala.GtkModule : GSignalModule {
private HashMap<string, string> gresource_to_file_map = null;
/* GtkBuilder xml handler set */
private HashMap<string, string> handler_map = new HashMap<string, string>(str_hash, str_equal);
- /* GtkBuilder xml handler to Vala signal mapping */
+ /* GtkBuilder xml handler to Vala property mapping */
private HashMap<string, Property> current_handler_to_property_map = new HashMap<string, Property>(str_hash, str_equal);
/* GtkBuilder xml handler to Vala signal mapping */
private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
@@ -40,6 +61,32 @@ public class Vala.GtkModule : GSignalModule {
/* Required custom application-specific gtype classes to be ref'd before initializing the template */
private List<Class> current_required_app_classes = new ArrayList<Class>();
+ /* Stack of occuring object elements in the template */
+ List<Class> current_object_stack = new ArrayList<Class> ();
+ Class? current_object;
+
+ void push_object (Class cl) {
+ current_object_stack.add (current_object);
+ current_object = cl;
+ }
+
+ void pop_object () {
+ current_object = current_object_stack.remove_at (current_object_stack.size - 1);
+ }
+
+ /* Stack of occuring property elements in the template */
+ List<Property> current_property_stack = new ArrayList<Property> ();
+ Property? current_property;
+
+ void push_property (Property prop) {
+ current_property_stack.add (current_property);
+ current_property = prop;
+ }
+
+ void pop_property () {
+ current_property = current_property_stack.remove_at (current_property_stack.size - 1);
+ }
+
private void ensure_type_id_to_vala_map () {
// map C type-func name of gtypeinstance classes to Vala classes
if (type_id_to_vala_map != null) {
@@ -156,10 +203,10 @@ public class Vala.GtkModule : GSignalModule {
handler_map = new HashMap<string, string>(str_hash, str_equal);
current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
current_child_to_class_map = new HashMap<string, Class>(str_hash, str_equal);
+ current_object_stack = new ArrayList<Class> ();
+ current_property_stack = new ArrayList<Property> ();
MarkupReader reader = new MarkupReader (ui_file);
- Class current_class = null;
- Property? current_property = null;
string? current_handler = null;
bool template_tag_found = false;
@@ -167,7 +214,7 @@ public class Vala.GtkModule : GSignalModule {
while (current_token != MarkupTokenType.EOF) {
unowned string current_name = reader.name;
if (current_token == MarkupTokenType.START_ELEMENT && (current_name == "object" || current_name == "template")) {
- current_class = null;
+ Class? current_class = null;
if (current_name == "object") {
var type_id = reader.get_attribute ("type-func");
@@ -186,6 +233,15 @@ public class Vala.GtkModule : GSignalModule {
continue;
}
current_class = cclass_to_vala_map.get (class_name);
+
+ if (current_class == null) {
+ push_object (new InvalidClass (class_name));
+ if (current_name == "template") {
+ Report.error (node.source_reference, "Unknown template `%s' in ui file `%s'", class_name, ui_file);
+ } else {
+ Report.warning (node.source_reference, "Unknown object `%s' in ui file `%s'", class_name, ui_file);
+ }
+ }
}
if (current_class != null) {
@@ -193,35 +249,40 @@ public class Vala.GtkModule : GSignalModule {
if (child_name != null) {
current_child_to_class_map.set (child_name, current_class);
}
+ push_object (current_class);
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "signal") {
+ } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name == "object" || current_name == "template")) {
+ pop_object ();
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "signal") {
var signal_name = reader.get_attribute ("name");
var handler_name = reader.get_attribute ("handler");
- if (current_class != null) {
- if (signal_name == null || handler_name == null) {
- if (signal_name != null) {
- Report.error (node.source_reference, "Invalid signal `%s' without handler in ui file `%s'", signal_name, ui_file);
- } else if (handler_name != null) {
- Report.error (node.source_reference, "Invalid signal without name in ui file `%s'", ui_file);
- } else {
- Report.error (node.source_reference, "Invalid signal without name and handler in ui file `%s'", ui_file);
- }
- current_token = reader.read_token (null, null);
- continue;
- }
- var sep_idx = signal_name.index_of ("::");
- if (sep_idx >= 0) {
- // detailed signal, we don't care about the detail
- signal_name = signal_name.substring (0, sep_idx);
+ if (signal_name == null || handler_name == null) {
+ if (signal_name != null) {
+ Report.error (node.source_reference, "Invalid signal `%s' without handler in ui file `%s'", signal_name, ui_file);
+ } else if (handler_name != null) {
+ Report.error (node.source_reference, "Invalid signal without name in ui file `%s'", ui_file);
+ } else {
+ Report.error (node.source_reference, "Invalid signal without name and handler in ui file `%s'", ui_file);
}
+ current_token = reader.read_token (null, null);
+ continue;
+ }
+ var sep_idx = signal_name.index_of ("::");
+ if (sep_idx >= 0) {
+ // detailed signal, we don't care about the detail
+ signal_name = signal_name.substring (0, sep_idx);
+ }
- var sig = SemanticAnalyzer.symbol_lookup_inherited (current_class, signal_name.replace ("-", "_")) as Signal;
- if (sig != null) {
- current_handler_to_signal_map.set (handler_name, sig);
- }
+ var sig = SemanticAnalyzer.symbol_lookup_inherited (current_object, signal_name.replace ("-", "_")) as Signal;
+ if (sig != null) {
+ current_handler_to_signal_map.set (handler_name, sig);
+ } else {
+ Report.error (node.source_reference, "Unknown signal `%s::%s' in ui file `%s'", current_object.get_full_name (), signal_name, ui_file);
+ current_token = reader.read_token (null, null);
+ continue;
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "binding") {
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && (current_name == "property" || current_name == "binding")) {
var property_name = reader.get_attribute ("name");
if (property_name == null) {
Report.error (node.source_reference, "Invalid binding in ui file `%s'", ui_file);
@@ -230,13 +291,20 @@ public class Vala.GtkModule : GSignalModule {
}
property_name = property_name.replace ("-", "_");
- current_property = SemanticAnalyzer.symbol_lookup_inherited (current_class, property_name) as Property;
- if (current_property == null) {
- Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'", current_class.get_full_name (), property_name, ui_file);
+ var property = SemanticAnalyzer.symbol_lookup_inherited (current_object, property_name) as Property;
+ if (property != null) {
+ push_property (property);
+ } else {
+ push_property (new InvalidProperty (property_name));
+ if (current_name == "binding") {
+ Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'", current_object.get_full_name (), property_name, ui_file);
+ }
current_token = reader.read_token (null, null);
continue;
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "closure") {
+ } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name == "property" || current_name == "binding")) {
+ pop_property ();
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "closure") {
var handler_name = reader.get_attribute ("function");
if (current_property != null) {
@@ -245,11 +313,13 @@ public class Vala.GtkModule : GSignalModule {
current_token = reader.read_token (null, null);
continue;
}
+ if (current_property is InvalidProperty) {
+ Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'", current_object.get_full_name (), current_property.name, ui_file);
+ }
//TODO Retrieve signature declaration? c-type to vala-type?
current_handler_to_property_map.set (handler_name, current_property);
current_handler = handler_name;
- current_property = null;
} else if (current_handler != null) {
// Track nested closure elements
handler_map.set (handler_name, current_handler);
@@ -386,7 +456,7 @@ public class Vala.GtkModule : GSignalModule {
return;
}
- if (m.binding != MemberBinding.INSTANCE || m.get_attribute ("GtkCallback") == null) {
+ if (m.get_attribute ("GtkCallback") == null) {
return;
}