1 module Core exposing (..)
3 import Types exposing (..)
6 import Printer exposing (printString)
9 import IO exposing (IO(..))
11 import Utils exposing (zip)
20 CoreFunc >> MalFunction
22 binaryOp fn retType args =
24 [ MalInt x, MalInt y ] ->
25 Eval.succeed (retType (fn x y))
28 Eval.fail "unsupported arguments"
32 Eval.succeed << MalList
38 Eval.succeed (MalBool True)
41 Eval.succeed (MalBool False)
47 Eval.succeed <| MalBool (List.isEmpty list)
50 Eval.succeed <| MalBool (Array.isEmpty vec)
53 Eval.fail "unsupported arguments"
59 Eval.succeed (MalInt 0)
62 Eval.succeed <| MalInt (List.length list)
65 Eval.succeed <| MalInt (Array.length vec)
68 Eval.fail "unsupported arguments"
75 ( x :: xs, y :: ys ) ->
76 if deepEquals x y then
84 compareListTo list other =
87 equalLists list otherList
90 equalLists list (Array.toList vec)
96 if Dict.keys a /= Dict.keys b then
99 zip (Dict.values a) (Dict.values b)
100 |> List.map (uncurry deepEquals)
105 ( MalList list, MalList otherList ) ->
106 equalLists list otherList
108 ( MalList list, MalVector vec ) ->
109 equalLists list (Array.toList vec)
114 ( MalVector vec, MalList list ) ->
115 equalLists (Array.toList vec) list
117 ( MalVector vec, MalVector otherVec ) ->
118 equalLists (Array.toList vec) (Array.toList otherVec)
120 ( MalVector _, _ ) ->
123 ( MalMap map, MalMap otherMap ) ->
124 equalMaps map otherMap
139 Eval.succeed <| MalBool (deepEquals a b)
142 Eval.fail "unsupported arguments"
149 |> List.map (printString env True)
160 |> List.map (printString env False)
166 {- helper function to write a string to stdout -}
168 Eval.io (IO.writeLine str)
175 Eval.fail "wrong IO, expected LineWritten"
182 |> List.map (printString env True)
191 |> List.map (printString env False)
199 Eval.withEnv (Printer.printEnv >> writeLine)
202 Eval.fail "unsupported arguments"
207 case Reader.readString str of
218 Eval.fail "unsupported arguments"
222 [ MalString filename ] ->
223 Eval.io (IO.readFile filename)
227 Eval.succeed <| MalString contents
233 Eval.fail "wrong IO, expected FileRead"
237 Eval.fail "unsupported arguments"
244 case Env.newAtom value env of
245 ( newEnv, atomId ) ->
247 |> Eval.map (\_ -> MalAtom atomId)
251 Eval.fail "unsupported arguments"
256 Eval.succeed <| MalBool True
259 Eval.succeed <| MalBool False
263 [ MalAtom atomId ] ->
264 Eval.withEnv (Env.getAtom atomId >> Eval.succeed)
267 Eval.fail "unsupported arguments"
271 [ MalAtom atomId, value ] ->
272 Eval.modifyEnv (Env.setAtom atomId value)
273 |> Eval.map (always value)
276 Eval.fail "unsupported arguments"
278 {- helper function for calling a core or user function -}
284 UserFunc { eagerFn } ->
289 (MalAtom atomId) :: (MalFunction func) :: args ->
294 Env.getAtom atomId env
296 callFn func (value :: args)
300 Eval.modifyEnv (Env.setAtom atomId res)
301 |> Eval.map (always res)
305 Eval.fail "unsupported arguments"
308 Eval.withEnv (Env.gc MalNil >> Printer.printEnv >> writeLine)
313 { env | debug = enabled }
315 |> Eval.andThen (\_ -> Eval.succeed MalNil)
325 Eval.succeed (MalBool env.debug)
331 Eval.succeed <| MalSymbol "int"
334 Eval.succeed <| MalSymbol "bool"
337 Eval.succeed <| MalSymbol "string"
340 Eval.succeed <| MalSymbol "keyword"
343 Eval.succeed <| MalSymbol "symbol"
346 Eval.succeed <| MalSymbol "nil"
349 Eval.succeed <| MalSymbol "vector"
352 Eval.succeed <| MalSymbol "vector"
355 Eval.succeed <| MalSymbol "vector"
358 Eval.succeed <| MalSymbol "function"
361 Eval.succeed <| MalSymbol "atom"
364 Eval.fail "unsupported arguments"
368 [ e, MalList list ] ->
369 Eval.succeed <| MalList (e :: list)
371 [ e, MalVector vec ] ->
372 Eval.succeed <| MalList (e :: (Array.toList vec))
375 Eval.fail "unsupported arguments"
382 Eval.succeed (acc ++ list)
385 Eval.succeed (acc ++ Array.toList vec)
388 Eval.fail "unsupported arguments"
390 List.foldl (go >> Eval.andThen) (Eval.succeed []) args
398 else if index == 0 then
414 Eval.fail "index out of bounds"
417 [ MalList list, MalInt index ] ->
418 make <| get list index
420 [ MalVector vec, MalInt index ] ->
421 make <| Array.get index vec
424 Eval.fail "unsupported arguments"
429 Eval.succeed << Maybe.withDefault MalNil
436 make <| List.head list
439 make <| Array.get 0 vec
442 Eval.fail "unsupported arguments"
447 Eval.succeed <| MalList []
450 Eval.succeed <| MalList []
452 [ MalList (head :: tail) ] ->
453 Eval.succeed <| MalList tail
458 |> Maybe.withDefault []
463 Eval.fail "unsupported arguments"
471 Eval.fail "undefined exception"
475 (MalFunction func) :: rest ->
476 case List.reverse rest of
477 (MalList last) :: middle ->
478 callFn func ((List.reverse middle) ++ last)
480 (MalVector last) :: middle ->
482 ((List.reverse middle)
483 ++ (Array.toList last)
487 Eval.fail "apply expected the last argument to be a list or vector"
490 Eval.fail "unsupported arguments"
497 Eval.succeed <| MalList <| List.reverse acc
503 go func rest (outv :: acc)
507 [ MalFunction func, MalList list ] ->
510 [ MalFunction func, MalVector vec ] ->
511 go func (Array.toList vec) []
514 Eval.fail "unsupported arguments"
530 (MalBool True) :: _ ->
540 (MalBool False) :: _ ->
550 (MalSymbol _) :: _ ->
560 (MalKeyword _) :: _ ->
570 (MalVector _) :: _ ->
590 (MalString _) :: _ ->
603 (MalVector _) :: _ ->
612 Eval.succeed <| MalSymbol str
615 Eval.fail "unsupported arguments"
620 Eval.succeed <| MalKeyword (String.cons ':' str)
623 Eval.fail "unsupported arguments"
626 Eval.succeed <| MalVector <| Array.fromList args
633 MalKeyword keyword ->
634 Ok <| String.cons keywordPrefix keyword
637 Err "map key must be a symbol or keyword"
642 Eval.succeed <| MalMap acc
644 key :: value :: rest ->
649 buildMap rest (Dict.insert key value acc)
653 Eval.fail "expected an even number of key-value pairs"
656 buildMap args Dict.empty
660 (MalMap dict) :: rest ->
664 Eval.fail "unsupported arguments"
671 Eval.succeed <| MalMap acc
678 go rest (Dict.remove key acc)
682 (MalMap dict) :: keys ->
686 Eval.fail "unsupported arguments"
693 [ MalMap dict, key ] ->
699 |> Maybe.withDefault MalNil
703 Eval.fail "unsupported arguments"
707 [ MalMap dict, key ] ->
710 |> Eval.map (\key -> Dict.member key dict)
714 Eval.fail "unsupported arguments"
717 case String.uncons key of
718 Just ( prefix, rest ) ->
719 if prefix == keywordPrefix then
731 |> List.map unparseKey
736 Eval.fail "unsupported arguments"
746 Eval.fail "unsupported arguments"
750 [ MalString prompt ] ->
751 Eval.io (IO.readLine prompt)
754 LineRead (Just line) ->
755 Eval.succeed (MalString line)
761 Eval.fail "wrong IO, expected LineRead"
765 Eval.fail "unsupported arguments"
769 [ MalFunction (UserFunc func), meta ] ->
770 Eval.succeed <| MalFunction <| UserFunc { func | meta = Just meta }
773 Eval.fail "with-meta expected a user function and a map"
777 [ MalFunction (UserFunc { meta }) ] ->
778 Eval.succeed (Maybe.withDefault MalNil meta)
785 (MalList list) :: rest ->
791 (MalVector vec) :: rest ->
796 (Array.fromList rest)
799 Eval.fail "unsupported arguments"
812 [ (MalList _) as list ] ->
817 if Array.isEmpty vec then
820 MalList <| Array.toList vec
826 |> List.map String.fromChar
827 |> List.map MalString
831 Eval.fail "unsupported arguments"
834 Task.perform (GotTime >> Ok >> Input) Time.now
843 Time.inMilliseconds time
849 Eval.fail "wrong IO, expected GotTime"
853 Eval.fail "time-ms takes no arguments"
856 |> Env.set "+" (makeFn <| binaryOp (+) MalInt)
857 |> Env.set "-" (makeFn <| binaryOp (-) MalInt)
858 |> Env.set "*" (makeFn <| binaryOp (*) MalInt)
859 |> Env.set "/" (makeFn <| binaryOp (//) MalInt)
860 |> Env.set "<" (makeFn <| binaryOp (<) MalBool)
861 |> Env.set ">" (makeFn <| binaryOp (>) MalBool)
862 |> Env.set "<=" (makeFn <| binaryOp (<=) MalBool)
863 |> Env.set ">=" (makeFn <| binaryOp (>=) MalBool)
864 |> Env.set "list" (makeFn list)
865 |> Env.set "list?" (makeFn isList)
866 |> Env.set "empty?" (makeFn isEmpty)
867 |> Env.set "count" (makeFn count)
868 |> Env.set "=" (makeFn equals)
869 |> Env.set "pr-str" (makeFn prStr)
870 |> Env.set "str" (makeFn str)
871 |> Env.set "prn" (makeFn prn)
872 |> Env.set "println" (makeFn println)
873 |> Env.set "pr-env" (makeFn printEnv)
874 |> Env.set "read-string" (makeFn readString)
875 |> Env.set "slurp" (makeFn slurp)
876 |> Env.set "atom" (makeFn atom)
877 |> Env.set "atom?" (makeFn isAtom)
878 |> Env.set "deref" (makeFn deref)
879 |> Env.set "reset!" (makeFn reset)
880 |> Env.set "swap!" (makeFn swap)
881 |> Env.set "gc" (makeFn gc)
882 |> Env.set "debug!" (makeFn debug)
883 |> Env.set "typeof" (makeFn typeof)
884 |> Env.set "cons" (makeFn cons)
885 |> Env.set "concat" (makeFn concat)
886 |> Env.set "nth" (makeFn nth)
887 |> Env.set "first" (makeFn first)
888 |> Env.set "rest" (makeFn rest)
889 |> Env.set "throw" (makeFn throw)
890 |> Env.set "apply" (makeFn apply)
891 |> Env.set "map" (makeFn map)
892 |> Env.set "nil?" (makeFn isNil)
893 |> Env.set "true?" (makeFn isTrue)
894 |> Env.set "false?" (makeFn isFalse)
895 |> Env.set "symbol?" (makeFn isSymbol)
896 |> Env.set "keyword?" (makeFn isKeyword)
897 |> Env.set "vector?" (makeFn isVector)
898 |> Env.set "map?" (makeFn isMap)
899 |> Env.set "string?" (makeFn isString)
900 |> Env.set "sequential?" (makeFn isSequential)
901 |> Env.set "symbol" (makeFn symbol)
902 |> Env.set "keyword" (makeFn keyword)
903 |> Env.set "vector" (makeFn vector)
904 |> Env.set "hash-map" (makeFn hashMap)
905 |> Env.set "assoc" (makeFn assoc)
906 |> Env.set "dissoc" (makeFn dissoc)
907 |> Env.set "get" (makeFn get)
908 |> Env.set "contains?" (makeFn contains)
909 |> Env.set "keys" (makeFn keys)
910 |> Env.set "vals" (makeFn vals)
911 |> Env.set "readline" (makeFn readLine)
912 |> Env.set "with-meta" (makeFn withMeta)
913 |> Env.set "meta" (makeFn meta)
914 |> Env.set "conj" (makeFn conj)
915 |> Env.set "seq" (makeFn seq)
916 |> Env.set "time-ms" (makeFn timeMs)