feat: add logical expressions
This commit is contained in:
2
examples/09_logical.peb
Normal file
2
examples/09_logical.peb
Normal file
@@ -0,0 +1,2 @@
|
||||
print("hi" or 2) // "hi".
|
||||
print(null or "yes") // "yes".
|
||||
2
main.py
2
main.py
@@ -13,7 +13,7 @@ def main():
|
||||
123
|
||||
"This is
|
||||
another string" """
|
||||
path: str = "examples/04_if_else.peb"
|
||||
path: str = "examples/09_logical.peb"
|
||||
with open(path, "r") as f:
|
||||
source = f.read()
|
||||
lexer: Lexer = Lexer()
|
||||
|
||||
@@ -41,6 +41,10 @@ class Expr(ABC):
|
||||
def visit_variable_expr(self, expr: VariableExpr) -> T:
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def visit_logical_expr(self, expr: LogicalExpr) -> T:
|
||||
...
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AssignExpr(Expr):
|
||||
@@ -92,3 +96,13 @@ class VariableExpr(Expr):
|
||||
|
||||
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||
return visitor.visit_variable_expr(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LogicalExpr(Expr):
|
||||
left: Expr
|
||||
operator: Token
|
||||
right: Expr
|
||||
|
||||
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||
return visitor.visit_logical_expr(self)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr
|
||||
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr
|
||||
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt
|
||||
from src.interpreter.environment import Environment
|
||||
from src.interpreter.error import PebbleRuntimeError
|
||||
@@ -40,6 +40,21 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
|
||||
self.env.assign(expr.name, value)
|
||||
return value
|
||||
|
||||
def visit_logical_expr(self, expr: LogicalExpr) -> Any:
|
||||
left: Any = self.evaluate(expr.left)
|
||||
|
||||
match expr.operator.type:
|
||||
case TokenType.OR:
|
||||
if self.is_truthy(left):
|
||||
return left
|
||||
case TokenType.AND:
|
||||
if not self.is_truthy(left):
|
||||
return left
|
||||
case _:
|
||||
# Unreachable
|
||||
raise PebbleRuntimeError(expr.operator, f"Unknown logical operator")
|
||||
return self.evaluate(expr.right)
|
||||
|
||||
def visit_binary_expr(self, expr: BinaryExpr) -> Any:
|
||||
left: Any = self.evaluate(expr.left)
|
||||
right: Any = self.evaluate(expr.right)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr
|
||||
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr
|
||||
from src.ast.stmt import Stmt, PrintStmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt
|
||||
from src.parser.error import ParsingError
|
||||
from src.pebble import Pebble
|
||||
@@ -149,7 +149,7 @@ class Parser:
|
||||
return self.assignment()
|
||||
|
||||
def assignment(self) -> Expr:
|
||||
expr: Expr = self.equality()
|
||||
expr: Expr = self.or_()
|
||||
if self.match(TokenType.EQUAL, TokenType.PLUS_EQUAL, TokenType.MINUS_EQUAL, TokenType.STAR_EQUAL, TokenType.SLASH_EQUAL):
|
||||
operator: Token = self.previous()
|
||||
value: Expr = self.assignment()
|
||||
@@ -169,6 +169,22 @@ class Parser:
|
||||
self.error(operator, "Invalid assignment target.")
|
||||
return expr
|
||||
|
||||
def or_(self) -> Expr:
|
||||
expr: Expr = self.and_()
|
||||
while self.match(TokenType.OR):
|
||||
operator: Token = self.previous()
|
||||
right: Expr = self.and_()
|
||||
expr = LogicalExpr(expr, operator, right)
|
||||
return expr
|
||||
|
||||
def and_(self) -> Expr:
|
||||
expr: Expr = self.equality()
|
||||
while self.match(TokenType.AND):
|
||||
operator: Token = self.previous()
|
||||
right: Expr = self.equality()
|
||||
expr = LogicalExpr(expr, operator, right)
|
||||
return expr
|
||||
|
||||
def equality(self) -> Expr:
|
||||
expr: Expr = self.comparison()
|
||||
while self.match(TokenType.BANG_EQUAL, TokenType.EQUAL_EQUAL):
|
||||
|
||||
Reference in New Issue
Block a user