move Handles from state to values

This commit is contained in:
darkf 2014-02-12 01:33:50 -08:00
parent 13b1671662
commit d180116931
1 changed files with 43 additions and 61 deletions

104
Interp.hs
View File

@ -28,7 +28,7 @@ instance Ord BIF where compare a b = if a == b then EQ else LT
data Value = IntV Integer data Value = IntV Integer
| StrV String | StrV String
| BoolV Bool | BoolV Bool
| StreamV Int | StreamV Handle
| TupleV [Value] | TupleV [Value]
| ListV [Value] | ListV [Value]
| DictV (M.Map Value Value) | DictV (M.Map Value Value)
@ -42,14 +42,14 @@ instance Ord Value where
compare (BoolV a) (BoolV b) = compare a b compare (BoolV a) (BoolV b) = compare a b
compare (TupleV a) (TupleV b) = compare a b compare (TupleV a) (TupleV b) = compare a b
compare (ListV a) (ListV b) = compare a b compare (ListV a) (ListV b) = compare a b
compare (StreamV a) (StreamV b) = compare a b compare (StreamV a) (StreamV b) = if a == b then EQ else LT
compare (Builtin a) (Builtin b) = compare a b compare (Builtin a) (Builtin b) = compare a b
compare (FnV a b) (FnV x y) = if a == x && b == y then EQ else LT compare (FnV a b) (FnV x y) = if a == x && b == y then EQ else LT
compare (DictV a) (DictV b) = compare a b compare (DictV a) (DictV b) = compare a b
compare _ _ = error "compare: not valid" compare _ _ = error "compare: not valid"
type Env = [M.Map String Value] -- lexical environment (linked list) type Env = [M.Map String Value] -- lexical environment (linked list)
type InterpState = StateT ([Handle], Env) IO -- interpreter state (open handles, global env) type InterpState = StateT Env IO -- interpreter state (open handles, global env)
emptyEnv = [M.empty] emptyEnv = [M.empty]
unitv = TupleV [] unitv = TupleV []
@ -111,69 +111,52 @@ fromDict m =
-- some built-in functions -- some built-in functions
_fputbytes (TupleV [StreamV h, StrV str]) = do _fputbytes (TupleV [StreamV handle, StrV str]) = do
(handles,_) <- get
let handle = handles !! h
io <- liftIO $ hPutStr handle str io <- liftIO $ hPutStr handle str
return unitv return unitv
_fputstr (TupleV [StreamV h, StrV str]) = do _fputstr (TupleV [StreamV handle, StrV str]) = do
(handles,_) <- get
let handle = handles !! h
io <- liftIO $ hPutStr handle str io <- liftIO $ hPutStr handle str
return unitv return unitv
_fgetline (StreamV h) = do _fgetline (StreamV handle) = do
(handles,_) <- get
let handle = handles !! h
str <- liftIO $ hGetLine handle str <- liftIO $ hGetLine handle
if last str == '\r' then -- remove trailing CR if last str == '\r' then -- remove trailing CR
return . StrV $ init str return . StrV $ init str
else return $ StrV str else return $ StrV str
_freadbytes (TupleV [StreamV h, IntV n]) = do _freadbytes (TupleV [StreamV handle, IntV n]) = do
(handles,_) <- get
let handle = handles !! h
str <- liftIO $ BSC.hGet handle (fromIntegral n :: Int) str <- liftIO $ BSC.hGet handle (fromIntegral n :: Int)
return . StrV $ BSC.unpack str return . StrV $ BSC.unpack str
_fopen (TupleV [StrV path, StrV mode]) = do _fopen (TupleV [StrV path, StrV mode]) = do
(handles,env) <- get
let mode' = case mode of let mode' = case mode of
"r" -> ReadMode "r" -> ReadMode
"w" -> WriteMode "w" -> WriteMode
"rw" -> ReadWriteMode "rw" -> ReadWriteMode
handle <- liftIO $ openBinaryFile path mode' handle <- liftIO $ openBinaryFile path mode'
put (handles ++ [handle], env) return $ StreamV handle
return . StreamV $ length handles
_feof (StreamV h) = do _feof (StreamV handle) = do
(handles,_) <- get
let handle = handles !! h
isEof <- liftIO $ hIsEOF handle isEof <- liftIO $ hIsEOF handle
return $ BoolV isEof return $ BoolV isEof
_fclose handle@(StreamV h) = do _fclose (StreamV handle) = do
(handles,_) <- get
let handle = handles !! h
liftIO $ hClose handle liftIO $ hClose handle
return unitv return unitv
_sockopen (TupleV [StrV host, IntV port]) = do _sockopen (TupleV [StrV host, IntV port]) = do
(handles,env) <- get liftIO $ SO.withSocketsDo $ do
handle <- 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
SO.connect sock (SO.addrAddress addr) SO.connect sock (SO.addrAddress addr)
handle <- SO.socketToHandle sock ReadWriteMode handle <- SO.socketToHandle sock ReadWriteMode
hSetBuffering handle NoBuffering hSetBuffering handle NoBuffering
return handle return $ StreamV handle
put (handles ++ [handle], env)
return . StreamV $ length handles
_putstr str@(StrV _) = _fputstr $ TupleV [StreamV 0, str] _putstr str@(StrV _) = _fputstr $ TupleV [StreamV stdout, str]
_putbytes str@(StrV _) = _fputbytes $ TupleV [StreamV 0, str] _putbytes str@(StrV _) = _fputbytes $ TupleV [StreamV stdout, str]
_getline (TupleV []) = _fgetline (StreamV 1) _getline (TupleV []) = _fgetline (StreamV stdin)
_print v = _putbytes $ StrV $ show v ++ "\n" _print v = _putbytes $ StrV $ show v ++ "\n"
_repr v = return . StrV $ show v _repr v = return . StrV $ show v
@ -190,7 +173,7 @@ _loop args@(TupleV [fn@(FnV _ _), arg]) = do
_eval (TupleV [StrV code, DictV env]) = do _eval (TupleV [StrV code, DictV env]) = do
let trySome :: IO a -> IO (Either SomeException a) let trySome :: IO a -> IO (Either SomeException a)
trySome = try trySome = try
state = ([stdout, stdin], [fromDict env]) state = [fromDict env]
ret <- liftIO. trySome $ evalStateT (evalString code) state ret <- liftIO. trySome $ evalStateT (evalString code) state
case ret of case ret of
Left err -> return $ TupleV [StrV "err", StrV (show err)] Left err -> return $ TupleV [StrV "err", StrV (show err)]
@ -203,29 +186,29 @@ _eval _ = error "eval: invalid args (want code and environment)"
-- returns a dictionary of a new environment with only the standard -- returns a dictionary of a new environment with only the standard
-- default-imported functions -- default-imported functions
_newStdEnv (TupleV []) = do _newStdEnv (TupleV []) = do
let (_,[stdEnv]) = initialState let [stdEnv] = initialState
return $ toDict stdEnv return $ toDict stdEnv
_globals (TupleV []) = do _globals (TupleV []) = do
(_, env) <- get env <- get
return $ toDict (last env) return $ toDict (last env)
_locals (TupleV []) = do _locals (TupleV []) = do
(_, locals:_) <- get locals:_ <- get
return $ toDict locals return $ toDict locals
-- import a module name as a module -- import a module name as a module
_Import (StrV modname) = do _Import (StrV modname) = do
(h,env) <- get -- save current state env <- get -- save current state
put initialState put initialState
(path,modname) <- liftIO $ findModule modname -- find the module file (path,modname) <- liftIO $ findModule modname -- find the module file
evalFile path -- evaluate the module file evalFile path -- evaluate the module file
(_,[modenv]) <- get -- get the module env [modenv] <- get -- get the module env
let (_, [initialEnv]) = initialState let [initialEnv] = initialState
let modenv' = M.difference modenv initialEnv -- subtract prelude stuff let modenv' = M.difference modenv initialEnv -- subtract prelude stuff
let mod = toDict modenv' let mod = toDict modenv'
let env' = bind env modname mod -- bind it let env' = bind env modname mod -- bind it
put (h,env') -- restore state put env' -- restore state
return mod -- return module value return mod -- return module value
where where
@ -241,12 +224,11 @@ _Import (StrV modname) = do
if exists then return (path, takeBaseName path) if exists then return (path, takeBaseName path)
else findModuleIn xs else findModuleIn xs
initialState = ([stdout, stdin], initialState = ( [M.fromList [("id", FnV emptyEnv [(VarP "x", Var "x")]),
[M.fromList [("id", FnV emptyEnv [(VarP "x", Var "x")]),
("loop", Builtin $ BIF _loop), ("loop", Builtin $ BIF _loop),
("repr", Builtin $ BIF _repr), ("repr", Builtin $ BIF _repr),
("stdout", StreamV 0), ("stdout", StreamV stdout),
("stdin", StreamV 1), ("stdin", StreamV stdin),
("print", Builtin $ BIF _print), ("print", Builtin $ BIF _print),
("putstr", Builtin $ BIF _putstr), ("putstr", Builtin $ BIF _putstr),
("putstrln", Builtin $ BIF (\x -> _putstr $ x +$ StrV "\n")), ("putstrln", Builtin $ BIF (\x -> _putstr $ x +$ StrV "\n")),
@ -291,35 +273,35 @@ eval (IfExpr c t e) = eval c >>= \cond ->
BoolV False -> eval e BoolV False -> eval e
_ -> error "if: condition must be a boolean" _ -> error "if: condition must be a boolean"
eval (Var var) = get >>= \(_,env) -> eval (Var var) = get >>= \env ->
maybe (error $ "unbound variable " ++ var) return (lookup env var) maybe (error $ "unbound variable " ++ var) return (lookup env var)
eval (Defun name fn) = do eval (Defun name fn) = do
(s,env) <- get env <- get
case lookup env name of case lookup env name of
Nothing -> -- bind new fn Nothing -> -- bind new fn
eval fn >>= \fn' -> eval fn >>= \fn' ->
put (s, bind env name fn') >> return fn' put (bind env name fn') >> return fn'
Just oldfn -> -- add pattern to old fn Just oldfn -> -- add pattern to old fn
let FnV cls oldpats = oldfn let FnV cls oldpats = oldfn
Lambda [(pat, body)] = fn Lambda [(pat, body)] = fn
newfn = FnV cls (oldpats ++ [(pat, body)]) in newfn = FnV cls (oldpats ++ [(pat, body)]) in
put (s, bind env name newfn) >> return newfn put (bind env name newfn) >> return newfn
eval (Def pat v') = do eval (Def pat v') = do
v <- eval v' v <- eval v'
(s,locals:xs) <- get locals:xs <- get
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 -> Just bindings -> do
put (s, (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) = eval (Lambda pats) = do
get >>= \(_,env) -> env <- get
if length env == 1 then -- if in global env just use [], denoting the current global scope if length env == 1 then -- if in global env just use [], denoting the current global scope
return $ FnV [] pats return $ FnV [] pats
else 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 }
@ -347,15 +329,15 @@ eval (Access left (Var right)) = do
eval (Access _ _) = error "op/: RHS must be an identifier" eval (Access _ _) = error "op/: RHS must be an identifier"
eval (Call lhs arg) = do eval (Call lhs arg) = do
(h,env) <- get env <- get
v <- eval lhs v <- eval lhs
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 cls == [] then [last env] else cls -- if [], use current global env
put (h,cls') -- enter closure env put cls' -- enter closure env
v <- apply fn arg' v <- apply fn arg'
put (h,env) -- restore env put env -- restore env
return v return v
fn@(Builtin _) -> eval arg >>= apply fn fn@(Builtin _) -> eval arg >>= apply fn
_ -> error $ "call: " ++ show v ++ " is not a function" _ -> error $ "call: " ++ show v ++ " is not a function"
@ -434,9 +416,9 @@ apply (FnV _ pats) arg =
case patternBindings pat arg of case patternBindings pat arg of
Just bindings -> -- satisfies Just bindings -> -- satisfies
do do
(s,env) <- get env <- get
let newenv = bindings:env let newenv = bindings:env
put (s, newenv) put newenv
eval body eval body
Nothing -> -- doesn't satisfy this pattern Nothing -> -- doesn't satisfy this pattern
apply' xs apply' xs