feat(parser): add new ast nodes to parser
This commit is contained in:
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user