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() |
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() |
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: |
72 | xs[0].hash_map[xs[1].str] |
73 | else: |
74 | nilObj |
75 | |
76 | proc contains_q(xs: varargs[MalType]): MalType = |
77 | boolObj xs[0].hash_map.hasKey(xs[1].str) |
78 | |
79 | proc keys(xs: varargs[MalType]): MalType = |
80 | result = list() |
81 | for key in xs[0].hash_map.keys: |
82 | result.list.add str(key) |
83 | |
84 | proc vals(xs: varargs[MalType]): MalType = |
85 | result = list() |
86 | for value in xs[0].hash_map.values: |
87 | result.list.add value |
88 | |
89 | proc conj(xs: varargs[MalType]): MalType = |
90 | if xs[0].kind == List: |
91 | result = list() |
92 | for i in countdown(xs.high, 1): |
93 | result.list.add xs[i] |
94 | result.list.add xs[0].list |
95 | else: |
96 | result = vector() |
97 | result.list.add xs[0].list |
98 | for i in 1..xs.high: |
99 | result.list.add xs[i] |
100 | result.meta = xs[0].meta |
101 | |
102 | proc apply(xs: varargs[MalType]): MalType = |
103 | var s = newSeq[MalType]() |
104 | if xs.len > 2: |
105 | for j in 1 .. xs.high-1: |
106 | s.add xs[j] |
107 | s.add xs[xs.high].list |
108 | xs[0].getFun()(s) |
109 | |
110 | proc map(xs: varargs[MalType]): MalType = |
111 | result = list() |
112 | for i in 0 .. xs[1].list.high: |
113 | result.list.add xs[0].getFun()(xs[1].list[i]) |
114 | |
115 | proc with_meta(xs: varargs[MalType]): MalType = |
116 | result = xs[0] |
117 | new result.meta |
118 | result.meta[] = xs[1] |
119 | |
120 | proc meta(xs: varargs[MalType]): MalType = |
121 | if xs[0].meta != nil: xs[0].meta[] |
122 | else: nilObj |
123 | |
124 | proc deref(xs: varargs[MalType]): MalType = |
125 | xs[0].val[] |
126 | |
127 | proc reset_bang(xs: varargs[MalType]): MalType = |
128 | xs[0].val[] = xs[1] |
129 | result = xs[0].val[] |
130 | |
131 | proc swap_bang(xs: varargs[MalType]): MalType = |
132 | var args = @[xs[0].val[]] |
133 | for i in 2 .. xs.high: |
134 | args.add xs[i] |
135 | xs[0].val[] = xs[1].getFun()(args) |
136 | result = xs[0].val[] |
137 | |
4ce9e165 |
138 | proc time_ms(xs: varargs[MalType]): MalType = |
139 | number int(epochTime() * 1000) |
140 | |
819bd786 |
141 | template wrapNumberFun(op: expr): expr = |
8de9f308 |
142 | fun proc(xs: varargs[MalType]): MalType = |
143 | number op(xs[0].number, xs[1].number) |
819bd786 |
144 | |
145 | template wrapBoolFun(op: expr): expr = |
146 | fun proc(xs: varargs[MalType]): MalType = |
147 | if op(xs[0].number, xs[1].number): trueObj else: falseObj |
148 | |
149 | let ns* = { |
150 | "+": wrapNumberFun(`+`), |
151 | "-": wrapNumberFun(`-`), |
152 | "*": wrapNumberFun(`*`), |
153 | "/": wrapNumberFun(`div`), |
154 | |
155 | "<": wrapBoolFun(`<`), |
156 | "<=": wrapBoolFun(`<=`), |
157 | ">": wrapBoolFun(`>`), |
158 | ">=": wrapBoolFun(`>=`), |
159 | |
160 | "list": fun list, |
161 | "list?": fun list_q, |
162 | "vector": fun vector, |
163 | "vector?": fun vector_q, |
8de9f308 |
164 | "hash-map": fun hash_map, |
165 | "map?": fun hash_map_q, |
819bd786 |
166 | "empty?": fun empty_q, |
8de9f308 |
167 | "assoc": fun assoc, |
168 | "dissoc": fun dissoc, |
169 | "get": fun get, |
170 | "contains?": fun contains_q, |
171 | "keys": fun keys, |
172 | "vals": fun vals, |
173 | |
819bd786 |
174 | "=": fun equal, |
175 | |
176 | "pr-str": fun pr_str, |
177 | "str": fun do_str, |
178 | "prn": fun prn, |
179 | "println": fun println, |
3603af96 |
180 | |
181 | "read-string": fun read_str, |
8de9f308 |
182 | "readline": fun readline, |
3603af96 |
183 | "slurp": fun slurp, |
8de9f308 |
184 | |
185 | "sequential?": fun seq_q, |
dc7f0b6a |
186 | "cons": fun cons, |
187 | "concat": fun concat, |
8de9f308 |
188 | "count": fun count, |
f5cf5237 |
189 | "nth": fun nth, |
190 | "first": fun first, |
191 | "rest": fun rest, |
8de9f308 |
192 | "conj": fun conj, |
193 | "apply": fun apply, |
194 | "map": fun map, |
195 | |
196 | "throw": fun throw, |
197 | |
198 | "nil?": fun nil_q, |
199 | "true?": fun true_q, |
200 | "false?": fun false_q, |
201 | "symbol": fun symbol, |
202 | "symbol?": fun symbol_q, |
203 | "keyword": fun keyword, |
204 | "keyword?": fun keyword_q, |
205 | |
206 | "with-meta": fun with_meta, |
207 | "meta": fun meta, |
208 | "atom": fun atom, |
209 | "atom?": fun atom_q, |
210 | "deref": fun deref, |
211 | "reset!": fun reset_bang, |
212 | "swap!": fun swap_bang, |
4ce9e165 |
213 | |
214 | "time-ms": fun time_ms, |
819bd786 |
215 | } |