This commit is contained in:
Anton Golov 2014-06-19 12:01:37 +00:00
commit 8e045c4806
2 changed files with 19 additions and 24 deletions

View File

@ -8,6 +8,8 @@ import qualified Data.Map as M
import qualified Data.ByteString.Char8 as BSC import qualified Data.ByteString.Char8 as BSC
import qualified Network.Socket as SO import qualified Network.Socket as SO
import Data.List (intercalate) import Data.List (intercalate)
import Control.Applicative ((<$>))
import Control.Monad (mplus)
import Control.Exception (try, SomeException) import Control.Exception (try, SomeException)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.State (StateT, runStateT, evalStateT, get, put) import Control.Monad.Trans.State (StateT, runStateT, evalStateT, get, put)
@ -59,11 +61,11 @@ unitv = TupleV []
-- look up a binding from the bottom up -- look up a binding from the bottom up
lookup :: Env -> String -> Maybe Value lookup :: Env -> String -> Maybe Value
lookup [] _ = Nothing lookup [] _ = Nothing
lookup (env:xs) name = maybe (lookup xs name) Just (M.lookup name env) lookup (env:xs) name = M.lookup name env `mplus` lookup xs name
-- bind in the local environment -- bind in the local environment
bind :: Env -> String -> Value -> Env bind :: Env -> String -> Value -> Env
bind (env:xs) name value = (M.insert name value env):xs bind (env:xs) name value = M.insert name value env : xs
instance Show Value where instance Show Value where
show (IntV i) = show i show (IntV i) = show i
@ -103,14 +105,10 @@ l ==$ r = BoolV (l == r)
l !=$ r = BoolV (l /= r) l !=$ r = BoolV (l /= r)
toDict :: M.Map String Value -> Value toDict :: M.Map String Value -> Value
toDict m = toDict = DictV . M.mapKeys StrV
let wrapped = map (\(k,v) -> (StrV k, v)) $ M.toAscList m in
DictV $ M.fromAscList wrapped
fromDict :: M.Map Value Value -> M.Map String Value fromDict :: M.Map Value Value -> M.Map String Value
fromDict m = fromDict = M.mapKeys (\(StrV s) -> s)
let unwrapped = map (\(StrV k,v) -> (k, v)) $ M.toAscList m in
M.fromAscList unwrapped
-- some built-in functions -- some built-in functions
@ -148,7 +146,7 @@ _fclose (StreamV handle) = do
liftIO $ hClose handle liftIO $ hClose handle
return unitv return unitv
_sockopen (TupleV [StrV host, IntV port]) = do _sockopen (TupleV [StrV host, IntV port]) =
liftIO $ SO.withSocketsDo $ do liftIO $ SO.withSocketsDo $ do
addr:_ <- SO.getAddrInfo Nothing (Just host) (Just $ show port) addr:_ <- SO.getAddrInfo Nothing (Just host) (Just $ show port)
sock <- SO.socket (SO.addrFamily addr) SO.Stream SO.defaultProtocol sock <- SO.socket (SO.addrFamily addr) SO.Stream SO.defaultProtocol
@ -171,9 +169,7 @@ _ref v = do
value <- liftIO $ newIORef v value <- liftIO $ newIORef v
return $ RefV value return $ RefV value
_readRef (RefV r) = do _readRef (RefV r) = liftIO $ readIORef r
value <- liftIO $ readIORef r
return value
_setRef (TupleV [RefV r, v]) = do _setRef (TupleV [RefV r, v]) = do
liftIO $ writeIORef r v liftIO $ writeIORef r v
@ -193,7 +189,7 @@ _eval (TupleV [StrV code, DictV env]) = do
case ret of case ret of
Left err -> return $ TupleV [StrV "err", StrV (show err)] Left err -> return $ TupleV [StrV "err", StrV (show err)]
Right v -> return v Right v -> return v
_eval (TupleV [code@(StrV _), (ListV env)]) = _eval (TupleV [code@(StrV _), ListV env]) =
let env' = map (\(TupleV [k,v]) -> (k,v)) env in let env' = map (\(TupleV [k,v]) -> (k,v)) env in
_eval (TupleV [code, DictV $ M.fromList env']) _eval (TupleV [code, DictV $ M.fromList env'])
_eval _ = error "eval: invalid args (want code and environment)" _eval _ = error "eval: invalid args (want code and environment)"
@ -284,8 +280,8 @@ eval (Cons a b) = do
ListV v' -> return $ ListV $ a':v' ListV v' -> return $ ListV $ a':v'
_ -> error "cons: RHS must be a list" _ -> error "cons: RHS must be a list"
eval (ListConst v) = mapM eval v >>= return . ListV eval (ListConst v) = ListV <$> mapM eval v
eval (TupleConst v) = mapM eval v >>= return . TupleV eval (TupleConst v) = TupleV <$> mapM eval v
eval (IfExpr c t e) = eval c >>= \cond -> eval (IfExpr c t e) = eval c >>= \cond ->
case cond of case cond of
@ -314,14 +310,13 @@ eval (Def pat v') = do
case patternBindings pat v of case patternBindings pat v of
Nothing -> error $ "pattern binding doesn't satisfy: " ++ show v ++ " with " ++ show pat Nothing -> error $ "pattern binding doesn't satisfy: " ++ show v ++ " with " ++ show pat
Just bindings -> do Just bindings -> do
put $ (M.union bindings locals):xs -- update our local bindings put $ M.union bindings locals : xs -- update our local bindings
return v return v
eval (Lambda pats) = do eval (Lambda pats) = do
env <- get env <- get
if length env == 1 then -- if in global env just use [], denoting the current global scope let env' = if length env == 1 then [] else env
return $ FnV [] pats return $ FnV env' pats
else return $ FnV env pats
eval (Add l r) = do { l <- eval l; r <- eval r; return $ l +$ r } eval (Add l r) = do { l <- eval l; r <- eval r; return $ l +$ r }
eval (Sub l r) = do { l <- eval l; r <- eval r; return $ l -$ r } eval (Sub l r) = do { l <- eval l; r <- eval r; return $ l -$ r }
@ -354,7 +349,7 @@ eval (Call lhs arg) = do
case v of case v of
fn@(FnV cls _) -> do fn@(FnV cls _) -> do
arg' <- eval arg arg' <- eval arg
let cls' = if cls == [] then [last env] else cls -- if [], use current global env let cls' = if null cls then [last env] else cls -- if [], use current global env
put cls' -- enter closure env put cls' -- enter closure env
v <- apply fn arg' v <- apply fn arg'
put env -- restore env put env -- restore env
@ -483,4 +478,4 @@ evalFile path = do
else evalString contents else evalString contents
evalFileV :: FilePath -> IO Value evalFileV :: FilePath -> IO Value
evalFileV = interpret . evalFile evalFileV = interpret . evalFile

View File

@ -6,7 +6,7 @@ import System.Environment (getArgs)
import System.Directory (doesFileExist) import System.Directory (doesFileExist)
import System.FilePath (FilePath, splitExtension) import System.FilePath (FilePath, splitExtension)
import Control.Applicative ((<$>)) import Control.Applicative ((<$>))
import Control.Monad (filterM) import Control.Monad (filterM, void)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Parser (parseProgram) import Parser (parseProgram)
import Interp (evalFileV, evalProgram, initIO, interpret, InterpState, Value) import Interp (evalFileV, evalProgram, initIO, interpret, InterpState, Value)
@ -23,7 +23,7 @@ repl = do
liftIO $ putStr ">> " liftIO $ putStr ">> "
line <- liftIO getLine line <- liftIO getLine
case parseProgram line of case parseProgram line of
Left err -> do Left err ->
liftIO $ putStrLn $ "parse error: " ++ show err liftIO $ putStrLn $ "parse error: " ++ show err
Right prg -> do Right prg -> do
ev <- evalProgram prg ev <- evalProgram prg
@ -31,7 +31,7 @@ repl = do
repl repl
repl' :: IO () repl' :: IO ()
repl' = interpret repl >> return () repl' = void $ interpret repl
main = do main = do
args <- getArgs args <- getArgs