feat(ast): add basic AST expressions and printer
This commit is contained in:
16
main.py
16
main.py
@@ -1,5 +1,7 @@
|
||||
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr
|
||||
from src.ast.printer import AstPrinter
|
||||
from src.lexer import Lexer
|
||||
from src.token import Token
|
||||
from src.token import Token, TokenType
|
||||
|
||||
|
||||
def main():
|
||||
@@ -17,5 +19,17 @@ def main():
|
||||
tokens: list[Token] = lexer.process(source, path)
|
||||
print(tokens)
|
||||
|
||||
printer: AstPrinter = AstPrinter()
|
||||
ast: Expr = BinaryExpr(
|
||||
UnaryExpr(
|
||||
Token(TokenType.MINUS, "-", None, None),
|
||||
LiteralExpr(123)
|
||||
),
|
||||
Token(TokenType.STAR, "*", None, None),
|
||||
GroupingExpr(LiteralExpr(45.67))
|
||||
)
|
||||
print(printer.print(ast))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
0
src/ast/__init__.py
Normal file
0
src/ast/__init__.py
Normal file
70
src/ast/expr.py
Normal file
70
src/ast/expr.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, TypeVar, Generic
|
||||
|
||||
from src.token import Token
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Expr(ABC):
|
||||
@abstractmethod
|
||||
def accept(self, visitor: Visitor[T]) -> T:
|
||||
...
|
||||
|
||||
|
||||
class Visitor(ABC, Generic[T]):
|
||||
@abstractmethod
|
||||
def visit_binary_expr(self, expr: BinaryExpr) -> T:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def visit_unary_expr(self, expr: UnaryExpr) -> T:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def visit_grouping_expr(self, expr: GroupingExpr) -> T:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def visit_literal_expr(self, expr: LiteralExpr) -> T:
|
||||
...
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BinaryExpr(Expr):
|
||||
left: Expr
|
||||
operator: Token
|
||||
right: Expr
|
||||
|
||||
def accept(self, visitor: Visitor[T]) -> T:
|
||||
return visitor.visit_binary_expr(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UnaryExpr(Expr):
|
||||
operator: Token
|
||||
right: Expr
|
||||
|
||||
def accept(self, visitor: Visitor[T]) -> T:
|
||||
return visitor.visit_unary_expr(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GroupingExpr(Expr):
|
||||
expression: Expr
|
||||
|
||||
def accept(self, visitor: Visitor[T]) -> T:
|
||||
return visitor.visit_grouping_expr(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LiteralExpr(Expr):
|
||||
value: Any
|
||||
|
||||
def accept(self, visitor: Visitor[T]) -> T:
|
||||
return visitor.visit_literal_expr(self)
|
||||
21
src/ast/printer.py
Normal file
21
src/ast/printer.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from src.ast.expr import Visitor, Expr, LiteralExpr, T, GroupingExpr, UnaryExpr, BinaryExpr
|
||||
|
||||
|
||||
class AstPrinter(Visitor[str]):
|
||||
def print(self, expr: Expr):
|
||||
return expr.accept(self)
|
||||
|
||||
def parenthesize(self, name: str, *expressions: Expr):
|
||||
return f"({name} {' '.join(expr.accept(self) for expr in expressions)})"
|
||||
|
||||
def visit_binary_expr(self, expr: BinaryExpr) -> str:
|
||||
return self.parenthesize(expr.operator.lexeme, expr.left, expr.right)
|
||||
|
||||
def visit_unary_expr(self, expr: UnaryExpr) -> str:
|
||||
return self.parenthesize(expr.operator.lexeme, expr.right)
|
||||
|
||||
def visit_grouping_expr(self, expr: GroupingExpr) -> str:
|
||||
return self.parenthesize("group", expr.expression)
|
||||
|
||||
def visit_literal_expr(self, expr: LiteralExpr) -> str:
|
||||
return str(expr.value)
|
||||
Reference in New Issue
Block a user