1 port module Main exposing (..)
3 import IO exposing (..)
4 import Json.Decode exposing (decodeValue)
5 import Platform exposing (programWithFlags)
6 import Types exposing (..)
7 import Reader exposing (readString)
8 import Printer exposing (printString)
9 import Utils exposing (maybeToList, zip)
10 import Dict exposing (Dict)
11 import Tuple exposing (mapFirst, mapSecond, second)
17 main : Program Flags Model Msg
22 , subscriptions = \model -> input (decodeValue decodeIO >> Input)
38 = Input (Result String IO)
41 init : Flags -> ( Model, Cmd Msg )
43 ( { args = args, env = initReplEnv }, readLine prompt )
50 CoreFunc >> MalFunction
54 [ MalInt x, MalInt y ] ->
55 Eval.succeed <| MalInt (fn x y)
58 Eval.fail "unsupported arguments"
61 |> Env.set "+" (makeFn <| binaryOp (+))
62 |> Env.set "-" (makeFn <| binaryOp (-))
63 |> Env.set "*" (makeFn <| binaryOp (*))
64 |> Env.set "/" (makeFn <| binaryOp (//))
67 update : Msg -> Model -> ( Model, Cmd Msg )
70 Input (Ok (LineRead (Just line))) ->
71 case rep model.env line of
73 ( model, readLine prompt )
75 Just ( result, newEnv ) ->
76 ( { model | env = newEnv }, writeLine (makeOutput result) )
78 Input (Ok LineWritten) ->
79 ( model, readLine prompt )
81 Input (Ok (LineRead Nothing)) ->
85 Debug.crash "unexpected IO received: " io
88 Debug.crash msg ( model, Cmd.none )
91 makeOutput : Result String String -> String
106 {-| read can return three things:
108 Ok (Just expr) -> parsed okay
109 Ok Nothing -> empty string (only whitespace and/or comments)
110 Err msg -> parse error
113 read : String -> Result String (Maybe MalExpr)
118 eval : Env -> MalExpr -> ( Result String MalExpr, Env )
124 MalList ((MalSymbol "def!") :: args) ->
127 MalList ((MalSymbol "let*") :: args) ->
131 case evalList env list [] of
132 ( Ok newList, newEnv ) ->
135 ( Err "can't happen", newEnv )
137 (MalFunction (CoreFunc fn)) :: args ->
138 case Eval.runSimple (fn args) of
143 ( Err (print msg), newEnv )
146 ( Err ((print fn) ++ " is not a function"), newEnv )
148 ( Err msg, newEnv ) ->
155 evalAst : Env -> MalExpr -> ( Result String MalExpr, Env )
159 -- Lookup symbol in env and return value or raise error if not found.
160 case Env.get sym env of
168 -- Return new list that is result of calling eval on each element of list.
170 |> mapFirst (Result.map MalList)
173 evalList env (Array.toList vec) []
174 |> mapFirst (Result.map (Array.fromList >> MalVector))
177 evalList env (Dict.values map) []
190 evalList : Env -> List MalExpr -> List MalExpr -> ( Result String (List MalExpr), Env )
191 evalList env list acc =
194 ( Ok (List.reverse acc), env )
198 ( Ok val, newEnv ) ->
199 evalList newEnv rest (val :: acc)
201 ( Err msg, newEnv ) ->
205 evalDef : Env -> List MalExpr -> ( Result String MalExpr, Env )
208 [ MalSymbol name, uneValue ] ->
209 case eval env uneValue of
210 ( Ok value, newEnv ) ->
211 ( Ok value, Env.set name value newEnv )
217 ( Err "def! expected two args: name and value", env )
220 evalLet : Env -> List MalExpr -> ( Result String MalExpr, Env )
223 evalBinds env binds =
225 (MalSymbol name) :: expr :: rest ->
226 case eval env expr of
227 ( Ok value, newEnv ) ->
230 Env.set name value env
232 if List.isEmpty rest then
235 evalBinds newEnv rest
241 Err "let* expected an even number of binds (symbol expr ..)"
244 case evalBinds (Env.push env) binds of
247 |> mapSecond (\_ -> Env.pop newEnv)
253 [ MalList binds, body ] ->
256 [ MalVector bindsVec, body ] ->
257 go (Array.toList bindsVec) body
260 ( Err "let* expected two args: binds and a body", env )
263 {-| Try to map a list with a fn that can return a Err.
265 Maps the list from left to right. As soon as a error
266 occurs it will not process any more elements and return
270 tryMapList : (a -> Result e b) -> List a -> Result e (List b)
284 List.foldl go (Ok []) list
285 |> Result.map List.reverse
288 print : MalExpr -> String
290 printString Env.global True
293 {-| Read-Eval-Print. rep returns:
295 Nothing -> if an empty string is read (ws/comments)
296 Just ((Ok out), newEnv) -> input has been evaluated.
297 Just ((Err msg), env) -> error parsing or evaluating.
300 rep : Env -> String -> Maybe ( Result String String, Env )
304 eval env >> mapFirst (Result.map print)
306 case readString input of
311 Just ( Err msg, env )