4ce9e165 |
1 | import strutils, rdstdin, tables, algorithm, times, types, printer, reader |
8de9f308 |
2 | |
3 | type MalError* = object of Exception |
4 | t*: MalType |
819bd786 |
5 | |
6 | # String functions |
7 | proc pr_str(xs: varargs[MalType]): MalType = |
4ce9e165 |
8 | str(xs.map(proc(x: MalType): string = x.pr_str(true)).join(" ")) |
819bd786 |
9 | |
10 | proc do_str(xs: varargs[MalType]): MalType = |
4ce9e165 |
11 | str(xs.map(proc(x: MalType): string = x.pr_str(false)).join) |
819bd786 |
12 | |
13 | proc prn(xs: varargs[MalType]): MalType = |
14 | echo xs.map(proc(x: MalType): string = x.pr_str(true)).join(" ") |
15 | result = nilObj |
16 | |
17 | proc println(xs: varargs[MalType]): MalType = |
18 | let line = xs.map(proc(x: MalType): string = x.pr_str(false)).join(" ") |
19 | echo line.replace("\\n", "\n") |
20 | result = nilObj |
21 | |
3603af96 |
22 | proc read_str(xs: varargs[MalType]): MalType = |
23 | read_str(xs[0].str) |
24 | |
8de9f308 |
25 | proc readline(xs: varargs[MalType]): MalType = |
26 | str readLineFromStdin(xs[0].str) |
27 | |
3603af96 |
28 | proc slurp(xs: varargs[MalType]): MalType = |
29 | str readFile(xs[0].str) |
30 | |
dc7f0b6a |
31 | proc cons(xs: varargs[MalType]): MalType = |
32 | result = list(xs[0]) |
33 | for x in xs[1].list: result.list.add x |
34 | |
35 | proc concat(xs: varargs[MalType]): MalType = |
36 | result = list() |
37 | for x in xs: |
38 | for i in x.list: |
39 | result.list.add i |
40 | |
f5cf5237 |
41 | proc nth(xs: varargs[MalType]): MalType = |
42 | if xs[1].number < xs[0].list.len: return xs[0].list[xs[1].number] |
43 | else: raise newException(ValueError, "nth: index out of range") |
44 | |
45 | proc first(xs: varargs[MalType]): MalType = |
4ce9e165 |
46 | if xs[0].kind in {List, Vector} and xs[0].list.len > 0: |
47 | xs[0].list[0] |
f5cf5237 |
48 | else: nilObj |
49 | |
50 | proc rest(xs: varargs[MalType]): MalType = |
4ce9e165 |
51 | if xs[0].kind in {List, Vector} and xs[0].list.len > 0: |
52 | list xs[0].list[1 .. -1] |
f5cf5237 |
53 | else: list() |
54 | |
8de9f308 |
55 | proc throw(xs: varargs[MalType]): MalType = |
56 | raise (ref MalError)(t: list xs) |
57 | |
58 | proc assoc(xs: varargs[MalType]): MalType = |
4ce9e165 |
59 | result = hash_map() |
2800f318 |
60 | result.hash_map = xs[0].hash_map |
8de9f308 |
61 | for i in countup(1, xs.high, 2): |
62 | result.hash_map[xs[i].str] = xs[i+1] |
63 | |
64 | proc dissoc(xs: varargs[MalType]): MalType = |
4ce9e165 |
65 | result = hash_map() |
2800f318 |
66 | result.hash_map = xs[0].hash_map |
8de9f308 |
67 | for i in 1 .. xs.high: |
68 | if result.hash_map.hasKey(xs[i].str): result.hash_map.del(xs[i].str) |
69 | |
70 | proc get(xs: varargs[MalType]): MalType = |
71 | if xs[0].kind == HashMap: |
2800f318 |
72 | result = xs[0].hash_map[xs[1].str] |
73 | if not result.isNil: return |
74 | |
75 | result = nilObj |
8de9f308 |
76 | |
77 | proc contains_q(xs: varargs[MalType]): MalType = |
78 | boolObj xs[0].hash_map.hasKey(xs[1].str) |
79 | |
80 | proc keys(xs: varargs[MalType]): MalType = |
81 | result = list() |
82 | for key in xs[0].hash_map.keys: |
83 | result.list.add str(key) |
84 | |
85 | proc vals(xs: varargs[MalType]): MalType = |
86 | result = list() |
87 | for value in xs[0].hash_map.values: |
88 | result.list.add value |
89 | |
90 | proc conj(xs: varargs[MalType]): MalType = |
91 | if xs[0].kind == List: |
92 | result = list() |
93 | for i in countdown(xs.high, 1): |
94 | result.list.add xs[i] |
95 | result.list.add xs[0].list |
96 | else: |
97 | result = vector() |
98 | result.list.add xs[0].list |
99 | for i in 1..xs.high: |
100 | result.list.add xs[i] |
101 | result.meta = xs[0].meta |
102 | |
103 | proc apply(xs: varargs[MalType]): MalType = |
104 | var s = newSeq[MalType]() |
105 | if xs.len > 2: |
106 | for j in 1 .. xs.high-1: |
107 | s.add xs[j] |
108 | s.add xs[xs.high].list |
109 | xs[0].getFun()(s) |
110 | |
111 | proc map(xs: varargs[MalType]): MalType = |
112 | result = list() |
113 | for i in 0 .. xs[1].list.high: |
114 | result.list.add xs[0].getFun()(xs[1].list[i]) |
115 | |
116 | proc with_meta(xs: varargs[MalType]): MalType = |
2800f318 |
117 | new result |
118 | result[] = xs[0][] |
119 | result.meta = xs[1] |
8de9f308 |
120 | |
121 | proc meta(xs: varargs[MalType]): MalType = |
2800f318 |
122 | if not xs[0].meta.isNil: xs[0].meta |
8de9f308 |
123 | else: nilObj |
124 | |
125 | proc deref(xs: varargs[MalType]): MalType = |
2800f318 |
126 | xs[0].val |
8de9f308 |
127 | |
128 | proc reset_bang(xs: varargs[MalType]): MalType = |
2800f318 |
129 | xs[0].val = xs[1] |
130 | result = xs[0].val |
8de9f308 |
131 | |
132 | proc swap_bang(xs: varargs[MalType]): MalType = |
2800f318 |
133 | var args = @[xs[0].val] |
8de9f308 |
134 | for i in 2 .. xs.high: |
135 | args.add xs[i] |
2800f318 |
136 | xs[0].val = xs[1].getFun()(args) |
137 | result = xs[0].val |
8de9f308 |
138 | |
4ce9e165 |
139 | proc time_ms(xs: varargs[MalType]): MalType = |
140 | number int(epochTime() * 1000) |
141 | |
819bd786 |
142 | template wrapNumberFun(op: expr): expr = |
8de9f308 |
143 | fun proc(xs: varargs[MalType]): MalType = |
144 | number op(xs[0].number, xs[1].number) |
819bd786 |
145 | |
146 | template wrapBoolFun(op: expr): expr = |
147 | fun proc(xs: varargs[MalType]): MalType = |
148 | if op(xs[0].number, xs[1].number): trueObj else: falseObj |
149 | |
150 | let ns* = { |
151 | "+": wrapNumberFun(`+`), |
152 | "-": wrapNumberFun(`-`), |
153 | "*": wrapNumberFun(`*`), |
154 | "/": wrapNumberFun(`div`), |
155 | |
156 | "<": wrapBoolFun(`<`), |
157 | "<=": wrapBoolFun(`<=`), |
158 | ">": wrapBoolFun(`>`), |
159 | ">=": wrapBoolFun(`>=`), |
160 | |
161 | "list": fun list, |
162 | "list?": fun list_q, |
163 | "vector": fun vector, |
164 | "vector?": fun vector_q, |
8de9f308 |
165 | "hash-map": fun hash_map, |
166 | "map?": fun hash_map_q, |
819bd786 |
167 | "empty?": fun empty_q, |
8de9f308 |
168 | "assoc": fun assoc, |
169 | "dissoc": fun dissoc, |
170 | "get": fun get, |
171 | "contains?": fun contains_q, |
172 | "keys": fun keys, |
173 | "vals": fun vals, |
174 | |
819bd786 |
175 | "=": fun equal, |
176 | |
177 | "pr-str": fun pr_str, |
178 | "str": fun do_str, |
179 | "prn": fun prn, |
180 | "println": fun println, |
3603af96 |
181 | |
182 | "read-string": fun read_str, |
8de9f308 |
183 | "readline": fun readline, |
3603af96 |
184 | "slurp": fun slurp, |
8de9f308 |
185 | |
186 | "sequential?": fun seq_q, |
dc7f0b6a |
187 | "cons": fun cons, |
188 | "concat": fun concat, |
8de9f308 |
189 | "count": fun count, |
f5cf5237 |
190 | "nth": fun nth, |
191 | "first": fun first, |
192 | "rest": fun rest, |
8de9f308 |
193 | "conj": fun conj, |
194 | "apply": fun apply, |
195 | "map": fun map, |
196 | |
197 | "throw": fun throw, |
198 | |
199 | "nil?": fun nil_q, |
200 | "true?": fun true_q, |
201 | "false?": fun false_q, |
202 | "symbol": fun symbol, |
203 | "symbol?": fun symbol_q, |
204 | "keyword": fun keyword, |
205 | "keyword?": fun keyword_q, |
206 | |
207 | "with-meta": fun with_meta, |
208 | "meta": fun meta, |
209 | "atom": fun atom, |
210 | "atom?": fun atom_q, |
211 | "deref": fun deref, |
212 | "reset!": fun reset_bang, |
213 | "swap!": fun swap_bang, |
4ce9e165 |
214 | |
215 | "time-ms": fun time_ms, |
819bd786 |
216 | } |