-- Some test code that tries to simulate important/interesting parts of mypy itself! [case testSimulateMypy] from mypy_extensions import trait from typing import List, TypeVar, cast, Generic from abc import abstractmethod import other_strconv as strconv #from other_visitor import ExpressionVisitor, StatementVisitor, NodeVisitor import other_visitor as visitor T = TypeVar('T') ############ nodes.py class Context: def __init__(self) -> None: self.line = -1 def set_line(self, line: int) -> None: self.line = line class Node(Context): def accept(self, visitor: visitor.NodeVisitor[T]) -> T: return cast(T, None) def to_str(self) -> str: return self.accept(strconv.StrConv()) @trait class Statement(Node): def accept(self, visitor: visitor.StatementVisitor[T]) -> T: return cast(T, None) @trait class Expression(Node): def accept(self, visitor: visitor.ExpressionVisitor[T]) -> T: return cast(T, None) @trait class SymbolNode(Node): """Nodes that can be stored in a symbol table.""" @abstractmethod def name(self) -> str: return cast(str, None) class FuncBase(Node): def __init__(self) -> None: super().__init__() self.is_static = False class Block(Statement): def __init__(self, stmts: List[Statement]) -> None: self.stmts = stmts def accept(self, visitor: visitor.StatementVisitor[T]) -> T: return visitor.visit_block(self) class ExprStmt(Statement): def __init__(self, expr: Expression) -> None: self.expr = expr def accept(self, visitor: visitor.StatementVisitor[T]) -> T: return visitor.visit_expr_stmt(self) class FuncItem(FuncBase): def __init__(self, body: Block) -> None: self.body = body class FuncDef(FuncItem, SymbolNode, Statement): def __init__(self, name: str, body: Block) -> None: super().__init__(body) self._name = name def accept(self, visitor: visitor.StatementVisitor[T]) -> T: return visitor.visit_func_def(self) def name(self) -> str: return self._name class LambdaExpr(FuncItem, Expression): def accept(self, visitor: visitor.ExpressionVisitor[T]) -> T: return visitor.visit_lambda_expr(self) def lol(x: Statement) -> int: return x.line [file other_visitor.py] from mypy_extensions import trait from typing import TypeVar, cast, Generic from abc import abstractmethod import native as nodes T = TypeVar('T') @trait class ExpressionVisitor(Generic[T]): @abstractmethod def visit_lambda_expr(self, o: 'nodes.LambdaExpr') -> T: return cast(T, None) @trait class StatementVisitor(Generic[T]): @abstractmethod def visit_block(self, o: 'nodes.Block') -> T: return cast(T, None) @abstractmethod def visit_func_def(self, o: 'nodes.FuncDef') -> T: return cast(T, None) @abstractmethod def visit_expr_stmt(self, o: 'nodes.ExprStmt') -> T: return cast(T, None) @trait class NodeVisitor(Generic[T], ExpressionVisitor[T], StatementVisitor[T]): pass [file other_strconv.py] from typing import List import native as nodes from other_visitor import NodeVisitor class StrConv(NodeVisitor[str]): def visit_block(self, b: nodes.Block) -> str: # we really need comprehensions! # TODO: PartialType unsupported things = [] # type: List[str] for s in b.stmts: things.append(s.accept(self)) return "{" + "; ".join(things) + "}" def visit_func_def(self, f: nodes.FuncDef) -> str: return "def " + f.name() + "(): " + f.body.accept(self) def visit_expr_stmt(self, e: nodes.ExprStmt) -> str: return e.expr.accept(self) def visit_lambda_expr(self, b: nodes.LambdaExpr) -> str: return "(fn: " + b.body.accept(self) + ")" [file driver.py] from native import * block = Block([Block([]), ExprStmt(LambdaExpr(Block([])))]) fn = FuncDef('test', block) assert fn.to_str() == "def test(): {{}; (fn: {})}"