calculator: add initial AST implementation
The AST's class hierarchy is defined inside the `calculator.ast` module. An abstract visitor is defined inside the `calculator.ast.visit` package.
This commit is contained in:
parent
e7c70bd6a5
commit
5ea82de840
1
calculator/calculator/__init__.py
Normal file
1
calculator/calculator/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
import calculator.ast
|
4
calculator/calculator/ast/__init__.py
Normal file
4
calculator/calculator/ast/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from .node import Node # isort:skip
|
||||
from .binop import BinOp
|
||||
from .constant import Constant
|
||||
from .unaryop import UnaryOp
|
28
calculator/calculator/ast/binop.py
Normal file
28
calculator/calculator/ast/binop.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Callable
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from .node import Node
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from calculator.ast.visit import Visitor
|
||||
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
@dataclass(config=Config)
|
||||
class BinOp(Node):
|
||||
"""
|
||||
Node to represent a binary operation
|
||||
"""
|
||||
|
||||
op: Callable[[int, int], int]
|
||||
lhs: Node
|
||||
rhs: Node
|
||||
|
||||
def accept(self, v: Visitor) -> None:
|
||||
v.visit_binop(self)
|
26
calculator/calculator/ast/constant.py
Normal file
26
calculator/calculator/ast/constant.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from .node import Node
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from calculator.ast.visit import Visitor
|
||||
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
@dataclass(config=Config)
|
||||
class Constant(Node):
|
||||
"""
|
||||
Node to represent a constant value.
|
||||
"""
|
||||
|
||||
value: int
|
||||
|
||||
def accept(self, v: Visitor) -> None:
|
||||
v.visit_constant(self)
|
17
calculator/calculator/ast/node.py
Normal file
17
calculator/calculator/ast/node.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from calculator.ast.visit import Visitor
|
||||
|
||||
|
||||
class Node(ABC):
|
||||
"""
|
||||
Abstract Node class for calculator AST.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def accept(self, v: Visitor) -> None:
|
||||
pass
|
27
calculator/calculator/ast/unaryop.py
Normal file
27
calculator/calculator/ast/unaryop.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Callable
|
||||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from .node import Node
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from calculator.ast.visit import Visitor
|
||||
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
@dataclass(config=Config)
|
||||
class UnaryOp(Node):
|
||||
"""
|
||||
Node to represent a unary operation
|
||||
"""
|
||||
|
||||
op: Callable[[int], int]
|
||||
rhs: Node
|
||||
|
||||
def accept(self, v: Visitor) -> None:
|
||||
v.visit_unaryop(self)
|
1
calculator/calculator/ast/visit/__init__.py
Normal file
1
calculator/calculator/ast/visit/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from .visitor import Visitor # isort:skip
|
28
calculator/calculator/ast/visit/visitor.py
Normal file
28
calculator/calculator/ast/visit/visitor.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from calculator.ast import BinOp, Constant, Node, UnaryOp
|
||||
|
||||
|
||||
class Visitor(ABC):
|
||||
"""
|
||||
Abstract Visitor class for the AST class hierarchy.
|
||||
"""
|
||||
|
||||
def visit(self, n: Node) -> None:
|
||||
n.accept(self)
|
||||
|
||||
@abstractmethod
|
||||
def visit_constant(self, c: Constant) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def visit_binop(self, b: BinOp) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def visit_unaryop(self, b: UnaryOp) -> None:
|
||||
pass
|
Loading…
Reference in a new issue