1 import strutils, rdstdin, tables, times, sequtils, types, printer, reader
3 type MalError* = object of Exception
7 proc pr_str(xs: varargs[MalType]): MalType =
8 str(xs.map(proc(x: MalType): string = x.pr_str(true)).join(" "))
10 proc do_str(xs: varargs[MalType]): MalType =
11 str(xs.map(proc(x: MalType): string = x.pr_str(false)).join)
13 proc prn(xs: varargs[MalType]): MalType =
14 echo xs.map(proc(x: MalType): string = x.pr_str(true)).join(" ")
17 proc println(xs: varargs[MalType]): MalType =
18 echo xs.map(proc(x: MalType): string = x.pr_str(false)).join(" ")
21 proc read_str(xs: varargs[MalType]): MalType =
24 proc readline(xs: varargs[MalType]): MalType =
25 str readLineFromStdin(xs[0].str)
27 proc slurp(xs: varargs[MalType]): MalType =
28 str readFile(xs[0].str)
30 proc cons(xs: varargs[MalType]): MalType =
32 for x in xs[1].list: result.list.add x
34 proc concat(xs: varargs[MalType]): MalType =
40 proc nth(xs: varargs[MalType]): MalType =
41 if xs[1].number < xs[0].list.len: return xs[0].list[xs[1].number]
42 else: raise newException(ValueError, "nth: index out of range")
44 proc first(xs: varargs[MalType]): MalType =
45 if xs[0].kind in {List, Vector} and xs[0].list.len > 0:
49 proc rest(xs: varargs[MalType]): MalType =
50 if xs[0].kind in {List, Vector} and xs[0].list.len > 0:
51 list xs[0].list[1 .. ^1]
54 proc throw(xs: varargs[MalType]): MalType =
55 raise (ref MalError)(t: list xs)
57 proc assoc(xs: varargs[MalType]): MalType =
59 result.hash_map = xs[0].hash_map
60 for i in countup(1, xs.high, 2):
61 result.hash_map[xs[i].str] = xs[i+1]
63 proc dissoc(xs: varargs[MalType]): MalType =
65 result.hash_map = xs[0].hash_map
66 for i in 1 .. xs.high:
67 if result.hash_map.hasKey(xs[i].str): result.hash_map.del(xs[i].str)
69 proc get(xs: varargs[MalType]): MalType =
70 if xs[0].kind == HashMap:
71 if xs[1].str in xs[0].hash_map:
72 result = xs[0].hash_map[xs[1].str]
73 if not result.isNil: return
77 proc contains_q(xs: varargs[MalType]): MalType =
78 boolObj xs[0].hash_map.hasKey(xs[1].str)
80 proc keys(xs: varargs[MalType]): MalType =
82 for key in xs[0].hash_map.keys:
83 result.list.add str(key)
85 proc vals(xs: varargs[MalType]): MalType =
87 for value in xs[0].hash_map.values:
90 proc apply(xs: varargs[MalType]): MalType =
91 var s = newSeq[MalType]()
93 for j in 1 .. xs.high-1:
95 s.add xs[xs.high].list
98 proc map(xs: varargs[MalType]): MalType =
100 for i in 0 .. xs[1].list.high:
101 result.list.add xs[0].getFun()(xs[1].list[i])
103 proc conj(xs: varargs[MalType]): MalType =
104 if xs[0].kind == List:
106 for i in countdown(xs.high, 1):
107 result.list.add xs[i]
108 result.list.add xs[0].list
111 result.list.add xs[0].list
113 result.list.add xs[i]
114 result.meta = xs[0].meta
116 proc seq(xs: varargs[MalType]): MalType =
117 if xs[0].kind == List:
118 if len(xs[0].list) == 0: return nilObj
120 elif xs[0].kind == Vector:
121 if len(xs[0].list) == 0: return nilObj
123 result.list.add xs[0].list
124 elif xs[0].kind == String:
125 if len(xs[0].str) == 0: return nilObj
127 for i in countup(0, len(xs[0].str) - 1):
128 result.list.add(str xs[0].str.substr(i,i))
129 elif xs[0] == nilObj:
132 raise newException(ValueError, "seq: called on non-sequence")
134 proc with_meta(xs: varargs[MalType]): MalType =
139 proc meta(xs: varargs[MalType]): MalType =
140 if not xs[0].meta.isNil: xs[0].meta
143 proc deref(xs: varargs[MalType]): MalType =
146 proc reset_bang(xs: varargs[MalType]): MalType =
150 proc swap_bang(xs: varargs[MalType]): MalType =
151 var args = @[xs[0].val]
152 for i in 2 .. xs.high:
154 xs[0].val = xs[1].getFun()(args)
157 proc time_ms(xs: varargs[MalType]): MalType =
158 number int(epochTime() * 1000)
160 template wrapNumberFun(op): untyped =
161 fun proc(xs: varargs[MalType]): MalType =
162 number op(xs[0].number, xs[1].number)
164 template wrapBoolFun(op): untyped =
165 fun proc(xs: varargs[MalType]): MalType =
166 if op(xs[0].number, xs[1].number): trueObj else: falseObj
169 "+": wrapNumberFun(`+`),
170 "-": wrapNumberFun(`-`),
171 "*": wrapNumberFun(`*`),
172 "/": wrapNumberFun(`div`),
174 "<": wrapBoolFun(`<`),
175 "<=": wrapBoolFun(`<=`),
176 ">": wrapBoolFun(`>`),
177 ">=": wrapBoolFun(`>=`),
181 "vector": fun vector,
182 "vector?": fun vector_q,
183 "hash-map": fun hash_map,
184 "map?": fun hash_map_q,
185 "empty?": fun empty_q,
187 "dissoc": fun dissoc,
189 "contains?": fun contains_q,
195 "pr-str": fun pr_str,
198 "println": fun println,
200 "read-string": fun read_str,
201 "readline": fun readline,
204 "sequential?": fun seq_q,
206 "concat": fun concat,
221 "false?": fun false_q,
222 "string?": fun string_q,
223 "symbol": fun symbol,
224 "symbol?": fun symbol_q,
225 "keyword": fun keyword,
226 "keyword?": fun keyword_q,
227 "number?": fun number_q,
229 "macro?": fun macro_q,
231 "with-meta": fun with_meta,
236 "reset!": fun reset_bang,
237 "swap!": fun swap_bang,
239 "time-ms": fun time_ms,