diff --git a/impls/elm/Dockerfile b/impls/elm/Dockerfile index ab64a79f8a..c9781fc276 100644 --- a/impls/elm/Dockerfile +++ b/impls/elm/Dockerfile @@ -9,7 +9,8 @@ MAINTAINER Joel Martin RUN apt-get -y update # Required for running tests -RUN apt-get -y install make python +RUN apt-get -y install make python3 +RUN ln -s /usr/bin/python3 /usr/local/bin/python RUN mkdir -p /mal WORKDIR /mal @@ -18,7 +19,7 @@ WORKDIR /mal # Specific implementation requirements ########################################################## -RUN apt-get -y install libreadline-dev nodejs npm +RUN apt-get -y install g++ libreadline-dev nodejs npm ENV HOME /mal ENV NPM_CONFIG_CACHE /mal/.npm diff --git a/impls/elm/Step2_eval.elm b/impls/elm/Step2_eval.elm index 00ae4e730c..d8b0f3a1c1 100644 --- a/impls/elm/Step2_eval.elm +++ b/impls/elm/Step2_eval.elm @@ -120,6 +120,10 @@ read = eval : ReplEnv -> MalExpr -> ( Result String MalExpr, ReplEnv ) eval env ast = + -- let + -- _ = Debug.log ("EVAL: " ++ printStr env True ast) () + -- -- The output ends with an ugly ": ()", but that does not hurt. + -- in case ast of MalList _ [] -> ( Ok ast, env ) @@ -145,13 +149,6 @@ eval env ast = ( Err msg, newEnv ) -> ( Err msg, newEnv ) - _ -> - evalAst env ast - - -evalAst : ReplEnv -> MalExpr -> ( Result String MalExpr, ReplEnv ) -evalAst env ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. case Dict.get sym env of @@ -161,11 +158,6 @@ evalAst env ast = Nothing -> ( Err ("symbol '" ++ sym ++ "' not found"), env ) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList env list [] - |> mapFirst (Result.map (MalList Nothing)) - MalVector _ vec -> evalList env (Array.toList vec) [] |> mapFirst (Result.map (Array.fromList >> MalVector Nothing)) diff --git a/impls/elm/Step3_env.elm b/impls/elm/Step3_env.elm index 95e3df4a03..997c991b6e 100644 --- a/impls/elm/Step3_env.elm +++ b/impls/elm/Step3_env.elm @@ -116,6 +116,14 @@ read = eval : Env -> MalExpr -> ( Result String MalExpr, Env ) eval env ast = + let + _ = case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + in case ast of MalList _ [] -> ( Ok ast, env ) @@ -147,13 +155,6 @@ eval env ast = ( Err msg, newEnv ) -> ( Err msg, newEnv ) - _ -> - evalAst env ast - - -evalAst : Env -> MalExpr -> ( Result String MalExpr, Env ) -evalAst env ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. case Env.get sym env of @@ -163,11 +164,6 @@ evalAst env ast = Err msg -> ( Err msg, env ) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList env list [] - |> mapFirst (Result.map (MalList Nothing)) - MalVector _ vec -> evalList env (Array.toList vec) [] |> mapFirst (Result.map (Array.fromList >> MalVector Nothing)) diff --git a/impls/elm/Step4_if_fn_do.elm b/impls/elm/Step4_if_fn_do.elm index 7e41f34e7b..1f5c129ee8 100644 --- a/impls/elm/Step4_if_fn_do.elm +++ b/impls/elm/Step4_if_fn_do.elm @@ -152,6 +152,14 @@ read = eval : MalExpr -> Eval MalExpr eval ast = + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> case ast of MalList _ [] -> Eval.succeed ast @@ -192,13 +200,6 @@ eval ast = ) ) - _ -> - evalAst ast - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv @@ -211,11 +212,6 @@ evalAst ast = Eval.fail msg ) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -230,6 +226,7 @@ evalAst ast = _ -> Eval.succeed ast + ) evalList : List MalExpr -> Eval (List MalExpr) diff --git a/impls/elm/Step5_tco.elm b/impls/elm/Step5_tco.elm index dfa9145576..987d020526 100644 --- a/impls/elm/Step5_tco.elm +++ b/impls/elm/Step5_tco.elm @@ -191,28 +191,34 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr evalNoApply ast = - debug "evalNoApply" - (\env -> printString env True ast) - (case ast of - MalList _ [] -> + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ [] -> Eval.succeed ast - MalList _ ((MalSymbol "def!") :: args) -> + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ list -> + MalList _ list -> evalList list |> Eval.andThen (\newList -> @@ -233,14 +239,6 @@ evalNoApply ast = ) ) - _ -> - evalAst ast - ) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv @@ -253,11 +251,6 @@ evalAst ast = Eval.fail msg ) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -272,6 +265,7 @@ evalAst ast = _ -> Eval.succeed ast + ) evalList : List MalExpr -> Eval (List MalExpr) diff --git a/impls/elm/Step6_file.elm b/impls/elm/Step6_file.elm index d9f4a555ae..61dc739971 100644 --- a/impls/elm/Step6_file.elm +++ b/impls/elm/Step6_file.elm @@ -261,28 +261,34 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr evalNoApply ast = - debug "evalNoApply" - (\env -> printString env True ast) - (case ast of - MalList _ [] -> + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ [] -> Eval.succeed ast - MalList _ ((MalSymbol "def!") :: args) -> + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ list -> + MalList _ list -> evalList list |> Eval.andThen (\newList -> @@ -303,14 +309,6 @@ evalNoApply ast = ) ) - _ -> - evalAst ast - ) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv @@ -323,11 +321,6 @@ evalAst ast = Eval.fail msg ) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -342,6 +335,7 @@ evalAst ast = _ -> Eval.succeed ast + ) evalList : List MalExpr -> Eval (List MalExpr) diff --git a/impls/elm/Step7_quote.elm b/impls/elm/Step7_quote.elm index 171c3f76ff..b174bbf272 100644 --- a/impls/elm/Step7_quote.elm +++ b/impls/elm/Step7_quote.elm @@ -261,36 +261,37 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr evalNoApply ast = - debug "evalNoApply" - (\env -> printString env True ast) - (case ast of - MalList _ [] -> + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ [] -> Eval.succeed ast - MalList _ ((MalSymbol "def!") :: args) -> + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ ((MalSymbol "quote") :: args) -> + MalList _ ((MalSymbol "quote") :: args) -> evalQuote args - MalList _ [MalSymbol "quasiquoteexpand", expr] -> - Eval.succeed <| evalQuasiQuote expr - MalList _ (MalSymbol "quasiquoteexpand" :: _) -> - Eval.fail "quasiquoteexpand: arg count" - - MalList _ ((MalSymbol "quasiquote") :: args) -> + MalList _ ((MalSymbol "quasiquote") :: args) -> case args of [ expr ] -> -- TCO. @@ -299,7 +300,7 @@ evalNoApply ast = _ -> Eval.fail "unsupported arguments" - MalList _ list -> + MalList _ list -> evalList list |> Eval.andThen (\newList -> @@ -320,23 +321,10 @@ evalNoApply ast = ) ) - _ -> - evalAst ast - ) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv (Env.get sym >> Eval.fromResult) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -351,6 +339,7 @@ evalAst ast = _ -> Eval.succeed ast + ) evalList : List MalExpr -> Eval (List MalExpr) diff --git a/impls/elm/Step8_macros.elm b/impls/elm/Step8_macros.elm index a21ac1acd5..5d26863349 100644 --- a/impls/elm/Step8_macros.elm +++ b/impls/elm/Step8_macros.elm @@ -268,40 +268,35 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr -evalNoApply ast0 = - debug "evalNoApply" - (\env -> printString env True ast0) - (macroexpand ast0 - |> Eval.andThen - (\ast -> - case ast of - MalList _ [] -> - Eval.succeed ast - - MalList _ ((MalSymbol "def!") :: args) -> +evalNoApply ast = + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ ((MalSymbol "quote") :: args) -> + MalList _ ((MalSymbol "quote") :: args) -> evalQuote args - MalList _ [MalSymbol "quasiquoteexpand", expr] -> - Eval.succeed <| evalQuasiQuote expr - MalList _ (MalSymbol "quasiquoteexpand" :: _) -> - Eval.fail "quasiquoteexpand: arg count" - - MalList _ ((MalSymbol "quasiquote") :: args) -> + MalList _ ((MalSymbol "quasiquote") :: args) -> case args of [ expr ] -> -- TCO. @@ -310,56 +305,36 @@ evalNoApply ast0 = _ -> Eval.fail "unsupported arguments" - MalList _ ((MalSymbol "defmacro!") :: args) -> + MalList _ ((MalSymbol "defmacro!") :: args) -> evalDefMacro args - MalList _ ((MalSymbol "macroexpand") :: args) -> - case args of - [ expr ] -> - macroexpand expr - - _ -> - Eval.fail "unsupported arguments" - - MalList _ list -> - evalList list + MalList _ (a0 :: rest) -> + eval a0 |> Eval.andThen - (\newList -> - case newList of - [] -> - Eval.fail "can't happen" - - (MalFunction (CoreFunc _ fn)) :: args -> + (\f -> + case f of + MalFunction (CoreFunc _ fn) -> + let args = evalList rest in Eval.andThen fn args - (MalFunction (UserFunc { lazyFn })) :: args -> + MalFunction (UserFunc {isMacro, eagerFn, lazyFn}) -> + if isMacro then + Eval.andThen evalNoApply (eagerFn rest) + else + let args = evalList rest in Eval.andThen lazyFn args - fn :: _ -> + fn -> Eval.withEnv (\env -> Eval.fail ((printString env True fn) ++ " is not a function") ) ) - _ -> - evalAst ast - ) - ) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv (Env.get sym >> Eval.fromResult) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -374,6 +349,7 @@ evalAst ast = _ -> Eval.succeed ast + ) evalList : List MalExpr -> Eval (List MalExpr) @@ -658,28 +634,6 @@ evalQuasiQuote expr = expr -macroexpand : MalExpr -> Eval MalExpr -macroexpand = - let - expand expr env = - case expr of - MalList _ ((MalSymbol name) :: args) -> - case Env.get name env of - Ok (MalFunction (UserFunc fn)) -> - if fn.isMacro then - Left <| fn.eagerFn args - else - Right expr - - _ -> - Right expr - - _ -> - Right expr - in - Eval.runLoop expand - - print : Env -> MalExpr -> String print env = printString env True diff --git a/impls/elm/Step9_try.elm b/impls/elm/Step9_try.elm index 919411005d..af3974c7b5 100644 --- a/impls/elm/Step9_try.elm +++ b/impls/elm/Step9_try.elm @@ -268,37 +268,35 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr -evalNoApply ast0 = - let - go ast = - case ast of - MalList _ [] -> - Eval.succeed ast - - MalList _ ((MalSymbol "def!") :: args) -> +evalNoApply ast = + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ ((MalSymbol "quote") :: args) -> + MalList _ ((MalSymbol "quote") :: args) -> evalQuote args - MalList _ [MalSymbol "quasiquoteexpand", expr] -> - Eval.succeed <| evalQuasiQuote expr - MalList _ (MalSymbol "quasiquoteexpand" :: _) -> - Eval.fail "quasiquoteexpand: arg count" - - MalList _ ((MalSymbol "quasiquote") :: args) -> + MalList _ ((MalSymbol "quasiquote") :: args) -> case args of [ expr ] -> -- TCO. @@ -307,61 +305,39 @@ evalNoApply ast0 = _ -> Eval.fail "unsupported arguments" - MalList _ ((MalSymbol "defmacro!") :: args) -> + MalList _ ((MalSymbol "defmacro!") :: args) -> evalDefMacro args - MalList _ ((MalSymbol "macroexpand") :: args) -> - case args of - [ expr ] -> - macroexpand expr - - _ -> - Eval.fail "unsupported arguments" - - MalList _ ((MalSymbol "try*") :: args) -> + MalList _ ((MalSymbol "try*") :: args) -> evalTry args - MalList _ list -> - evalList list + MalList _ (a0 :: rest) -> + eval a0 |> Eval.andThen - (\newList -> - case newList of - [] -> - Eval.fail "can't happen" - - (MalFunction (CoreFunc _ fn)) :: args -> + (\f -> + case f of + MalFunction (CoreFunc _ fn) -> + let args = evalList rest in Eval.andThen fn args - (MalFunction (UserFunc { lazyFn })) :: args -> + MalFunction (UserFunc {isMacro, eagerFn, lazyFn}) -> + if isMacro then + Eval.andThen evalNoApply (eagerFn rest) + else + let args = evalList rest in Eval.andThen lazyFn args - fn :: _ -> + fn -> Eval.withEnv (\env -> Eval.fail ((printString env True fn) ++ " is not a function") ) ) - _ -> - evalAst ast - in - debug "evalNoApply" - (\env -> printString env True ast0) - (macroexpand ast0 |> Eval.andThen go) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv (Env.get sym >> Eval.fromResult) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -377,6 +353,8 @@ evalAst ast = _ -> Eval.succeed ast + ) + evalList : List MalExpr -> Eval (List MalExpr) evalList list = @@ -660,28 +638,6 @@ evalQuasiQuote expr = expr -macroexpand : MalExpr -> Eval MalExpr -macroexpand = - let - expand expr env = - case expr of - MalList _ ((MalSymbol name) :: args) -> - case Env.get name env of - Ok (MalFunction (UserFunc fn)) -> - if fn.isMacro then - Left <| fn.eagerFn args - else - Right expr - - _ -> - Right expr - - _ -> - Right expr - in - Eval.runLoop expand - - evalTry : List MalExpr -> Eval MalExpr evalTry args = case args of diff --git a/impls/elm/StepA_mal.elm b/impls/elm/StepA_mal.elm index f14b9d5de6..965f15ec37 100644 --- a/impls/elm/StepA_mal.elm +++ b/impls/elm/StepA_mal.elm @@ -270,37 +270,35 @@ evalApply { frameId, bound, body } = evalNoApply : MalExpr -> Eval MalExpr -evalNoApply ast0 = - let - go ast = - case ast of - MalList _ [] -> - Eval.succeed ast - - MalList _ ((MalSymbol "def!") :: args) -> +evalNoApply ast = + Eval.withEnv (\env -> Eval.succeed <| + case Env.get "DEBUG-EVAL" env of + Err _ -> () + Ok MalNil -> () + Ok (MalBool False) -> () + _ -> Debug.log ("EVAL: " ++ printString env True ast) () + -- The output ends with an ugly ": ()", but that does not hurt. + ) |> Eval.andThen (\_ -> + case ast of + MalList _ ((MalSymbol "def!") :: args) -> evalDef args - MalList _ ((MalSymbol "let*") :: args) -> + MalList _ ((MalSymbol "let*") :: args) -> evalLet args - MalList _ ((MalSymbol "do") :: args) -> + MalList _ ((MalSymbol "do") :: args) -> evalDo args - MalList _ ((MalSymbol "if") :: args) -> + MalList _ ((MalSymbol "if") :: args) -> evalIf args - MalList _ ((MalSymbol "fn*") :: args) -> + MalList _ ((MalSymbol "fn*") :: args) -> evalFn args - MalList _ ((MalSymbol "quote") :: args) -> + MalList _ ((MalSymbol "quote") :: args) -> evalQuote args - MalList _ [MalSymbol "quasiquoteexpand", expr] -> - Eval.succeed <| evalQuasiQuote expr - MalList _ (MalSymbol "quasiquoteexpand" :: _) -> - Eval.fail "quasiquoteexpand: arg count" - - MalList _ ((MalSymbol "quasiquote") :: args) -> + MalList _ ((MalSymbol "quasiquote") :: args) -> case args of [ expr ] -> -- TCO. @@ -309,66 +307,39 @@ evalNoApply ast0 = _ -> Eval.fail "unsupported arguments" - MalList _ ((MalSymbol "defmacro!") :: args) -> + MalList _ ((MalSymbol "defmacro!") :: args) -> evalDefMacro args - MalList _ ((MalSymbol "macroexpand") :: args) -> - case args of - [ expr ] -> - macroexpand expr - - _ -> - Eval.fail "unsupported arguments" - - MalList _ ((MalSymbol "try*") :: args) -> + MalList _ ((MalSymbol "try*") :: args) -> evalTry args - MalList _ list -> - evalList list + MalList _ (a0 :: rest) -> + eval a0 |> Eval.andThen - (\newList -> - case newList of - [] -> - Eval.fail "can't happen" - - (MalFunction (CoreFunc _ fn)) :: args -> + (\f -> + case f of + MalFunction (CoreFunc _ fn) -> + let args = evalList rest in Eval.andThen fn args - (MalFunction (UserFunc { lazyFn })) :: args -> + MalFunction (UserFunc {isMacro, eagerFn, lazyFn}) -> + if isMacro then + Eval.andThen evalNoApply (eagerFn rest) + else + let args = evalList rest in Eval.andThen lazyFn args - fn :: _ -> + fn -> Eval.withEnv (\env -> Eval.fail ((printString env True fn) ++ " is not a function") ) ) - _ -> - evalAst ast - in - macroexpand ast0 - |> Eval.andThen go - |> Eval.andThen - (\res -> - debug "evalNoApply" - (\env -> (printString env True ast0) ++ " = " ++ (printString env True res)) - (Eval.succeed res) - ) - - -evalAst : MalExpr -> Eval MalExpr -evalAst ast = - case ast of MalSymbol sym -> -- Lookup symbol in env and return value or raise error if not found. Eval.withEnv (Env.get sym >> Eval.fromResult) - MalList _ list -> - -- Return new list that is result of calling eval on each element of list. - evalList list - |> Eval.map (MalList Nothing) - MalVector _ vec -> evalList (Array.toList vec) |> Eval.map (Array.fromList >> MalVector Nothing) @@ -384,6 +355,12 @@ evalAst ast = _ -> Eval.succeed ast + ) |> Eval.andThen (\res -> + debug "evalNoApply" + (\env -> (printString env True ast) ++ " = " ++ (printString env True res)) + (Eval.succeed res) + ) + evalList : List MalExpr -> Eval (List MalExpr) evalList list = @@ -667,28 +644,6 @@ evalQuasiQuote expr = expr -macroexpand : MalExpr -> Eval MalExpr -macroexpand = - let - expand expr env = - case expr of - MalList _ ((MalSymbol name) :: args) -> - case Env.get name env of - Ok (MalFunction (UserFunc fn)) -> - if fn.isMacro then - Left <| fn.eagerFn args - else - Right expr - - _ -> - Right expr - - _ -> - Right expr - in - Eval.runLoop expand - - evalTry : List MalExpr -> Eval MalExpr evalTry args = case args of