2017-06-08 20:19:27 +03:00
|
|
|
module Eval exposing (..)
|
|
|
|
|
|
|
|
import Types exposing (..)
|
|
|
|
import IO exposing (IO)
|
2017-06-14 16:49:27 +03:00
|
|
|
import Env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-11 23:44:49 +03:00
|
|
|
apply : Eval a -> Env -> EvalContext a
|
2017-06-15 22:06:49 +03:00
|
|
|
apply f env =
|
|
|
|
f env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-11 23:44:49 +03:00
|
|
|
run : Env -> Eval a -> EvalContext a
|
2017-06-15 22:06:49 +03:00
|
|
|
run env e =
|
|
|
|
apply e env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-11 23:44:49 +03:00
|
|
|
withEnv : (Env -> Eval a) -> Eval a
|
2017-06-15 22:06:49 +03:00
|
|
|
withEnv f env =
|
|
|
|
apply (f env) env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-11 23:44:49 +03:00
|
|
|
setEnv : Env -> Eval ()
|
2017-06-15 22:06:49 +03:00
|
|
|
setEnv env _ =
|
|
|
|
apply (succeed ()) env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-11 23:44:49 +03:00
|
|
|
modifyEnv : (Env -> Env) -> Eval ()
|
2017-06-15 22:06:49 +03:00
|
|
|
modifyEnv f env =
|
|
|
|
apply (succeed ()) (f env)
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
succeed : a -> Eval a
|
2017-06-15 22:06:49 +03:00
|
|
|
succeed res env =
|
|
|
|
( env, EvalOk res )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
io : Cmd Msg -> (IO -> Eval a) -> Eval a
|
2017-06-15 22:06:49 +03:00
|
|
|
io cmd cont env =
|
|
|
|
( env, EvalIO cmd cont )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
map : (a -> b) -> Eval a -> Eval b
|
2017-06-15 22:06:49 +03:00
|
|
|
map f e env =
|
|
|
|
case apply e env of
|
|
|
|
( env, EvalOk res ) ->
|
|
|
|
( env, EvalOk (f res) )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
2017-06-15 22:06:49 +03:00
|
|
|
( env, EvalErr msg ) ->
|
|
|
|
( env, EvalErr msg )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
2017-06-15 22:06:49 +03:00
|
|
|
( env, EvalIO cmd cont ) ->
|
|
|
|
( env, EvalIO cmd (cont >> map f) )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
andThen : (a -> Eval b) -> Eval a -> Eval b
|
2017-06-15 22:06:49 +03:00
|
|
|
andThen f e env =
|
|
|
|
case apply e env of
|
|
|
|
( env, EvalOk res ) ->
|
|
|
|
apply (f res) env
|
2017-06-08 20:19:27 +03:00
|
|
|
|
2017-06-15 22:06:49 +03:00
|
|
|
( env, EvalErr msg ) ->
|
|
|
|
( env, EvalErr msg )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
2017-06-15 22:06:49 +03:00
|
|
|
( env, EvalIO cmd cont ) ->
|
|
|
|
( env, EvalIO cmd (cont >> andThen f) )
|
2017-06-08 20:19:27 +03:00
|
|
|
|
|
|
|
|
2017-06-20 18:23:00 +03:00
|
|
|
catchError : (String -> Eval a) -> Eval a -> Eval a
|
|
|
|
catchError f e env =
|
|
|
|
case apply e env of
|
|
|
|
( env, EvalOk res ) ->
|
|
|
|
( env, EvalOk res )
|
|
|
|
|
|
|
|
( env, EvalErr msg ) ->
|
|
|
|
apply (f msg) env
|
|
|
|
|
|
|
|
( env, EvalIO cmd cont ) ->
|
|
|
|
( env, EvalIO cmd (cont >> catchError f) )
|
|
|
|
|
|
|
|
|
2017-06-08 20:19:27 +03:00
|
|
|
fail : String -> Eval a
|
2017-06-15 22:06:49 +03:00
|
|
|
fail msg env =
|
|
|
|
( env, EvalErr msg )
|
2017-06-14 16:49:27 +03:00
|
|
|
|
|
|
|
|
|
|
|
enter : Int -> List ( String, MalExpr ) -> Eval a -> Eval a
|
|
|
|
enter frameId bound body =
|
|
|
|
withEnv
|
|
|
|
(\env ->
|
|
|
|
modifyEnv (Env.enter frameId bound)
|
2017-06-15 22:06:49 +03:00
|
|
|
|> andThen (always body)
|
2017-06-14 16:49:27 +03:00
|
|
|
|> andThen
|
|
|
|
(\res ->
|
|
|
|
modifyEnv (Env.leave env.currentFrameId)
|
2017-06-15 22:06:49 +03:00
|
|
|
|> map (always res)
|
2017-06-14 16:49:27 +03:00
|
|
|
)
|
|
|
|
)
|
2017-06-15 22:06:49 +03:00
|
|
|
|
|
|
|
|
|
|
|
{-| Apply f to expr repeatedly.
|
|
|
|
Continues iterating if f returns (Left eval).
|
|
|
|
Stops if f returns (Right expr).
|
|
|
|
|
|
|
|
Tail call optimized.
|
|
|
|
|
|
|
|
-}
|
2017-06-20 18:23:00 +03:00
|
|
|
runLoop : (MalExpr -> Env -> Either (Eval MalExpr) MalExpr) -> MalExpr -> Eval MalExpr
|
2017-06-15 22:06:49 +03:00
|
|
|
runLoop f expr env =
|
2017-06-20 18:23:00 +03:00
|
|
|
case f expr env of
|
2017-06-15 22:06:49 +03:00
|
|
|
Left e ->
|
|
|
|
case apply e env of
|
|
|
|
( env, EvalOk expr ) ->
|
|
|
|
runLoop f expr env
|
|
|
|
|
|
|
|
( env, EvalErr msg ) ->
|
|
|
|
( env, EvalErr msg )
|
|
|
|
|
|
|
|
( env, EvalIO cmd cont ) ->
|
|
|
|
( env, EvalIO cmd (cont >> andThen (runLoop f)) )
|
|
|
|
|
|
|
|
Right expr ->
|
|
|
|
( env, EvalOk expr )
|
2017-06-18 22:38:48 +03:00
|
|
|
|
|
|
|
|
|
|
|
fromResult : Result String a -> Eval a
|
|
|
|
fromResult res =
|
|
|
|
case res of
|
|
|
|
Ok val ->
|
|
|
|
succeed val
|
|
|
|
|
|
|
|
Err msg ->
|
|
|
|
fail msg
|
2017-06-18 23:21:25 +03:00
|
|
|
|
|
|
|
|
|
|
|
{-| Chain the left and right Eval but ignore the right's result.
|
|
|
|
-}
|
|
|
|
ignore : Eval b -> Eval a -> Eval a
|
|
|
|
ignore right left =
|
|
|
|
left
|
|
|
|
|> andThen
|
|
|
|
(\res ->
|
|
|
|
right
|
|
|
|
|> andThen (\_ -> succeed res)
|
|
|
|
)
|