2025-12-25 18:41:04 +03:00
|
|
|
module Lox.Interpreter (
|
2025-12-30 01:27:01 +03:00
|
|
|
runStatements,
|
2025-12-25 18:41:04 +03:00
|
|
|
eval
|
|
|
|
|
) where
|
|
|
|
|
|
|
|
|
|
import Lox.Expr
|
|
|
|
|
import Lox.Scanner
|
2025-12-30 02:56:06 +03:00
|
|
|
import Lox.Environment
|
2025-12-25 18:41:04 +03:00
|
|
|
import Control.Monad.State
|
2025-12-30 01:27:01 +03:00
|
|
|
import Control.Monad
|
2025-12-25 18:41:04 +03:00
|
|
|
|
2025-12-30 02:56:06 +03:00
|
|
|
data InterpreterState = InterpreterState {io :: IO (), environment :: Environment}
|
2025-12-30 01:27:01 +03:00
|
|
|
|
|
|
|
|
emptyInterpreter :: InterpreterState
|
2025-12-30 02:56:06 +03:00
|
|
|
emptyInterpreter = InterpreterState {io=return (), environment=emptyEnvironment}
|
2025-12-30 01:27:01 +03:00
|
|
|
|
|
|
|
|
runStatements :: [Stmt] -> IO ()
|
|
|
|
|
runStatements s = io
|
2025-12-30 02:56:06 +03:00
|
|
|
where InterpreterState {io=io} = execState (interpret s) emptyInterpreter
|
2025-12-30 01:27:01 +03:00
|
|
|
|
|
|
|
|
interpret :: [Stmt] -> State InterpreterState ()
|
|
|
|
|
interpret = foldr ((>>) . execute) (return ())
|
|
|
|
|
|
|
|
|
|
execute :: Stmt -> State InterpreterState ()
|
2025-12-30 02:56:06 +03:00
|
|
|
execute (PrintStmt expr) = do
|
2025-12-30 01:27:01 +03:00
|
|
|
value <- evalFrom expr
|
2025-12-30 02:56:06 +03:00
|
|
|
modify (\s@(InterpreterState {io=io}) -> s {io=io >> print value})
|
|
|
|
|
execute (ExpressionStmt value) = void $ evalFrom value
|
|
|
|
|
execute (VariableStmt name expr) = do
|
|
|
|
|
value <- evalFrom expr
|
|
|
|
|
modify (\s@(InterpreterState {environment=env}) -> s {environment=define (tokenLexeme name) value env})
|
2025-12-25 18:41:04 +03:00
|
|
|
|
2025-12-29 23:57:15 +03:00
|
|
|
eval :: Expr -> IO Object
|
2025-12-30 02:56:06 +03:00
|
|
|
eval expr = return $ evalState (evalFrom expr) emptyInterpreter
|
2025-12-25 18:41:04 +03:00
|
|
|
|
2025-12-30 01:27:01 +03:00
|
|
|
evalFrom :: Expr -> State InterpreterState Object
|
2025-12-30 02:56:06 +03:00
|
|
|
evalFrom (LiteralExpr value) = return value
|
|
|
|
|
evalFrom (VariableExpr name) = do
|
|
|
|
|
maybeObject <- gets (\(InterpreterState {environment=env}) -> Lox.Environment.get (tokenLexeme name) env)
|
|
|
|
|
case maybeObject of
|
|
|
|
|
Nothing -> error "Undefined variable"
|
|
|
|
|
Just object -> return object
|
|
|
|
|
evalFrom (AssignmentExpr name expr) = do
|
|
|
|
|
value <- evalFrom expr
|
|
|
|
|
success <- state $ f value
|
|
|
|
|
if success then return value else error "Undefined variable"
|
|
|
|
|
where f value s@InterpreterState {environment=env} = let (success, newEnv) = assign (tokenLexeme name) value env in (success, s {environment=newEnv})
|
|
|
|
|
|
|
|
|
|
evalFrom (GroupingExpr expr) = evalFrom expr
|
|
|
|
|
evalFrom (UnaryExpr op expr) = do
|
2025-12-30 01:27:01 +03:00
|
|
|
right <- evalFrom expr
|
2025-12-25 18:48:12 +03:00
|
|
|
case (tokenType op, right) of
|
2025-12-25 18:41:04 +03:00
|
|
|
(MINUS, NumberObject x) -> return $ NumberObject (-x)
|
|
|
|
|
(BANG, NullObject) -> return $ BoolObject False
|
|
|
|
|
(BANG, BoolObject x) -> return $ BoolObject (not x)
|
|
|
|
|
(BANG, _) -> return $ BoolObject True
|
|
|
|
|
_ -> error "Type error"
|
2025-12-30 02:56:06 +03:00
|
|
|
evalFrom (BinaryExpr leftExpr op rightExpr) = do
|
2025-12-30 01:27:01 +03:00
|
|
|
left <- evalFrom leftExpr
|
|
|
|
|
right <- evalFrom rightExpr
|
2025-12-25 18:48:12 +03:00
|
|
|
case (tokenType op, left, right) of
|
2025-12-25 18:41:04 +03:00
|
|
|
(PLUS, NumberObject x, NumberObject y) -> return $ NumberObject (x + y)
|
|
|
|
|
(MINUS, NumberObject x, NumberObject y) -> return $ NumberObject (x - y)
|
|
|
|
|
(SLASH, NumberObject x, NumberObject y) -> return $ NumberObject (x / y)
|
|
|
|
|
(STAR, NumberObject x, NumberObject y) -> return $ NumberObject (x * y)
|
|
|
|
|
|
|
|
|
|
(GREATER, NumberObject x, NumberObject y) -> return $ BoolObject (x > y)
|
|
|
|
|
(GREATER_EQUAL, NumberObject x, NumberObject y) -> return $ BoolObject (x >= y)
|
|
|
|
|
(LESS, NumberObject x, NumberObject y) -> return $ BoolObject (x < y)
|
|
|
|
|
(LESS_EQUAL, NumberObject x, NumberObject y) -> return $ BoolObject (x <= y)
|
|
|
|
|
|
|
|
|
|
(PLUS, StringObject s, StringObject t) -> return $ StringObject (s ++ t)
|
|
|
|
|
|
|
|
|
|
(EQUAL_EQUAL, x, y) -> return $ BoolObject (x == y)
|
|
|
|
|
|
|
|
|
|
_ -> error "Type error"
|
|
|
|
|
|