Step 5
[jackhill/mal.git] / livescript / core.ls
CommitLineData
2ff2d84b 1{zip, map, apply, and-list, join, Obj} = require 'prelude-ls'
3181c695
JB
2{pr_str} = require './printer'
3
4
5export runtime-error = (msg) -> throw new Error msg
6
7
8fn = (body) -> {type: \function, value: body}
2ff2d84b 9const-nil = -> {type: \const, value: \nil}
3181c695
JB
10const-int = (int) -> {type: \int, value: int}
11const-bool = (bool) -> {type: \const, value: if bool then \true else \false}
12const-str = (str) -> {type: \string, value: str}
13
14list-or-vector = ({type}) -> type in [\list \vector]
15
16deep-equals = (a, b) ->
17 if not list-or-vector a then
18 if a.type != b.type then false
19 else a.value == b.value
20 else if list-or-vector b then
21 if a.value.length != b.value.length then false
22 else
23 # Compare all elements of a and b with deep-equals.
24 zip a.value, b.value
25 |> map (apply deep-equals)
26 |> and-list # all must be true (equals)
27 else false
28
29
30export ns = do
31 '+': fn (a, b) -> const-int a.value + b.value
32 '-': fn (a, b) -> const-int a.value - b.value
33 '*': fn (a, b) -> const-int a.value * b.value
34 '/': fn (a, b) -> const-int parseInt (a.value / b.value)
35
36 'list': fn (...list) -> {type: \list, value: list}
37 'list?': fn (param) -> const-bool param.type == \list
38
2ff2d84b
JB
39 'empty?': fn ({type, value}) ->
40 switch type
41 | \const =>
42 if value == \nil
43 then const-bool true
44 else runtime-error "'empty?' is not supported on #{value}"
45 | \list, \vector =>
46 const-bool value.length == 0
47 | \map =>
48 const-bool Obj.empty value
49 | otherwise =>
50 runtime-error "'empty?' is not supported on type #{type}"
51
52 'count': fn ({type, value}) ->
53 switch type
54 | \const =>
55 if value == \nil
56 then const-int 0
57 else runtime-error "'count' is not supported on #{value}"
58 | \list, \vector =>
59 const-int value.length
60 | \map =>
61 value |> Obj.keys |> (.length) |> const-int
62 | otherwise =>
63 runtime-error "'count' is not supported on type #{type}"
3181c695
JB
64
65 '=': fn (a, b) -> const-bool (deep-equals a, b)
66 '<': fn (a, b) -> const-bool a.value < b.value
67 '>': fn (a, b) -> const-bool a.value > b.value
68 '<=': fn (a, b) -> const-bool a.value <= b.value
69 '>=': fn (a, b) -> const-bool a.value >= b.value
70
2ff2d84b
JB
71 'not': fn ({type, value}) ->
72 const-bool (type == \const and value == \false)
73
74 'pr-str': fn (...params) ->
75 params |> map (p) -> pr_str p, print_readably=true
76 |> join ' '
77 |> const-str
78
79 'str': fn (...params) ->
80 params |> map (p) -> pr_str p, print_readably=false
81 |> join ''
82 |> const-str
83
84 'prn': fn (...params) ->
85 params |> map (p) -> pr_str p, print_readably=true
86 |> join ' '
87 |> console.log
88 |> const-nil
89
90 'println': fn (...params) ->
91 params |> map (p) -> pr_str p, print_readbly=false
92 |> join ' '
93 |> console.log
94 |> const-nil