add parser

This commit is contained in:
SimonFJ20 2023-04-08 19:21:37 +02:00
parent 4f2bf4f2ba
commit 5135c149ef
3 changed files with 238 additions and 6 deletions

View File

@ -2,6 +2,15 @@ from enum import Enum, auto
from position import Node
from typing import Optional, List
class Type:
def __str__(self) -> str:
raise NotImplementedError()
class TypeError(Type):
def __init__(self, message: str) -> None:
super().__init__()
self.message = message
class Pattern:
def __str__(self) -> str:
raise NotImplementedError()
@ -11,6 +20,14 @@ class PatternError(Pattern):
super().__init__()
self.message = message
class Parameter:
def __init__(self, subject: Pattern, value_type: Type) -> None:
self.subject = subject
self.value_type = value_type
def __str__(self) -> str:
return f"Parameter {{ subject: {self.subject}, value_type: {self.value_type} }}"
class Expr:
def __str__(self) -> str:
raise NotImplementedError()
@ -76,6 +93,14 @@ class Unit(Expr):
def __str__(self) -> str:
return "Unit"
class Tuple(Expr):
def __init__(self, values: List[Node[Expr]]) -> None:
super().__init__()
self.values = values
def __str__(self) -> str:
values = ", ".join(node.__str__() for node in self.values)
return f"Tuple {{ values: [{values}] }}"
class Block(Expr):
def __init__(self, statements: List[Node[Expr]], value: Optional[Node[Expr]]) -> None:
@ -87,6 +112,16 @@ class Block(Expr):
statements = ", ".join(node.__str__() for node in self.statements)
return f"Block {{ statements: [{statements}], value: {self.value} }}"
class Lambda(Expr):
def __init__(self, params: List[Node[Parameter]], body: Node[Expr]) -> None:
super().__init__()
self.params = params
self.body = body
def __str__(self) -> str:
params = ", ".join(node.__str__() for node in self.params)
return f"Lambda {{ params: [{params}], body: {self.body} }}"
class If(Expr):
def __init__(self, condition: Node[Expr], truthy: Node[Expr], falsy: Optional[Node[Expr]]) -> None:
@ -238,3 +273,49 @@ class Assign(Expr):
def __str__(self) -> str:
return f"Assign {{ assign_type: {self.assign_type}, subject: {self.subject}, value: {self.value} }}"
class Let(Expr):
def __init__(self, subject: Node[Pattern], value_type: Optional[Node[Type]], value: Node[Expr]) -> None:
super().__init__()
self.subject = subject
self.value_type = value_type
self.value = value
def __str__(self) -> str:
return f"Let {{ subject: {self.subject}, value_type: {self.value_type}, value: {self.value} }}"
class Function(Expr):
def __init__(self, subject_id: str, params: List[Node[Parameter]], body: Node[Expr]) -> None:
super().__init__()
self.subject_id = subject_id
self.params = params
self.body = body
def __str__(self) -> str:
params = ", ".join(node.__str__() for node in self.params)
return f"Function {{ subject_id: {self.subject_id}, params: [{params}], body: {self.body} }}"
class Return(Expr):
def __init__(self, value: Optional[Node[Expr]]) -> None:
super().__init__()
self.value = value
def __str__(self) -> str:
return f"Return {{ value: {self.value} }}"
class Break(Expr):
def __init__(self, value: Optional[Node[Expr]]) -> None:
super().__init__()
self.value = value
def __str__(self) -> str:
return f"Break {{ value: {self.value} }}"
class Continue(Expr):
def __init__(self, value: Optional[Node[Expr]]) -> None:
super().__init__()
self.value = value
def __str__(self) -> str:
return f"Continue {{ value: {self.value} }}"

113
parser.py
View File

