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