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 (printStr)
9 import Utils exposing (maybeToList, zip)
10 import Dict exposing (Dict)
11 import Tuple exposing (mapFirst, second)
16 main : Program Flags Model Msg
22 \model -> input (decodeValue decodeIO >> Input)
42 = Input (Result String IO)
45 init : Flags -> ( Model, Cmd Msg )
47 ( { args = args, env = initReplEnv }, readLine prompt )
54 CoreFunc >> MalFunction
58 [ MalInt x, MalInt y ] ->
59 Eval.succeed <| MalInt (fn x y)
62 Eval.fail "unsupported arguments"
65 [ ( "+", makeFn <| binaryOp (+) )
66 , ( "-", makeFn <| binaryOp (-) )
67 , ( "*", makeFn <| binaryOp (*) )
68 , ( "/", makeFn <| binaryOp (//) )
72 update : Msg -> Model -> ( Model, Cmd Msg )
75 Input (Ok (LineRead (Just line))) ->
76 case rep model.env line of
78 ( model, readLine prompt )
80 Just ( result, newEnv ) ->
81 ( { model | env = newEnv }, writeLine (makeOutput result) )
83 Input (Ok LineWritten) ->
84 ( model, readLine prompt )
86 Input (Ok (LineRead Nothing)) ->
90 Debug.crash "unexpected IO received: " io
93 Debug.crash msg ( model, Cmd.none )
96 makeOutput : Result String String -> String
111 {-| read can return three things:
113 Ok (Just expr) -> parsed okay
114 Ok Nothing -> empty string (only whitespace and/or comments)
115 Err msg -> parse error
118 read : String -> Result String (Maybe MalExpr)
123 eval : ReplEnv -> MalExpr -> ( Result String MalExpr, ReplEnv )
130 case evalList env list [] of
131 ( Ok newList, newEnv ) ->
134 ( Err "can't happen", newEnv )
136 (MalFunction (CoreFunc fn)) :: args ->
137 case Eval.runSimple (fn args) of
142 ( Err (print msg), newEnv )
145 ( Err ((print fn) ++ " is not a function"), newEnv )
147 ( Err msg, newEnv ) ->
154 evalAst : ReplEnv -> MalExpr -> ( Result String MalExpr, ReplEnv )
158 -- Lookup symbol in env and return value or raise error if not found.
159 case Dict.get sym env of
164 ( Err "symbol not found", env )
167 -- Return new list that is result of calling eval on each element of list.
169 |> mapFirst (Result.map MalList)
172 evalList env (Array.toList vec) []
173 |> mapFirst (Result.map (Array.fromList >> MalVector))
176 evalList env (Dict.values map) []
189 evalList : ReplEnv -> List MalExpr -> List MalExpr -> ( Result String (List MalExpr), ReplEnv )
190 evalList env list acc =
193 ( Ok (List.reverse acc), env )
197 ( Ok val, newEnv ) ->
198 evalList newEnv rest (val :: acc)
200 ( Err msg, newEnv ) ->
204 {-| Try to map a list with a fn that can return a Err.
206 Maps the list from left to right. As soon as a error
207 occurs it will not process any more elements and return
211 tryMapList : (a -> Result e b) -> List a -> Result e (List b)
225 List.foldl go (Ok []) list
226 |> Result.map List.reverse
229 print : MalExpr -> String
234 {-| Read-Eval-Print. rep returns:
236 Nothing -> if an empty string is read (ws/comments)
237 Just ((Ok out), newEnv) -> input has been evaluated.
238 Just ((Err msg), env) -> error parsing or evaluating.
241 rep : ReplEnv -> String -> Maybe ( Result String String, ReplEnv )
245 eval env >> mapFirst (Result.map print)
247 case readString input of
252 Just ( Err msg, env )