language: Add cast expressions

This commit is contained in:
James Westman 2022-12-23 23:24:29 -06:00
parent 2033bd9e16
commit 5cf9b63547
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
15 changed files with 122 additions and 20 deletions

View file

@ -19,29 +19,59 @@
from .common import *
from .types import TypeName
expr = Pratt()
class Expr(AstNode):
class Expr:
@property
def type(self) -> T.Optional[GirType]:
raise NotImplementedError()
class ExprChain(Expr, AstNode):
grammar = expr
@property
def last(self) -> Expr:
return self.children[-1]
class InfixExpr(AstNode):
@property
def type(self) -> T.Optional[GirType]:
return self.last.type
class InfixExpr(Expr, AstNode):
@property
def lhs(self):
children = list(self.parent_by_type(Expr).children)
children = list(self.parent_by_type(ExprChain).children)
return children[children.index(self) - 1]
class IdentExpr(AstNode):
class IdentExpr(Expr, AstNode):
grammar = UseIdent("ident")
@property
def ident(self) -> str:
return self.tokens["ident"]
@validate()
def exists(self):
if self.root.objects_by_id.get(self.ident) is None:
raise CompileError(
f"Could not find object with ID {self.ident}",
did_you_mean=(self.ident, self.root.objects_by_id.keys()),
)
@property
def type(self) -> T.Optional[GirType]:
if object := self.root.objects_by_id.get(self.ident):
return object.gir_class
else:
return None
class LookupOp(InfixExpr):
grammar = [".", UseIdent("property")]
@ -50,9 +80,53 @@ class LookupOp(InfixExpr):
def property_name(self) -> str:
return self.tokens["property"]
@property
def type(self) -> T.Optional[GirType]:
if isinstance(self.lhs.type, gir.Class) or isinstance(
self.lhs.type, gir.Interface
):
if property := self.lhs.type.properties.get(self.property_name):
return property.type
return None
@validate("property")
def property_exists(self):
if self.lhs.type is None or isinstance(self.lhs.type, UncheckedType):
return
elif not isinstance(self.lhs.type, gir.Class) and not isinstance(
self.lhs.type, gir.Interface
):
raise CompileError(
f"Type {self.lhs.type.full_name} does not have properties"
)
elif self.lhs.type.properties.get(self.property_name) is None:
raise CompileError(
f"{self.lhs.type.full_name} does not have a property called {self.property_name}"
)
class CastExpr(InfixExpr):
grammar = ["as", "(", TypeName, ")"]
@property
def type(self) -> T.Optional[GirType]:
return self.children[TypeName][0].gir_type
@validate()
def cast_makes_sense(self):
if self.lhs.type is None:
return
if not self.type.assignable_to(self.lhs.type):
raise CompileError(
f"Invalid cast. No instance of {self.lhs.type.full_name} can be an instance of {self.type.full_name}."
)
expr.children = [
Prefix(IdentExpr),
Prefix(["(", Expr, ")"]),
Prefix(["(", ExprChain, ")"]),
Infix(10, LookupOp),
Infix(10, CastExpr),
]