From f78478bea118583ea8f730a9e426f262f3f642fc Mon Sep 17 00:00:00 2001 From: James Westman Date: Thu, 28 Apr 2022 22:42:09 -0500 Subject: [PATCH] validation: Writable/construct-only properties Add two new errors, one for non-writable properties and another for binding construct-only properties. --- blueprintcompiler/gir.py | 8 ++++++++ blueprintcompiler/language/gobject_property.py | 15 ++++++++++++++- tests/sample_errors/read_only_properties.blp | 6 ++++++ tests/sample_errors/read_only_properties.err | 2 ++ tests/test_samples.py | 1 + 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/sample_errors/read_only_properties.blp create mode 100644 tests/sample_errors/read_only_properties.err diff --git a/blueprintcompiler/gir.py b/blueprintcompiler/gir.py index e30f04a..973ccbb 100644 --- a/blueprintcompiler/gir.py +++ b/blueprintcompiler/gir.py @@ -184,6 +184,14 @@ class Property(GirNode): def signature(self): return f"{self.type_name} {self.container.name}.{self.name}" + @property + def writable(self): + return self.xml["writable"] == "1" + + @property + def construct_only(self): + return self.xml["construct-only"] == "1" + class Parameter(GirNode): def __init__(self, container: GirNode, xml: xml_reader.Element): diff --git a/blueprintcompiler/language/gobject_property.py b/blueprintcompiler/language/gobject_property.py index 99e51fd..a542901 100644 --- a/blueprintcompiler/language/gobject_property.py +++ b/blueprintcompiler/language/gobject_property.py @@ -29,7 +29,7 @@ class Property(AstNode): Statement( UseIdent("name"), ":", - "bind", + Keyword("bind"), UseIdent("bind_source").expected("the ID of a source object to bind from"), ".", UseIdent("bind_property").expected("a property name to bind from"), @@ -85,6 +85,19 @@ class Property(AstNode): did_you_mean=(self.tokens["name"], self.gir_class.properties.keys()) ) + @validate("bind") + def property_bindable(self): + if self.tokens["bind"] and self.gir_property is not None and self.gir_property.construct_only: + raise CompileError( + f"{self.gir_property.full_name} can't be bound because it is construct-only", + hints=["construct-only properties may only be set to a static value"] + ) + + @validate("name") + def property_writable(self): + if self.gir_property is not None and not self.gir_property.writable: + raise CompileError(f"{self.gir_property.full_name} is not writable") + @validate() def obj_property_type(self): diff --git a/tests/sample_errors/read_only_properties.blp b/tests/sample_errors/read_only_properties.blp new file mode 100644 index 0000000..0c0b5ca --- /dev/null +++ b/tests/sample_errors/read_only_properties.blp @@ -0,0 +1,6 @@ +using Gtk 4.0; + +ComboBox combo_box { + has-entry: bind combo_box.visible; + scale-factor: 2; +} diff --git a/tests/sample_errors/read_only_properties.err b/tests/sample_errors/read_only_properties.err new file mode 100644 index 0000000..dc03297 --- /dev/null +++ b/tests/sample_errors/read_only_properties.err @@ -0,0 +1,2 @@ +4,14,4,ComboBox.has-entry can't be bound because it is construct-only +5,3,12,Widget.scale-factor is not writable diff --git a/tests/test_samples.py b/tests/test_samples.py index f077536..c490388 100644 --- a/tests/test_samples.py +++ b/tests/test_samples.py @@ -190,6 +190,7 @@ class TestSamples(unittest.TestCase): self.assert_sample_error("obj_in_string_list") self.assert_sample_error("obj_prop_type") self.assert_sample_error("property_dne") + self.assert_sample_error("read_only_properties") self.assert_sample_error("signal_dne") self.assert_sample_error("signal_object_dne") self.assert_sample_error("size_group_non_widget")