forked from kanaka/mal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
haskell: make grammar readable as reference, misc
Split user functions and macros, merge user functions and core functions. Add a flag triggering debugging info in EVAL. Reserve mutable environments for REPL and let*. Move env type declaration from Types to Env. Check let* arguments only once. Share more code between map constructions and key type checks. Stop copying metadata when evaluating collections. The strict variant of Data.Map.Strict is recommended for general use. simplify printer.
- Loading branch information
1 parent
003947b
commit c9c504a
Showing
15 changed files
with
819 additions
and
732 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,60 @@ | ||
module Env | ||
( Env, env_new, env_bind, env_get, env_set ) | ||
( Env, env_apply, env_get, env_let, env_put, env_repl, env_set ) | ||
where | ||
|
||
import Data.IORef (modifyIORef, newIORef, readIORef) | ||
import qualified Data.Map as Map | ||
import Data.IORef (IORef, modifyIORef, newIORef, readIORef) | ||
import qualified Data.Map.Strict as Map | ||
|
||
import Printer (_pr_str) | ||
import Types | ||
|
||
-- The Env type si defined in Types module to avoid dep cycle. | ||
data Binds = Variable (IORef (Map.Map String MalVal)) | ||
| Constant (Map.Map String MalVal) | ||
|
||
env_new :: Env -> IO Env | ||
env_new outer = (: outer) <$> newIORef (Map.fromList []) | ||
type Env = [Binds] | ||
|
||
-- True means that the actual arguments match the signature. | ||
env_bind :: Env -> [String] -> [MalVal] -> IO Bool | ||
env_bind env (k : ks) (v : vs) | k /= "&" = do | ||
env_set env k v | ||
env_bind env ks vs | ||
env_bind env ["&", k] vs = do | ||
env_set env k $ toList vs | ||
return True | ||
env_bind _ [] [] = return True | ||
env_bind _ _ _ = return False | ||
env_repl :: IO Env | ||
env_repl = (: []) . Variable <$> newIORef Map.empty | ||
|
||
env_let :: Env -> IO Env | ||
env_let outer = (: outer) . Variable <$> newIORef Map.empty | ||
|
||
-- catch* should also use this | ||
env_apply :: Env -> [MalVal] -> [MalVal] -> Maybe (Env) | ||
env_apply outer keys values = (: outer) . Constant <$> bind keys values Map.empty | ||
|
||
bind :: [MalVal] -> [MalVal] -> Map.Map String MalVal -> Maybe (Map.Map String MalVal) | ||
bind [MalSymbol "&", (MalSymbol k)] vs m = Just $ Map.insert k (toList vs) m | ||
bind (MalSymbol k : ks) (v : vs) m = Map.insert k v <$> bind ks vs m | ||
bind [] [] m = Just m | ||
bind _ _ _ = Nothing | ||
|
||
env_get :: Env -> String -> IO (Maybe MalVal) | ||
env_get [] _ = return Nothing | ||
env_get (ref : outer) key = do | ||
hm <- readIORef ref | ||
case Map.lookup key hm of | ||
Nothing -> env_get outer key | ||
justVal -> return justVal | ||
env_get env key = loop env where | ||
loop :: Env -> IO (Maybe MalVal) | ||
loop [] = return Nothing | ||
loop (Constant m : outer) = case Map.lookup key m of | ||
Nothing -> loop outer | ||
justVal -> return justVal | ||
loop (Variable ref : outer) = do | ||
m <- readIORef ref | ||
case Map.lookup key m of | ||
Nothing -> loop outer | ||
justVal -> return justVal | ||
|
||
-- def! and let* | ||
env_set :: Env -> String -> MalVal -> IO () | ||
env_set (ref : _) key val = modifyIORef ref $ Map.insert key val | ||
env_set [] _ _ = error "assertion failed in env_set" | ||
env_set (Variable ref : _) key value = modifyIORef ref $ Map.insert key value | ||
env_set _ _ _ = error "assertion failed in env.env_set" | ||
|
||
put1 :: (String, MalVal) -> IO () | ||
put1 (key, value) = do | ||
putChar ' ' | ||
putStr key | ||
putChar ':' | ||
putStr =<< _pr_str True value | ||
|
||
env_put :: Env -> IO () | ||
env_put [] = error "assertion failed in Env.env_format" | ||
env_put (Variable ref : _) = mapM_ put1 =<< Map.assocs <$> readIORef ref | ||
env_put (Constant m : _) = mapM_ put1 $ Map.assocs m |
Oops, something went wrong.