Now works as a simple calculator of s-exprs, with + - * / and numbers
This commit is contained in:
parent
a00e5b46be
commit
a02176ee18
|
@ -17,4 +17,10 @@ executable picolisp
|
|||
hs-source-dirs: src
|
||||
main-is: Main.hs
|
||||
default-language: Haskell2010
|
||||
build-depends: base >= 4.7 && < 5
|
||||
other-modules: Parser,
|
||||
Evaluator,
|
||||
Expression,
|
||||
Primitives
|
||||
build-depends: base >= 4.7 && < 5,
|
||||
parsec,
|
||||
haskeline
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
module Evaluator where
|
||||
|
||||
import Expression
|
||||
import Primitives
|
||||
|
||||
eval :: Expression -> Expression
|
||||
eval n@(Number _) = n
|
||||
eval s@(Symbol _) = s
|
||||
eval (SExpr es) = apply $ SExpr (map eval es)
|
||||
|
||||
apply :: Expression -> Expression
|
||||
apply (SExpr (f:args)) = case f of
|
||||
Symbol "+" -> pAdd args
|
||||
Symbol "-" -> pSub args
|
||||
Symbol "*" -> pMul args
|
||||
Symbol "/" -> pDiv args
|
||||
Symbol _ -> error "no primitive functions not supported"
|
||||
_ -> error "object not applicable"
|
||||
apply _ = error "Object not applicable"
|
|
@ -0,0 +1,14 @@
|
|||
module Expression where
|
||||
|
||||
-- The basic unit of the language are Expressions, so we make an
|
||||
-- Expression data with the primitive expression values as the
|
||||
-- constructors
|
||||
data Expression = Number Double
|
||||
| Symbol String
|
||||
| SExpr [Expression]
|
||||
deriving (Eq)
|
||||
|
||||
instance Show Expression where
|
||||
show (Number n) = show n
|
||||
show (Symbol s) = show s
|
||||
show (SExpr es) = "(" ++ unwords (map show es) ++ ")"
|
20
src/Main.hs
20
src/Main.hs
|
@ -1,5 +1,21 @@
|
|||
module Main where
|
||||
|
||||
import Parser
|
||||
import Evaluator
|
||||
import System.Console.Haskeline
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
putStrLn "hello world"
|
||||
main = runInputT defaultSettings repl
|
||||
where repl = do
|
||||
line <- getInputLine "picolisp> "
|
||||
case line of
|
||||
Nothing -> return ()
|
||||
Just s -> do
|
||||
let eithE = parseExpression s
|
||||
case eithE of
|
||||
Left err -> do
|
||||
outputStrLn $ show err
|
||||
repl
|
||||
Right e -> do
|
||||
outputStrLn . show $ eval e
|
||||
repl
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
module Parser where
|
||||
|
||||
import Text.ParserCombinators.Parsec
|
||||
import Data.Char
|
||||
|
||||
import Expression
|
||||
|
||||
-- Receives a string, parses it, and returns an expression
|
||||
parseExpression :: String -> Either ParseError Expression
|
||||
parseExpression s = do
|
||||
e <- parse anyExpressionParser "" s
|
||||
return e
|
||||
|
||||
-- Parser any possible expression
|
||||
anyExpressionParser :: GenParser Char st Expression
|
||||
anyExpressionParser = numberParser <|> symbolParser <|> sexprParser
|
||||
|
||||
-- Parses an S-expr
|
||||
sexprParser :: GenParser Char st Expression
|
||||
sexprParser = do
|
||||
_ <- spaces
|
||||
_ <- char '('
|
||||
es <- many1 (try $ spaces >> anyExpressionParser)
|
||||
_ <- spaces
|
||||
_ <- char ')' >> spaces
|
||||
return $ SExpr es
|
||||
|
||||
-- Parses a symbol
|
||||
symbolParser :: GenParser Char st Expression
|
||||
symbolParser = Symbol <$> do
|
||||
c <- symbolChar
|
||||
cs <- many (symbolChar <|> digit)
|
||||
return $ c:cs
|
||||
where symbolChar = letter <|> oneOf "!#$%&*+-/:<=>?@\\^_`~"
|
||||
|
||||
-- Parses a number
|
||||
numberParser :: GenParser Char st Expression
|
||||
numberParser = do
|
||||
num <- read <$> many1 digit
|
||||
return $ Number num
|
|
@ -0,0 +1,10 @@
|
|||
module Primitives where
|
||||
|
||||
import Expression
|
||||
|
||||
pAdd, pSub, pMul, pDiv :: [Expression] -> Expression
|
||||
|
||||
pAdd = foldr1 $ \(Number a) (Number b) -> Number (a+b)
|
||||
pSub = foldr1 $ \(Number a) (Number b) -> Number (a-b)
|
||||
pMul = foldr1 $ \(Number a) (Number b) -> Number (a*b)
|
||||
pDiv = foldr1 $ \(Number a) (Number b) -> Number (a/b)
|
Loading…
Reference in New Issue