feat(parser): add new ast nodes to parser

This commit is contained in:
2026-06-11 13:49:47 +02:00
parent 31158df2a9
commit bfa0bb3ee0
2 changed files with 37 additions and 20 deletions

View File

@@ -50,6 +50,7 @@ class TokenType(Enum):
PREDICATE = auto() PREDICATE = auto()
EXTEND = auto() EXTEND = auto()
WHERE = auto() WHERE = auto()
FUNC = auto()
# Misc # Misc
COMMENT = auto() COMMENT = auto()
@@ -67,6 +68,7 @@ KEYWORDS: dict[str, TokenType] = {
"true": TokenType.TRUE, "true": TokenType.TRUE,
"false": TokenType.FALSE, "false": TokenType.FALSE,
"none": TokenType.NONE, "none": TokenType.NONE,
"fn": TokenType.FUNC,
} }

View File

@@ -7,16 +7,17 @@ from midas.ast.midas import (
ConstraintType, ConstraintType,
Expr, Expr,
ExtendStmt, ExtendStmt,
ExtensionType,
FunctionType, FunctionType,
GenericType, GenericType,
GetExpr, GetExpr,
GroupingExpr, GroupingExpr,
LiteralExpr, LiteralExpr,
LogicalExpr, LogicalExpr,
MemberStmt,
NamedType, NamedType,
OpStmt, OpStmt,
PredicateStmt, PredicateStmt,
PropertyStmt,
Stmt, Stmt,
Type, Type,
TypeParam, TypeParam,
@@ -163,7 +164,19 @@ class MidasParser(Parser):
Returns: Returns:
TypeExpr: the parsed type expression TypeExpr: the parsed type expression
""" """
return self.constraint_type() base: Type
if self.match(TokenType.FUNC):
base = self.function()
else:
base = self.constraint_type()
if self.match(TokenType.AND):
extension: ComplexType = self.complex_type()
return ExtensionType(
location=Location.span(base.location, extension.location),
base=base,
extension=extension,
)
return base
def constraint_type(self) -> Type: def constraint_type(self) -> Type:
type: Type = self.base_type() type: Type = self.base_type()
@@ -215,30 +228,32 @@ class MidasParser(Parser):
name=name, name=name,
) )
def complex_type(self) -> Type: def complex_type(self) -> ComplexType:
"""Parse a type definition body """Parse a type definition body
A type definition body is a set of whitespace-separated A type definition body is a set of whitespace-separated
property statements enclosed in curly braces property statements enclosed in curly braces
Returns: Returns:
list[PropertyStmt]: the parsed type properties ComplexType: the parsed complex type
""" """
left: Token = self.consume( left: Token = self.consume(
TokenType.LEFT_BRACE, "Expected '{' to start type body" TokenType.LEFT_BRACE, "Expected '{' to start type body"
) )
properties: list[PropertyStmt] = [] members: list[MemberStmt] = []
# TODO: add keyword to differentiate properties and methods,
# and allow multiple methods with the same name but not properties
names: set[str] = set() names: set[str] = set()
while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end(): while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end():
prop: PropertyStmt = self.property_stmt() member: MemberStmt = self.member_stmt()
if prop.name.lexeme in names: # if member.name.lexeme in names:
raise self.error(prop.name, "Duplicate property") # raise self.error(member.name, "Duplicate property")
names.add(prop.name.lexeme) # names.add(member.name.lexeme)
properties.append(prop) members.append(member)
right: Token = self.consume(TokenType.RIGHT_BRACE, "Unclosed type body") right: Token = self.consume(TokenType.RIGHT_BRACE, "Unclosed type body")
return ComplexType( return ComplexType(
location=left.location_to(right), location=left.location_to(right),
properties=properties, members=members,
) )
def constraint(self) -> Expr: def constraint(self) -> Expr:
@@ -376,18 +391,18 @@ class MidasParser(Parser):
return True return True
return False return False
def property_stmt(self) -> PropertyStmt: def member_stmt(self) -> MemberStmt:
"""Parse a property statement """Parse a member statement
A type property statement is written `name: Type` or `name: Type where Condition` A type member statement is written `name: Type`
Returns: Returns:
PropertyStmt: the parsed property statement MemberStmt: the parsed member statement
""" """
name: Token = self.consume_identifier("Expected property name") name: Token = self.consume_identifier("Expected member name")
self.consume(TokenType.COLON, "Expected ':' after property name") self.consume(TokenType.COLON, "Expected ':' after member name")
type: Type = self.type_expr() type: Type = self.type_expr()
return PropertyStmt( return MemberStmt(
location=name.location_to(self.previous()), location=name.location_to(self.previous()),
name=name, name=name,
type=type, type=type,
@@ -487,12 +502,12 @@ class MidasParser(Parser):
name = self.advance() name = self.advance()
self.advance() self.advance()
type: Type = self.type_expr() type: Type = self.type_expr()
required: bool = self.match(TokenType.QMARK) optional: bool = self.match(TokenType.QMARK)
arg = FunctionType.Argument( arg = FunctionType.Argument(
location=None, location=None,
name=name, name=name,
type=type, type=type,
required=required, required=not optional,
) )
if positional: if positional:
pos_args.append(arg) pos_args.append(arg)