expressions
This commit is contained in:
parent
75a33c2d94
commit
f5e7b7c091
5 changed files with 95 additions and 21 deletions
|
|
@ -9,13 +9,12 @@ run source = do
|
|||
case tokensMaybe of
|
||||
Left UnexpectedCharacterError -> putStrLn "Unexpected character"
|
||||
Right tokens -> do
|
||||
let exprMaybe = parse tokens
|
||||
case exprMaybe of
|
||||
let stmtMaybe = parse tokens
|
||||
case stmtMaybe of
|
||||
Left ExpectedExpressionError -> putStrLn "Expected expression"
|
||||
Left MismatchedParenthesesError -> putStrLn "Mismatched parentheses"
|
||||
Right expr -> do
|
||||
result <- eval expr
|
||||
print result
|
||||
Left ExpectedSemicolonError -> putStrLn "Expected semicolon"
|
||||
Right statements -> runStatements statements
|
||||
|
||||
main :: IO ()
|
||||
main = putStr ">> " >> hFlush stdout >> getLine >>= run
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue