Commit | Line | Data |
---|---|---|
2ff2d84b | 1 | {zip, map, apply, and-list, join, Obj} = require 'prelude-ls' |
3181c695 JB |
2 | {pr_str} = require './printer' |
3 | ||
4 | ||
5 | export runtime-error = (msg) -> throw new Error msg | |
6 | ||
7 | ||
8 | fn = (body) -> {type: \function, value: body} | |
2ff2d84b | 9 | const-nil = -> {type: \const, value: \nil} |
3181c695 JB |
10 | const-int = (int) -> {type: \int, value: int} |
11 | const-bool = (bool) -> {type: \const, value: if bool then \true else \false} | |
12 | const-str = (str) -> {type: \string, value: str} | |
13 | ||
14 | list-or-vector = ({type}) -> type in [\list \vector] | |
15 | ||
16 | deep-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 | ||
30 | export 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 |