expressions

This commit is contained in:
Oleg Sobolev 2025-12-30 01:27:01 +03:00
parent 75a33c2d94
commit f5e7b7c091
5 changed files with 95 additions and 21 deletions

View file

@ -1,9 +1,15 @@
module Lox.Expr (
Stmt (..),
Expr (..)
) where
import Lox.Scanner
data Stmt =
Expression Expr |
Print Expr
deriving Show
data Expr =
Literal Object |
Unary Token Expr |

View file

@ -1,30 +1,48 @@
module Lox.Interpreter (
runStatements,
eval
) where
import Lox.Expr
import Lox.Scanner
import Control.Monad.State
import Control.Monad
data InterpreterState = InterpreterState
data InterpreterState = InterpreterState (IO ())
emptyInterpreter :: InterpreterState
emptyInterpreter = InterpreterState (return ())
runStatements :: [Stmt] -> IO ()
runStatements s = io
where InterpreterState io = execState (interpret s) emptyInterpreter
interpret :: [Stmt] -> State InterpreterState ()
interpret = foldr ((>>) . execute) (return ())
execute :: Stmt -> State InterpreterState ()
execute (Print expr) = do
value <- evalFrom expr
modify (\(InterpreterState s) -> InterpreterState (s >> print value))
execute (Expression value) = void $ evalFrom value
eval :: Expr -> IO Object
eval expr = return $ evalState (interpret expr) InterpreterState
eval expr = return $ evalState (evalFrom expr) $ InterpreterState (return ())
interpret :: Expr -> State InterpreterState Object
interpret (Literal value) = return value
interpret (Grouping expr) = interpret expr
interpret (Unary op expr) = do
right <- interpret expr
evalFrom :: Expr -> State InterpreterState Object
evalFrom (Literal value) = return value
evalFrom (Grouping expr) = evalFrom expr
evalFrom (Unary op expr) = do
right <- evalFrom expr
case (tokenType op, right) of
(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"
interpret (Binary leftExpr op rightExpr) = do
left <- interpret leftExpr
right <- interpret rightExpr
evalFrom (Binary leftExpr op rightExpr) = do
left <- evalFrom leftExpr
right <- evalFrom rightExpr
case (tokenType op, left, right) of
(PLUS, NumberObject x, NumberObject y) -> return $ NumberObject (x + y)
(MINUS, NumberObject x, NumberObject y) -> return $ NumberObject (x - y)

View file

@ -10,7 +10,19 @@ import Lox.Expr
data ParserState = ParserState {tokens :: [Token]}
data ParserError = MismatchedParenthesesError | ExpectedExpressionError
data ParserError = MismatchedParenthesesError
| ExpectedExpressionError
| ExpectedSemicolonError
deriving Show
-- program → statement* EOF ;
--
-- statement → exprStmt
-- | printStmt ;
--
-- exprStmt → expression ";" ;
-- printStmt → "print" expression ";" ;
-- expression → equality ;
-- equality → comparison ( ( "!=" | "==" ) comparison )* ;
@ -22,8 +34,47 @@ data ParserError = MismatchedParenthesesError | ExpectedExpressionError
-- primary → NUMBER | STRING | "true" | "false" | "nil"
-- | "(" expression ")" ;
parse :: [Token] -> Either ParserError Expr
parse tokens = evalState expression (ParserState {tokens=tokens})
parse :: [Token] -> Either ParserError [Stmt]
parse tokens = evalState program (ParserState {tokens=tokens})
program :: State ParserState (Either ParserError [Stmt])
program = do
atEnd <- isAtEnd
if atEnd then return $ Right [] else do
headMaybe <- statement
case headMaybe of
Left err -> return $ Left err
Right head -> do
tailMaybe <- program
case tailMaybe of
Left err -> return $ Left err
Right tail -> return $ Right $ head : tail
statement :: State ParserState (Either ParserError Stmt)
statement = do
printMaybe <- matchToken [PRINT]
case printMaybe of
Just _ -> printStatement
_ -> expressionStatement
printStatement :: State ParserState (Either ParserError Stmt)
printStatement = do
valueMaybe <- expression
semicolonMaybe <- consume SEMICOLON ExpectedSemicolonError
case (valueMaybe, semicolonMaybe) of
(Left err, _) -> return $ Left err
(_, Left err) -> return $ Left err
(Right value, Right _) -> return $ Right $ Print value
expressionStatement :: State ParserState (Either ParserError Stmt)
expressionStatement = do
valueMaybe <- expression
semicolonMaybe <- consume SEMICOLON ExpectedSemicolonError
case (valueMaybe, semicolonMaybe) of
(Left err, _) -> return $ Left err
(_, Left err) -> return $ Left err
(Right value, Right _) -> return $ Right $ Expression value
expression :: State ParserState (Either ParserError Expr)
expression = equality

View file

@ -31,7 +31,7 @@ data Object = NullObject
instance Show Object where
show NullObject = "Nil"
show (StringObject s) = show s
show (StringObject s) = s
show (NumberObject x) = show x
show (BoolObject False) = "false"
show (BoolObject True) = "true"
@ -45,7 +45,7 @@ data Token = Token {
data ScannerState = ScannerState {source :: String, current :: String, lineNumber :: Int}
data ScannerError = UnexpectedCharacterError
data ScannerError = UnexpectedCharacterError deriving Show
emptyScannerState :: String -> ScannerState
emptyScannerState source =
@ -96,7 +96,7 @@ scanToken = do
' ' -> return nothing
'\r' -> return nothing
'\t' -> return nothing
'\n' -> return nothing
'\n' -> modify (\s@(ScannerState {lineNumber=n}) -> s {lineNumber=n+1}) >> return nothing
c -> if isDigit c then ok <$> scanNumber else if isAlpha c then ok <$> scanIdentifier else return $ Left UnexpectedCharacterError
scanString :: State ScannerState Token