1 module Core exposing (..)
3 import Types exposing (MalExpr(..), MalFunction(..), Eval, Env, keywordPrefix)
6 import Printer exposing (printString)
9 import IO exposing (IO(..))
11 import Utils exposing (zip)
18 CoreFunc >> MalFunction
20 binaryOp fn retType args =
22 [ MalInt x, MalInt y ] ->
23 Eval.succeed (retType (fn x y))
26 Eval.fail "unsupported arguments"
30 Eval.succeed << MalList
36 Eval.succeed (MalBool True)
39 Eval.succeed (MalBool False)
45 Eval.succeed <| MalBool (List.isEmpty list)
48 Eval.succeed <| MalBool (Array.isEmpty vec)
51 Eval.fail "unsupported arguments"
57 Eval.succeed (MalInt 0)
60 Eval.succeed <| MalInt (List.length list)
63 Eval.succeed <| MalInt (Array.length vec)
66 Eval.fail "unsupported arguments"
73 ( x :: xs, y :: ys ) ->
74 if deepEquals x y then
82 compareListTo list other =
85 equalLists list otherList
88 equalLists list (Array.toList vec)
94 if Dict.keys a /= Dict.keys b then
97 zip (Dict.values a) (Dict.values b)
98 |> List.map (uncurry deepEquals)
103 ( MalList list, MalList otherList ) ->
104 equalLists list otherList
106 ( MalList list, MalVector vec ) ->
107 equalLists list (Array.toList vec)
112 ( MalVector vec, MalList list ) ->
113 equalLists (Array.toList vec) list
115 ( MalVector vec, MalVector otherVec ) ->
116 equalLists (Array.toList vec) (Array.toList otherVec)
118 ( MalVector _, _ ) ->
121 ( MalMap map, MalMap otherMap ) ->
122 equalMaps map otherMap
137 Eval.succeed <| MalBool (deepEquals a b)
140 Eval.fail "unsupported arguments"
147 |> List.map (printString env True)
158 |> List.map (printString env False)
164 {- helper function to write a string to stdout -}
166 Eval.io (IO.writeLine str)
173 Eval.fail "wrong IO, expected LineWritten"
180 |> List.map (printString env True)
189 |> List.map (printString env False)
197 Eval.withEnv (Printer.printEnv >> writeLine)
200 Eval.fail "unsupported arguments"
205 case Reader.readString str of
216 Eval.fail "unsupported arguments"
220 [ MalString filename ] ->
221 Eval.io (IO.readFile filename)
225 Eval.succeed <| MalString contents
231 Eval.fail "wrong IO, expected FileRead"
235 Eval.fail "unsupported arguments"
242 case Env.newAtom value env of
243 ( newEnv, atomId ) ->
245 |> Eval.map (\_ -> MalAtom atomId)
249 Eval.fail "unsupported arguments"
254 Eval.succeed <| MalBool True
257 Eval.succeed <| MalBool False
261 [ MalAtom atomId ] ->
262 Eval.withEnv (Env.getAtom atomId >> Eval.succeed)
265 Eval.fail "unsupported arguments"
269 [ MalAtom atomId, value ] ->
270 Eval.modifyEnv (Env.setAtom atomId value)
271 |> Eval.map (always value)
274 Eval.fail "unsupported arguments"
276 {- helper function for calling a core or user function -}
282 UserFunc { eagerFn } ->
287 (MalAtom atomId) :: (MalFunction func) :: args ->
292 Env.getAtom atomId env
294 callFn func (value :: args)
298 Eval.modifyEnv (Env.setAtom atomId res)
299 |> Eval.map (always res)
303 Eval.fail "unsupported arguments"
306 Eval.withEnv (Env.gc >> Printer.printEnv >> writeLine)
311 { env | debug = enabled }
313 |> Eval.andThen (\_ -> Eval.succeed MalNil)
326 Eval.succeed <| MalSymbol "int"
329 Eval.succeed <| MalSymbol "bool"
332 Eval.succeed <| MalSymbol "string"
335 Eval.succeed <| MalSymbol "keyword"
338 Eval.succeed <| MalSymbol "symbol"
341 Eval.succeed <| MalSymbol "nil"
344 Eval.succeed <| MalSymbol "vector"
347 Eval.succeed <| MalSymbol "vector"
350 Eval.succeed <| MalSymbol "vector"
353 Eval.succeed <| MalSymbol "function"
356 Eval.succeed <| MalSymbol "atom"
359 Eval.fail "unsupported arguments"
363 [ e, MalList list ] ->
364 Eval.succeed <| MalList (e :: list)
366 [ e, MalVector vec ] ->
367 Eval.succeed <| MalList (e :: (Array.toList vec))
370 Eval.fail "unsupported arguments"
377 Eval.succeed (acc ++ list)
380 Eval.succeed (acc ++ Array.toList vec)
383 Eval.fail "unsupported arguments"
385 List.foldl (go >> Eval.andThen) (Eval.succeed []) args
393 else if index == 0 then
409 Eval.fail "index out of bounds"
412 [ MalList list, MalInt index ] ->
413 make <| get list index
415 [ MalVector vec, MalInt index ] ->
416 make <| Array.get index vec
419 Eval.fail "unsupported arguments"
424 Eval.succeed << Maybe.withDefault MalNil
431 make <| List.head list
434 make <| Array.get 0 vec
437 Eval.fail "unsupported arguments"
442 Eval.succeed <| MalList []
445 Eval.succeed <| MalList []
447 [ MalList (head :: tail) ] ->
448 Eval.succeed <| MalList tail
453 |> Maybe.withDefault []
458 Eval.fail "unsupported arguments"
466 Eval.fail "undefined exception"
470 (MalFunction func) :: rest ->
474 Eval.fail "unsupported arguments"
481 Eval.succeed <| MalList <| List.reverse acc
487 go func rest (outv :: acc)
491 [ MalFunction func, MalList list ] ->
494 [ MalFunction func, MalVector vec ] ->
495 go func (Array.toList vec) []
498 Eval.fail "unsupported arguments"
514 (MalBool True) :: _ ->
524 (MalBool False) :: _ ->
534 (MalSymbol _) :: _ ->
544 (MalKeyword _) :: _ ->
554 (MalVector _) :: _ ->
573 Eval.succeed <| MalSymbol str
576 Eval.fail "unsupported arguments"
581 Eval.succeed <| MalKeyword (String.cons ':' str)
584 Eval.fail "unsupported arguments"
587 Eval.succeed <| MalVector <| Array.fromList args
594 MalKeyword keyword ->
595 Ok <| String.cons keywordPrefix keyword
598 Err "map key must be a symbol or keyword"
603 Eval.succeed <| MalMap acc
605 key :: value :: rest ->
610 buildMap rest (Dict.insert key value acc)
614 Eval.fail "expected an even number of key-value pairs"
617 buildMap args Dict.empty
621 (MalMap dict) :: rest ->
625 Eval.fail "unsupported arguments"
632 Eval.succeed <| MalMap acc
639 go rest (Dict.remove key acc)
643 (MalMap dict) :: keys ->
647 Eval.fail "unsupported arguments"
654 [ MalMap dict, key ] ->
660 |> Maybe.withDefault MalNil
664 Eval.fail "unsupported arguments"
668 [ MalMap dict, key ] ->
671 |> Eval.map (\key -> Dict.member key dict)
675 Eval.fail "unsupported arguments"
678 case String.uncons key of
679 Just ( prefix, rest ) ->
680 if prefix == keywordPrefix then
692 |> List.map unparseKey
697 Eval.fail "unsupported arguments"
707 Eval.fail "unsupported arguments"
710 |> Env.set "+" (makeFn <| binaryOp (+) MalInt)
711 |> Env.set "-" (makeFn <| binaryOp (-) MalInt)
712 |> Env.set "*" (makeFn <| binaryOp (*) MalInt)
713 |> Env.set "/" (makeFn <| binaryOp (//) MalInt)
714 |> Env.set "<" (makeFn <| binaryOp (<) MalBool)
715 |> Env.set ">" (makeFn <| binaryOp (>) MalBool)
716 |> Env.set "<=" (makeFn <| binaryOp (<=) MalBool)
717 |> Env.set ">=" (makeFn <| binaryOp (>=) MalBool)
718 |> Env.set "list" (makeFn list)
719 |> Env.set "list?" (makeFn isList)
720 |> Env.set "empty?" (makeFn isEmpty)
721 |> Env.set "count" (makeFn count)
722 |> Env.set "=" (makeFn equals)
723 |> Env.set "pr-str" (makeFn prStr)
724 |> Env.set "str" (makeFn str)
725 |> Env.set "prn" (makeFn prn)
726 |> Env.set "println" (makeFn println)
727 |> Env.set "pr-env" (makeFn printEnv)
728 |> Env.set "read-string" (makeFn readString)
729 |> Env.set "slurp" (makeFn slurp)
730 |> Env.set "atom" (makeFn atom)
731 |> Env.set "atom?" (makeFn isAtom)
732 |> Env.set "deref" (makeFn deref)
733 |> Env.set "reset!" (makeFn reset)
734 |> Env.set "swap!" (makeFn swap)
735 |> Env.set "gc" (makeFn gc)
736 |> Env.set "debug!" (makeFn debug)
737 |> Env.set "typeof" (makeFn typeof)
738 |> Env.set "cons" (makeFn cons)
739 |> Env.set "concat" (makeFn concat)
740 |> Env.set "nth" (makeFn nth)
741 |> Env.set "first" (makeFn first)
742 |> Env.set "rest" (makeFn rest)
743 |> Env.set "throw" (makeFn throw)
744 |> Env.set "nil?" (makeFn isNil)
745 |> Env.set "true?" (makeFn isTrue)
746 |> Env.set "false?" (makeFn isFalse)
747 |> Env.set "symbol?" (makeFn isSymbol)
748 |> Env.set "keyword?" (makeFn isKeyword)
749 |> Env.set "vector?" (makeFn isVector)
750 |> Env.set "map?" (makeFn isMap)
751 |> Env.set "symbol" (makeFn symbol)
752 |> Env.set "keyword" (makeFn keyword)
753 |> Env.set "vector" (makeFn vector)
754 |> Env.set "hash-map" (makeFn hashMap)
755 |> Env.set "assoc" (makeFn assoc)
756 |> Env.set "dissoc" (makeFn dissoc)
757 |> Env.set "get" (makeFn get)
758 |> Env.set "contains?" (makeFn contains)
759 |> Env.set "keys" (makeFn keys)
760 |> Env.set "vals" (makeFn vals)