tests: Test custom types in lookup expressions

This commit is contained in:
James Westman 2022-04-30 16:13:40 -05:00
parent c7c32cbb4a
commit 52f7d790bd
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
10 changed files with 82 additions and 14 deletions

View file

@ -32,6 +32,10 @@ class Expr(AstNode):
def gir_type(self):
return self.children[-1].gir_type
@property
def glib_type_name(self):
return self.children[-1].glib_type_name
def emit_xml(self, xml: XmlEmitter):
self.children[-1].emit_xml(xml)
@ -71,6 +75,15 @@ class IdentExpr(AstNode):
elif self.tokens["ident"] in scope.get_objects():
return scope.get_objects()[self.tokens["ident"]].gir_class
@property
def glib_type_name(self):
scope = self.parent_by_type(Scope)
if self.is_this:
return scope.this_type_glib_name
elif self.tokens["ident"] in scope.get_objects():
return scope.get_objects()[self.tokens["ident"]].glib_type_name
def emit_xml(self, xml: XmlEmitter):
if self.is_this:
raise CompilerBugError()
@ -97,6 +110,10 @@ class ClosureExpr(AstNode):
def gir_type(self):
return self.parent.parent.gir_type
@property
def glib_type_name(self):
return self.parent.parent.glib_type_name
def emit_xml(self, xml: XmlEmitter):
xml.start_tag("closure", function=self.tokens["function"], type=self.gir_type)
for child in self.children[Expr]:
@ -113,6 +130,11 @@ class LookupOp(InfixExpr):
if prop := parent_type.properties.get(self.tokens["property"]):
return prop.type
@property
def glib_type_name(self):
if self.gir_type is not None:
return self.gir_type.glib_type_name
@validate("property")
def property_exists(self):
if parent_type := self.lhs.gir_type:
@ -127,9 +149,9 @@ class LookupOp(InfixExpr):
def emit_xml(self, xml: XmlEmitter):
if isinstance(self.lhs, IdentExpr) and self.lhs.is_this:
xml.put_self_closing("lookup", name=self.tokens["property"], type=self.parent_by_type(Scope).this_type)
xml.put_self_closing("lookup", name=self.tokens["property"], type=self.parent_by_type(Scope).this_type_glib_name)
else:
xml.start_tag("lookup", name=self.tokens["property"], type=self.lhs.gir_type)
xml.start_tag("lookup", name=self.tokens["property"], type=self.lhs.glib_type_name)
self.lhs.emit_xml(xml)
xml.end_tag()
@ -141,6 +163,10 @@ class CastExpr(AstNode):
def gir_type(self):
return self.children[TypeName][0].gir_type
@property
def glib_type_name(self):
return self.children[TypeName][0].glib_type_name
def emit_xml(self, xml: XmlEmitter):
self.children[Expr][0].emit_xml(xml)

View file

@ -21,6 +21,7 @@
import typing as T
from functools import cached_property
from ..gir import Class
from .types import ConcreteClassName, ClassName
from .common import *
from .response_id import ResponseId
@ -60,10 +61,13 @@ class Object(AstNode):
@property
def gir_class(self):
class_names = self.children[ClassName]
if len(class_names) == 0:
return None
else:
return class_names[0].gir_type
if len(class_names) > 0:
if isinstance(class_names[0].gir_type, Class):
return class_names[0].gir_type
@property
def glib_type_name(self) -> str:
return self.children[ClassName][0].glib_type_name
@docs("namespace")
def namespace_docs(self):
@ -94,7 +98,7 @@ class Object(AstNode):
from .gtkbuilder_child import Child
xml.start_tag("object", **{
"class": self.children[ClassName][0].glib_type_name,
"class": self.glib_type_name,
"id": self.tokens["id"],
})
for child in self.children:

View file

@ -51,3 +51,7 @@ class Lambda(Value, Scope):
@property
def this_type(self) -> str:
return self.children[TypeName][0].gir_type
@property
def this_type_glib_name(self) -> str:
return self.children[TypeName][0].glib_type_name

View file

@ -20,6 +20,7 @@
import typing as T
from .common import *
from ..gir import Class, Interface
class TypeName(AstNode):
@ -80,16 +81,19 @@ class TypeName(AstNode):
class ClassName(TypeName):
@validate("class_name")
def gir_type_is_class(self):
if self.gir_type is not None and not isinstance(self.gir_type, gir.Class):
raise CompileError(f"{self.gir_type.full_name} is not a class")
@validate("namespace", "class_name")
def gir_class_exists(self):
if self.gir_type is not None and not isinstance(self.gir_type, Class):
if isinstance(self.gir_type, Interface):
raise CompileError(f"{self.gir_type.full_name} is an interface, not a class")
else:
raise CompileError(f"{self.gir_type.full_name} is not a class")
class ConcreteClassName(ClassName):
@validate("namespace", "class_name")
def not_abstract(self):
if self.gir_type is not None and self.gir_type.abstract:
if isinstance(self.gir_type, Class) and self.gir_type.abstract:
raise CompileError(
f"{self.gir_type.full_name} can't be instantiated because it's abstract",
hints=[f"did you mean to use a subclass of {self.gir_type.full_name}?"]

View file

@ -1,3 +1,5 @@
using Gtk 4.0;
template TestTemplate : Gtk.Orientable {}
Gtk.Orientable {}
int {}

View file

@ -1 +1,3 @@
3,29,10,Gtk.Orientable is not a class
3,25,14,Gtk.Orientable is an interface, not a class
4,1,14,Gtk.Orientable is an interface, not a class
5,1,3,int is not a class

View file

@ -0,0 +1,8 @@
using Gtk 4.0;
.MyWidget widget {}
.MyOtherWidget other_widget {
property: bind ((.MyObject) widget.something).other;
expr-prop: (.MyObject obj) => obj.other;
}

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="MyWidget" id="widget"></object>
<object class="MyOtherWidget" id="other_widget">
<binding name="property">
<lookup name="other" type="MyObject">
<lookup name="something" type="MyWidget">
<constant>widget</constant>
</lookup>
</lookup>
</binding>
<property name="expr-prop">
<lookup name="other" type="MyObject"/>
</property>
</object>
</interface>

View file

@ -137,6 +137,7 @@ class TestSamples(unittest.TestCase):
self.assert_sample("comments")
self.assert_sample("enum")
self.assert_sample("expr_closure")
self.assert_sample("expr_custom_types")
self.assert_sample("expr_lookup")
self.assert_sample("file_filter")
self.assert_sample("flags")