refactor: implement print as a builtin function
This commit is contained in:
@@ -33,10 +33,6 @@ class Stmt(ABC):
|
|||||||
def visit_if_stmt(self, stmt: IfStmt) -> T:
|
def visit_if_stmt(self, stmt: IfStmt) -> T:
|
||||||
...
|
...
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def visit_print_stmt(self, stmt: PrintStmt) -> T:
|
|
||||||
...
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_return_stmt(self, stmt: ReturnStmt) -> T:
|
def visit_return_stmt(self, stmt: ReturnStmt) -> T:
|
||||||
...
|
...
|
||||||
@@ -98,14 +94,6 @@ class IfStmt(Stmt):
|
|||||||
return visitor.visit_if_stmt(self)
|
return visitor.visit_if_stmt(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class PrintStmt(Stmt):
|
|
||||||
expression: Expr
|
|
||||||
|
|
||||||
def accept(self, visitor: Stmt.Visitor[T]) -> T:
|
|
||||||
return visitor.visit_print_stmt(self)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ReturnStmt(Stmt):
|
class ReturnStmt(Stmt):
|
||||||
keyword: Token
|
keyword: Token
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import Any
|
|||||||
|
|
||||||
from src.ast.expr import Expr, VariableExpr, LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import Expr, VariableExpr, LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr
|
CallExpr
|
||||||
from src.ast.stmt import Stmt, LetStmt, PrintStmt, IfStmt, ExpressionStmt, BlockStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, LetStmt, IfStmt, ExpressionStmt, BlockStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt
|
ReturnStmt, BreakStmt, ContinueStmt
|
||||||
|
|
||||||
|
|
||||||
@@ -93,9 +93,6 @@ class Formatter(Expr.Visitor[str], Stmt.Visitor[str]):
|
|||||||
res += "\n"
|
res += "\n"
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def visit_print_stmt(self, stmt: PrintStmt) -> str:
|
|
||||||
return self.indented(f"print({self.format(stmt.expression)})\n")
|
|
||||||
|
|
||||||
def visit_return_stmt(self, stmt: ReturnStmt) -> str:
|
def visit_return_stmt(self, stmt: ReturnStmt) -> str:
|
||||||
res: str = self.indented("return")
|
res: str = self.indented("return")
|
||||||
if stmt.value is not None:
|
if stmt.value is not None:
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ from src.interpreter.environment import Environment
|
|||||||
class GlobalEnvironment(Environment):
|
class GlobalEnvironment(Environment):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self.define("print", make_builtin(lambda interpreter, args: print(*map(interpreter.stringify, args)), -1))
|
||||||
self.define("time", make_builtin(lambda interpreter, args: time.time()))
|
self.define("time", make_builtin(lambda interpreter, args: time.time()))
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import time
|
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr
|
CallExpr
|
||||||
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt
|
ReturnStmt, BreakStmt, ContinueStmt
|
||||||
from src.core.callable import PebbleCallable
|
from src.core.callable import PebbleCallable
|
||||||
from src.core.function import PebbleFunction
|
from src.core.function import PebbleFunction
|
||||||
@@ -138,8 +137,9 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
|
|||||||
if not isinstance(callee, PebbleCallable):
|
if not isinstance(callee, PebbleCallable):
|
||||||
raise PebbleRuntimeError(expr.paren, "Can only call functions and classes.")
|
raise PebbleRuntimeError(expr.paren, "Can only call functions and classes.")
|
||||||
function: PebbleCallable = callee
|
function: PebbleCallable = callee
|
||||||
if len(arguments) != function.arity():
|
arity: int = function.arity()
|
||||||
raise PebbleRuntimeError(expr.paren, f"Expected {function.arity()} arguments but got {len(arguments)}.")
|
if arity != -1 and len(arguments) != arity:
|
||||||
|
raise PebbleRuntimeError(expr.paren, f"Expected {arity} arguments but got {len(arguments)}.")
|
||||||
return function.call(self, arguments)
|
return function.call(self, arguments)
|
||||||
|
|
||||||
def visit_grouping_expr(self, expr: GroupingExpr) -> Any:
|
def visit_grouping_expr(self, expr: GroupingExpr) -> Any:
|
||||||
@@ -167,10 +167,6 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
|
|||||||
elif stmt.else_branch is not None:
|
elif stmt.else_branch is not None:
|
||||||
self.execute(stmt.else_branch)
|
self.execute(stmt.else_branch)
|
||||||
|
|
||||||
def visit_print_stmt(self, stmt: PrintStmt) -> None:
|
|
||||||
value: Any = self.evaluate(stmt.expression)
|
|
||||||
print(self.stringify(value))
|
|
||||||
|
|
||||||
def visit_return_stmt(self, stmt: ReturnStmt) -> None:
|
def visit_return_stmt(self, stmt: ReturnStmt) -> None:
|
||||||
value: Any = None
|
value: Any = None
|
||||||
if stmt.value is not None:
|
if stmt.value is not None:
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ from typing import TYPE_CHECKING
|
|||||||
|
|
||||||
from src.ast.expr import Expr, LogicalExpr, VariableExpr, LiteralExpr, GroupingExpr, CallExpr, UnaryExpr, BinaryExpr, \
|
from src.ast.expr import Expr, LogicalExpr, VariableExpr, LiteralExpr, GroupingExpr, CallExpr, UnaryExpr, BinaryExpr, \
|
||||||
AssignExpr
|
AssignExpr
|
||||||
from src.ast.stmt import Stmt, ForStmt, WhileStmt, LetStmt, ReturnStmt, PrintStmt, IfStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ForStmt, WhileStmt, LetStmt, ReturnStmt, IfStmt, FunctionStmt, \
|
||||||
ExpressionStmt, BlockStmt, BreakStmt, T, ContinueStmt
|
ExpressionStmt, BlockStmt, BreakStmt, ContinueStmt
|
||||||
from src.pebble import Pebble
|
from src.pebble import Pebble
|
||||||
from src.token import Token
|
from src.token import Token
|
||||||
|
|
||||||
@@ -121,9 +121,6 @@ class Resolver(Expr.Visitor[None], Stmt.Visitor[None]):
|
|||||||
if stmt.else_branch is not None:
|
if stmt.else_branch is not None:
|
||||||
self.resolve(stmt.else_branch)
|
self.resolve(stmt.else_branch)
|
||||||
|
|
||||||
def visit_print_stmt(self, stmt: PrintStmt) -> None:
|
|
||||||
self.resolve(stmt.expression)
|
|
||||||
|
|
||||||
def visit_return_stmt(self, stmt: ReturnStmt) -> None:
|
def visit_return_stmt(self, stmt: ReturnStmt) -> None:
|
||||||
if self.current_func == FunctionType.NONE:
|
if self.current_func == FunctionType.NONE:
|
||||||
Pebble.token_error(stmt.keyword, "Cannot return from top-level scope.")
|
Pebble.token_error(stmt.keyword, "Cannot return from top-level scope.")
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ KEYWORDS: dict[str, TokenType] = {
|
|||||||
"false": TokenType.FALSE,
|
"false": TokenType.FALSE,
|
||||||
"true": TokenType.TRUE,
|
"true": TokenType.TRUE,
|
||||||
"null": TokenType.NULL,
|
"null": TokenType.NULL,
|
||||||
"print": TokenType.PRINT,
|
|
||||||
"return": TokenType.RETURN,
|
"return": TokenType.RETURN,
|
||||||
"break": TokenType.BREAK,
|
"break": TokenType.BREAK,
|
||||||
"continue": TokenType.CONTINUE,
|
"continue": TokenType.CONTINUE,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from typing import Optional
|
|||||||
|
|
||||||
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr
|
CallExpr
|
||||||
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt
|
ReturnStmt, BreakStmt, ContinueStmt
|
||||||
from src.consts import MAX_FUNCTION_ARGS
|
from src.consts import MAX_FUNCTION_ARGS
|
||||||
from src.parser.error import ParsingError
|
from src.parser.error import ParsingError
|
||||||
@@ -16,7 +16,7 @@ class Parser:
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATEMENT_BOUNDARY: set[TokenType] = {
|
STATEMENT_BOUNDARY: set[TokenType] = {
|
||||||
TokenType.FOR, TokenType.WHILE, TokenType.IF, TokenType.PRINT
|
TokenType.FOR, TokenType.WHILE, TokenType.IF
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, tokens: list[Token]):
|
def __init__(self, tokens: list[Token]):
|
||||||
@@ -130,8 +130,6 @@ class Parser:
|
|||||||
return self.for_stmt()
|
return self.for_stmt()
|
||||||
if self.match(TokenType.IF):
|
if self.match(TokenType.IF):
|
||||||
return self.if_stmt()
|
return self.if_stmt()
|
||||||
if self.match(TokenType.PRINT):
|
|
||||||
return self.print_stmt()
|
|
||||||
if self.match(TokenType.RETURN):
|
if self.match(TokenType.RETURN):
|
||||||
return self.return_stmt()
|
return self.return_stmt()
|
||||||
if self.match(TokenType.BREAK):
|
if self.match(TokenType.BREAK):
|
||||||
@@ -207,13 +205,6 @@ class Parser:
|
|||||||
else_branch = self.statement()
|
else_branch = self.statement()
|
||||||
return IfStmt(condition, then_branch, else_branch)
|
return IfStmt(condition, then_branch, else_branch)
|
||||||
|
|
||||||
def print_stmt(self) -> Stmt:
|
|
||||||
self.consume(TokenType.LEFT_PAREN, "Missing parentheses")
|
|
||||||
value: Expr = self.expression()
|
|
||||||
self.consume(TokenType.RIGHT_PAREN, "Unclosed parenthesis")
|
|
||||||
self.expect_eol("Expected end of line after statement")
|
|
||||||
return PrintStmt(value)
|
|
||||||
|
|
||||||
def return_stmt(self) -> Stmt:
|
def return_stmt(self) -> Stmt:
|
||||||
keyword: Token = self.previous()
|
keyword: Token = self.previous()
|
||||||
value: Optional[Expr] = None
|
value: Optional[Expr] = None
|
||||||
@@ -257,7 +248,8 @@ class Parser:
|
|||||||
|
|
||||||
def assignment(self) -> Expr:
|
def assignment(self) -> Expr:
|
||||||
expr: Expr = self.or_()
|
expr: Expr = self.or_()
|
||||||
if self.match(TokenType.EQUAL, TokenType.PLUS_EQUAL, TokenType.MINUS_EQUAL, TokenType.STAR_EQUAL, TokenType.SLASH_EQUAL):
|
if self.match(TokenType.EQUAL, TokenType.PLUS_EQUAL, TokenType.MINUS_EQUAL, TokenType.STAR_EQUAL,
|
||||||
|
TokenType.SLASH_EQUAL):
|
||||||
operator: Token = self.previous()
|
operator: Token = self.previous()
|
||||||
value: Expr = self.assignment()
|
value: Expr = self.assignment()
|
||||||
if isinstance(expr, VariableExpr):
|
if isinstance(expr, VariableExpr):
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ class TokenType(Enum):
|
|||||||
CONTINUE = auto()
|
CONTINUE = auto()
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
PRINT = auto()
|
|
||||||
COMMENT = auto()
|
COMMENT = auto()
|
||||||
WHITESPACE = auto()
|
WHITESPACE = auto()
|
||||||
EOF = auto()
|
EOF = auto()
|
||||||
|
|||||||
Reference in New Issue
Block a user