expressions: Validate lookup expressions

This commit is contained in:
James Westman 2022-04-30 15:20:05 -05:00
parent cc1d2ab78f
commit 76a482affb
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
8 changed files with 50 additions and 9 deletions

View file

@ -50,12 +50,26 @@ class IdentExpr(AstNode):
def is_this(self): def is_this(self):
return self.parent_by_type(Scope).this_name == self.tokens["ident"] return self.parent_by_type(Scope).this_name == self.tokens["ident"]
@validate()
def exists(self):
if self.is_this:
return
scope = self.parent_by_type(Scope)
if self.tokens["ident"] not in scope.variables:
raise CompileError(
f"Could not find object with ID '{self.tokens['ident']}'",
did_you_mean=(self.tokens['ident'], scope.variables.keys()),
)
@property @property
def gir_type(self): def gir_type(self):
scope = self.parent_by_type(Scope)
if self.is_this: if self.is_this:
return self.parent_by_type(Scope).this_type return scope.this_type
else: elif self.tokens["ident"] in scope.variables:
return None return scope.variables[self.tokens["ident"]].gir_class
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
if self.is_this: if self.is_this:
@ -93,7 +107,21 @@ class LookupOp(InfixExpr):
@property @property
def gir_type(self): def gir_type(self):
return None if parent_type := self.lhs.gir_type:
if prop := parent_type.properties.get(self.tokens["property"]):
return prop.type
@validate("property")
def property_exists(self):
if parent_type := self.lhs.gir_type:
if not (isinstance(parent_type, gir.Class) or isinstance(parent_type, gir.Interface)):
raise CompileError(f"Type {parent_type.full_name} does not have properties")
elif self.tokens["property"] not in parent_type.properties:
raise CompileError(
f"{parent_type.full_name} does not have a property called {self.tokens['property']}",
hints=["Do you need to cast the previous expression?"],
did_you_mean=(self.tokens['property'], parent_type.properties.keys()),
)
def emit_xml(self, xml: XmlEmitter): def emit_xml(self, xml: XmlEmitter):
if isinstance(self.lhs, IdentExpr) and self.lhs.is_this: if isinstance(self.lhs, IdentExpr) and self.lhs.is_this:

View file

@ -0,0 +1,9 @@
using Gtk 4.0;
Box {
Label label {
visible: bind label.parent.something;
margin-start: bind label.margin-start.other;
label: bind nothing.parent.label;
}
}

View file

@ -0,0 +1,3 @@
5,32,9,Gtk.Widget does not have a property called something
6,43,5,Type int does not have properties
7,17,7,Could not find object with ID 'nothing'

View file

@ -10,7 +10,7 @@
<binding name="visible-child"> <binding name="visible-child">
<lookup name="parent" type="GtkButton"> <lookup name="parent" type="GtkButton">
<closure function="my_closure" type="GtkButton"> <closure function="my_closure" type="GtkButton">
<lookup name="parent"> <lookup name="parent" type="GtkBox">
<constant>box</constant> <constant>box</constant>
</lookup> </lookup>
</closure> </closure>

View file

@ -5,5 +5,5 @@ Overlay {
} }
Label { Label {
label: bind ((Label) label.parent.child).label; label: bind ((Label) ((Overlay) label.parent).child).label;
} }

View file

@ -9,8 +9,8 @@
<object class="GtkLabel"> <object class="GtkLabel">
<binding name="label"> <binding name="label">
<lookup name="label" type="GtkLabel"> <lookup name="label" type="GtkLabel">
<lookup name="child"> <lookup name="child" type="GtkOverlay">
<lookup name="parent"> <lookup name="parent" type="GtkLabel">
<constant>label</constant> <constant>label</constant>
</lookup> </lookup>
</lookup> </lookup>

View file

@ -8,7 +8,7 @@
</object> </object>
<object class="GtkBoolFilter"> <object class="GtkBoolFilter">
<property name="expression"> <property name="expression">
<lookup name="invert"> <lookup name="invert" type="GtkBoolFilter">
<constant>filter</constant> <constant>filter</constant>
</lookup> </lookup>
</property> </property>

View file

@ -187,6 +187,7 @@ class TestSamples(unittest.TestCase):
self.assert_sample_error("duplicates") self.assert_sample_error("duplicates")
self.assert_sample_error("empty") self.assert_sample_error("empty")
self.assert_sample_error("enum_member_dne") self.assert_sample_error("enum_member_dne")
self.assert_sample_error("expr_lookup_prop")
self.assert_sample_error("filters_in_non_file_filter") self.assert_sample_error("filters_in_non_file_filter")
self.assert_sample_error("gtk_3") self.assert_sample_error("gtk_3")
self.assert_sample_error("gtk_exact_version") self.assert_sample_error("gtk_exact_version")