@ -1,7 +1,8 @@
from tokens import Token, TokenType, TokenIterator
from position import Span, Node
from parsed import Assign, AssignType, Binary, BinaryType, Block, Call, MatchArm, PatternError, Expr, For, Id, If, Index, Int, Char, Loop, Pattern, String, ExprError, StructMember, TupleMember, Unary, UnaryType, While
from position import Position, Span, Node
from parsed import Assign, AssignType, Binary, BinaryType, Block, Break, Call, Continue, Match, MatchArm, PatternError, Expr, For, Id, If, Index, Int, Char, Loop, Pattern, Return, String, ExprError, StructMember, Tuple, TupleMember, Unary, UnaryType, Unit, While
from typing import List, Optional
from utils import Result, Ok, Err
class Parser:
@ -234,6 +235,8 @@ class Parser:
value = token.text_slice(self.text)
self.step()
return Node(String(value), token.span)
elif self.current_is(TokenType.LParen):
return self.parse_unit_group_tuple()
elif self.current_is(TokenType.LBrace):
return self.parse_block()
elif self.current_is(TokenType.KwIf):
@ -249,6 +252,38 @@ class Parser:
self.step()
return Node(ExprError("expected value"), token.span)
def parse_unit_group_tuple(self) -> Node[Expr]:
begin = self.current().span
self.step()
if self.current_is(TokenType.RParen):
end = self.current().span
self.step()
return Node(Unit(), begin.to(end))
else:
first_expr = self.parse_expr()
if self.current_is(TokenType.RParen):
end = self.current().span
self.step()
return Node(first_expr.value, begin.to(end))
elif self.current_is(TokenType.Comma):
values = [first_expr]
end = self.current().span
while self.current_is(TokenType.Comma):
end = self.current().span
self.step()
if self.done() or self.current().token_type == TokenType.RParen:
break
value = self.parse_expr()
end = value.span
values.append(value)
if not self.current_is(TokenType.RParen):
return Node(ExprError("expected ')'"), begin.to(end))
end = self.current().span
self.step()
return Node(Tuple(values), begin.to(end))
else:
return Node(ExprError("expected ')' or ','"), begin.to(first_expr.span))
def parse_block(self) -> Node[Expr]:
begin = self.current().span
self.step()
@ -288,17 +323,58 @@ class Parser:
def parse_match(self) -> Node[Expr]:
begin = self.current().span
self.step()
value = self.parse_expr()
if not self.current_is(TokenType.LBrace):
return Node(ExprError("expected '{'"), begin)
lbrace_span = self.current().span
self.step()
arms: List[Node[MatchArm]] = []
if not self.done() and self.current() != TokenType.RBrace:
arm = self.parse_match_arm()
if not arm.ok():
return Node(ExprError(arm.error().value), begin.to(arm.error().span))
arms.append(arm.value())
while not self.done() and self.current() != TokenType.RBrace:
arm = self.parse_match_arm()
if not arm.ok():
return Node(ExprError(arm.error().value), begin.to(arm.error().span))
arms.append(arm.value())
if not self.current_is(TokenType.RBrace):
if len(arms) > 0:
end = arms[-1].span
else:
end = lbrace_span
return Node(ExprError("expected '}'"), begin.to(end))
rbrace_span = self.current().span
self.step()
return Node(Match(value, arms), begin.to(rbrace_span))
def parse_match_arm(self) -> Node[MatchArm]:
pass
def parse_match_arm_statement(self) -> Node[Expr]:
pass
def parse_match_arm(self) -> Result[Node[MatchArm], Node[str]]:
pattern = self.parse_pattern()
if not self.current_is(TokenType.EqualLT):
return Err(Node("expected '=>'", pattern.span.to(pattern.span)))
self.step()
if self.current_is(TokenType.LParen):
expr = self.parse_block()
if self.current_is(TokenType.Comma):
self.step()
else:
expr = self.parse_match_arm_expr()
if not self.current_is(TokenType.Comma):
return Err(Node("expected ','", pattern.span.to(expr.span)))
self.step()
return Ok(Node(MatchArm(pattern, expr), pattern.span.to(expr.span)))
def parse_match_arm_expr(self) -> Node[Expr]:
if self.current_is(TokenType.KwReturn):
return self.parse_return()
elif self.current_is(TokenType.KwBreak):
return self.parse_break()
elif self.current_is(TokenType.KwContinue):
return self.parse_continue()
else:
return self.parse_expr()
def parse_loop(self) -> Node[Expr]:
begin = self.current().span
@ -332,6 +408,31 @@ class Parser:
body = self.parse_block()
return Node(For(subject, value, body), begin.to(body.span))
def parse_return(self) -> Node[Expr]:
begin = self.current().span
self.step()
value: Optional[Node[Expr]] = None
if not self.done() and self.current() not in [TokenType.Comma, TokenType.Semicolon]:
value = self.parse_expr()
return Node(Return(value), begin.to(value.span if value is not None else begin))
def parse_break(self) -> Node[Expr]:
begin = self.current().span
self.step()
value: Optional[Node[Expr]] = None
if not self.done() and self.current() not in [TokenType.Comma, TokenType.Semicolon]:
value = self.parse_expr()
return Node(Break(value), begin.to(value.span if value is not None else begin))
def parse_continue(self) -> Node[Expr]:
begin = self.current().span
self.step()
value: Optional[Node[Expr]] = None
if not self.done() and self.current() not in [TokenType.Comma, TokenType.Semicolon]:
value = self.parse_expr()
return Node(Continue(value), begin.to(value.span if value is not None else begin))
def parse_pattern(self) -> Node[Pattern]:
return Node(PatternError("not implemented"), self.current().span)

50
utils.py Normal file
View File

@ -0,0 +1,50 @@
from typing import Generic, TypeVar
class UnwrapException(Exception):
def __init__(self, *args: object) -> None:
super().__init__(*args)
T = TypeVar("T")
E = TypeVar("E")
class Result(Generic[T, E]):
def __init__(self) -> None:
super().__init__()
def ok(self) -> bool:
raise NotImplementedError()
def value(self) -> T:
raise NotImplementedError()
def error(self) -> E:
raise NotImplementedError()
class Ok(Result[T, E]):
def __init__(self, value: T) -> None:
super().__init__()
self.__value = value
def ok(self) -> bool:
return True
def value(self) -> T:
return self.__value
def error(self) -> E:
raise UnwrapException("cannot unwrap error of ok result")
class Err(Result[T, E]):
def __init__(self, error: E) -> None:
super().__init__()
self.__error = error
def ok(self) -> bool:
return False
def value(self) -> T:
raise UnwrapException("cannot unwrap value of error result")
def error(self) -> E:
return self.__error