all: added function definitions and calls
This commit is contained in:
@@ -16,6 +16,7 @@ eval state [x@(BNum _)] = (x, state)
|
|||||||
eval state [(BDef (BSym sym) expr)] =
|
eval state [(BDef (BSym sym) expr)] =
|
||||||
let (val, newstate) = eval state expr
|
let (val, newstate) = eval state expr
|
||||||
in (val, M.insert sym val newstate)
|
in (val, M.insert sym val newstate)
|
||||||
|
eval state [x@(BFun sym _ _)] = (BBool True, M.insert sym x state)
|
||||||
eval state [x@(BBool _)] = (x, state)
|
eval state [x@(BBool _)] = (x, state)
|
||||||
eval state [x@(BErr _)] = (x, state)
|
eval state [x@(BErr _)] = (x, state)
|
||||||
eval state [x@(BWhile cond body)] =
|
eval state [x@(BWhile cond body)] =
|
||||||
@@ -39,6 +40,11 @@ eval state [(BSym x)] =
|
|||||||
case M.lookup x state of
|
case M.lookup x state of
|
||||||
Just val -> (val, state)
|
Just val -> (val, state)
|
||||||
Nothing -> (BErr (x ++ " is undefined"), state)
|
Nothing -> (BErr (x ++ " is undefined"), state)
|
||||||
|
eval state [(BCall (BSym name) args)] =
|
||||||
|
case M.lookup name state of
|
||||||
|
Just val@(BFun _ _ _) -> funCall state val args
|
||||||
|
Nothing -> (BErr ("function " ++ name ++ " is undefined"), state)
|
||||||
|
_ -> (BErr (name ++ " is not a function"), state)
|
||||||
eval state [] = (BSym "", state)
|
eval state [] = (BSym "", state)
|
||||||
eval state l = (treeEval state l [] [], state)
|
eval state l = (treeEval state l [] [], state)
|
||||||
|
|
||||||
@@ -96,3 +102,21 @@ binOp (BSym "+") = Just (+)
|
|||||||
binOp (BSym "-") = Just ( - )
|
binOp (BSym "-") = Just ( - )
|
||||||
binOp (BSym "^") = Just (**)
|
binOp (BSym "^") = Just (**)
|
||||||
binOp _ = Nothing
|
binOp _ = Nothing
|
||||||
|
|
||||||
|
|
||||||
|
funCall :: State -> Value -> [[Value]] -> (Value, State)
|
||||||
|
funCall state (BFun name args body) provided =
|
||||||
|
if length args == length provided
|
||||||
|
then let
|
||||||
|
nstate = callWith state args provided
|
||||||
|
(val, _) = eval nstate body
|
||||||
|
in (val, state)
|
||||||
|
else
|
||||||
|
(BErr ("Expected " ++ show (length args) ++
|
||||||
|
" arguments in call to function " ++ name ++ ", got " ++
|
||||||
|
show (length provided)),
|
||||||
|
state)
|
||||||
|
where callWith state [] _ = state
|
||||||
|
callWith state (a:args) (p:provided) =
|
||||||
|
let (evald, nstate) = eval state p
|
||||||
|
in callWith (M.insert a evald nstate) args provided
|
||||||
|
@@ -6,6 +6,13 @@ import qualified Text.ParserCombinators.Parsec as P
|
|||||||
|
|
||||||
import BC.Types
|
import BC.Types
|
||||||
|
|
||||||
|
keywords = ["define", "if", "else", "while"]
|
||||||
|
|
||||||
|
|
||||||
|
optspace :: P.Parser (Maybe ())
|
||||||
|
optspace = P.optionMaybe P.spaces
|
||||||
|
|
||||||
|
|
||||||
symchar :: P.Parser Char
|
symchar :: P.Parser Char
|
||||||
symchar = P.oneOf "!%&|*+-/<=>^~"
|
symchar = P.oneOf "!%&|*+-/<=>^~"
|
||||||
|
|
||||||
@@ -14,6 +21,13 @@ number :: P.Parser Value
|
|||||||
number = P.try float P.<|> integer
|
number = P.try float P.<|> integer
|
||||||
|
|
||||||
|
|
||||||
|
commasep parser = P.sepBy parser sep
|
||||||
|
where sep = do _ <- optspace
|
||||||
|
str <- P.string ","
|
||||||
|
_ <- optspace
|
||||||
|
return $ str
|
||||||
|
|
||||||
|
|
||||||
float :: P.Parser Value
|
float :: P.Parser Value
|
||||||
float = do
|
float = do
|
||||||
neg <- P.optionMaybe (P.string "-")
|
neg <- P.optionMaybe (P.string "-")
|
||||||
@@ -47,15 +61,19 @@ bool = P.try parseTrue P.<|> parseFalse
|
|||||||
symbol :: P.Parser Value
|
symbol :: P.Parser Value
|
||||||
symbol = do
|
symbol = do
|
||||||
res <- P.many1 $ P.letter P.<|> symchar
|
res <- P.many1 $ P.letter P.<|> symchar
|
||||||
return $ BSym res
|
if contains keywords res
|
||||||
|
then P.unexpected res
|
||||||
|
else return $ BSym res
|
||||||
|
where contains [] _ = False
|
||||||
|
contains (x:xy) y = if x == y then True else contains xy y
|
||||||
|
|
||||||
|
|
||||||
block :: P.Parser [Value]
|
block :: P.Parser [Value]
|
||||||
block = do
|
block = do
|
||||||
_ <- P.string "{"
|
_ <- P.string "{"
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
body <- P.sepBy expr P.spaces
|
body <- P.sepBy expr P.spaces
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
_ <- P.string "}"
|
_ <- P.string "}"
|
||||||
return $ body
|
return $ body
|
||||||
|
|
||||||
@@ -64,19 +82,19 @@ block = do
|
|||||||
parseIf :: P.Parser Value
|
parseIf :: P.Parser Value
|
||||||
parseIf = do
|
parseIf = do
|
||||||
_ <- P.string "if"
|
_ <- P.string "if"
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
_ <- P.string "("
|
_ <- P.string "("
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
cond <- P.sepBy expr P.spaces
|
cond <- P.sepBy expr P.spaces
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
_ <- P.string ")"
|
_ <- P.string ")"
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
body <- block
|
body <- block
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
alt <- P.optionMaybe (P.string "else")
|
alt <- P.optionMaybe (P.string "else")
|
||||||
case alt of
|
case alt of
|
||||||
Just _ -> do
|
Just _ -> do
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
altbody <- block
|
altbody <- block
|
||||||
return $ BIf cond body (Just altbody)
|
return $ BIf cond body (Just altbody)
|
||||||
Nothing -> return $ BIf cond body Nothing
|
Nothing -> return $ BIf cond body Nothing
|
||||||
@@ -85,15 +103,15 @@ parseIf = do
|
|||||||
while :: P.Parser Value
|
while :: P.Parser Value
|
||||||
while = do
|
while = do
|
||||||
_ <- P.string "while"
|
_ <- P.string "while"
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
_ <- P.string "("
|
_ <- P.string "("
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
cond <- P.sepBy expr P.spaces
|
cond <- P.sepBy expr P.spaces
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
_ <- P.string ")"
|
_ <- P.string ")"
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
body <- block
|
body <- block
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
return $ BWhile cond body
|
return $ BWhile cond body
|
||||||
|
|
||||||
|
|
||||||
@@ -102,25 +120,56 @@ def = do
|
|||||||
sym <- symbol
|
sym <- symbol
|
||||||
_ <- P.spaces
|
_ <- P.spaces
|
||||||
_ <- P.string "="
|
_ <- P.string "="
|
||||||
_ <- P.optionMaybe P.spaces
|
_ <- optspace
|
||||||
expr <- P.sepBy expr P.spaces
|
expr <- P.sepBy expr P.spaces
|
||||||
return $ BDef sym expr
|
return $ BDef sym expr
|
||||||
|
|
||||||
|
|
||||||
|
fun :: P.Parser Value
|
||||||
|
fun = do
|
||||||
|
_ <- P.string "define"
|
||||||
|
_ <- P.spaces
|
||||||
|
name <- P.many1 $ P.letter P.<|> symchar
|
||||||
|
_ <- optspace
|
||||||
|
_ <- P.string "("
|
||||||
|
_ <- optspace
|
||||||
|
args <- commasep (P.many1 $ P.letter P.<|> symchar)
|
||||||
|
_ <- optspace
|
||||||
|
_ <- P.string ")"
|
||||||
|
_ <- optspace
|
||||||
|
body <- block
|
||||||
|
_ <- optspace
|
||||||
|
return $ BFun name args body
|
||||||
|
|
||||||
|
|
||||||
|
call :: P.Parser Value
|
||||||
|
call = do
|
||||||
|
name <- symbol
|
||||||
|
_ <- P.string "("
|
||||||
|
_ <- optspace
|
||||||
|
args <- commasep parser
|
||||||
|
_ <- optspace
|
||||||
|
_ <- P.string ")"
|
||||||
|
return $ BCall name args
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
expr :: P.Parser Value
|
expr :: P.Parser Value
|
||||||
expr = P.try bool
|
expr = P.try bool
|
||||||
P.<|> P.try def
|
P.<|> P.try def
|
||||||
P.<|> P.try while
|
P.<|> P.try while
|
||||||
P.<|> P.try parseIf
|
P.<|> P.try parseIf
|
||||||
|
P.<|> P.try fun
|
||||||
|
P.<|> P.try call
|
||||||
P.<|> P.try number
|
P.<|> P.try number
|
||||||
P.<|> symbol
|
P.<|> symbol
|
||||||
|
|
||||||
|
|
||||||
parser :: P.Parser [Value]
|
parser :: P.Parser [Value]
|
||||||
parser = (P.sepBy expr P.spaces) <* P.eof
|
parser = (P.sepBy expr P.spaces)
|
||||||
|
|
||||||
parse :: String -> [Value]
|
parse :: String -> [Value]
|
||||||
parse input = case P.parse parser (trim input) (trim input) of
|
parse input = case P.parse (parser <* P.eof) (trim input) (trim input) of
|
||||||
Left err -> [BErr $ show err]
|
Left err -> [BErr $ show err]
|
||||||
Right val -> val
|
Right val -> val
|
||||||
where trim s = trimR "" $ dropWhile isSpace s
|
where trim s = trimR "" $ dropWhile isSpace s
|
||||||
|
@@ -44,7 +44,14 @@ printStatus state str =
|
|||||||
in putStr (str ++ repeat '\b' (length str - 9))
|
in putStr (str ++ repeat '\b' (length str - 9))
|
||||||
where repeat str 0 = ""
|
where repeat str 0 = ""
|
||||||
repeat str n = (str:repeat str (n-1))
|
repeat str n = (str:repeat str (n-1))
|
||||||
trunc s = if length s > 20 then take 20 s ++ "..." else s
|
contains c [] = False
|
||||||
|
contains c (s:xs) = if c == s then True else contains c xs
|
||||||
|
trunc s =
|
||||||
|
let tr = truncLen s
|
||||||
|
in if contains '\n' tr
|
||||||
|
then takeWhile (\x -> x /= '\n') tr ++ "..."
|
||||||
|
else tr
|
||||||
|
truncLen s = if length s > 20 then take 20 s ++ "..." else s
|
||||||
|
|
||||||
|
|
||||||
cleanPrompt :: IO ()
|
cleanPrompt :: IO ()
|
||||||
|
@@ -8,20 +8,27 @@ data Value = BNum Number
|
|||||||
| BIf [Value] [Value] (Maybe [Value])
|
| BIf [Value] [Value] (Maybe [Value])
|
||||||
| BWhile [Value] [Value]
|
| BWhile [Value] [Value]
|
||||||
| BDef Value [Value]
|
| BDef Value [Value]
|
||||||
|
| BFun String [String] [Value]
|
||||||
|
| BCall Value [[Value]]
|
||||||
| BErr String
|
| BErr String
|
||||||
instance Show Value where
|
instance Show Value where
|
||||||
show (BBool b) = if b then "true" else "false"
|
show (BBool b) = if b then "true" else "false"
|
||||||
show (BDef sym expr) = show sym ++ " = " ++ unwords (map show expr)
|
show (BDef sym expr) = show sym ++ " = " ++ unwords (map show expr)
|
||||||
show (BIf cond body alt) =
|
show (BIf cond body alt) =
|
||||||
"if (" ++ unwords (map show cond) ++ ") {\n\t" ++
|
"if (" ++ unwords (map show cond) ++ ") {\n " ++
|
||||||
intercalate "\n\t" (map show body) ++ "\n}" ++
|
unwords (map show body) ++ "\n}" ++
|
||||||
(case alt of
|
(case alt of
|
||||||
Just vals ->
|
Just vals ->
|
||||||
" else {\n\t" ++ intercalate "\n\t" (map show vals) ++ "\n}"
|
" else {\n " ++ unwords (map show vals) ++ "\n}"
|
||||||
Nothing -> "")
|
Nothing -> "")
|
||||||
show (BWhile cond body) =
|
show (BWhile cond body) =
|
||||||
"while (" ++ unwords (map show cond) ++ ") {\n\t" ++
|
"while (" ++ unwords (map show cond) ++ ") {\n " ++
|
||||||
intercalate "\n\t" (map show body) ++ "\n}"
|
unwords (map show body) ++ "\n}"
|
||||||
|
show (BFun name args body) =
|
||||||
|
"define " ++ name ++ "(" ++ intercalate ", " args ++ ") {\n " ++
|
||||||
|
unwords (map show body) ++ "\n}"
|
||||||
|
show (BCall name args) =
|
||||||
|
show name ++ "(" ++ intercalate ", " (map show args) ++ ")"
|
||||||
show (BSym o) = o
|
show (BSym o) = o
|
||||||
show (BNum n) = show n
|
show (BNum n) = show n
|
||||||
show (BErr e) = "error: " ++ e
|
show (BErr e) = "error: " ++ e
|
||||||
|
Reference in New Issue
Block a user