Commit | Line | Data |
---|---|---|
034e82ad DM |
1 | class MalError { |
2 | const message string | |
3 | } | |
4 | ||
5 | class MalUserError { | |
6 | const data MalVal | |
7 | } | |
8 | ||
9 | class MalVal { | |
10 | var _meta MalVal = gNil | |
11 | def toHashKey string { throw MalError.new("Not allowed as hash map key") } | |
12 | def print(readable bool) string | |
13 | def equal(o MalVal) bool | |
14 | def isSymbol(name string) bool { return false } | |
15 | def seq MalVal { throw MalError.new("seq: called on non-sequence") } | |
16 | def meta MalVal { return _meta } | |
17 | def _setMeta(newMeta MalVal) { _meta = newMeta } | |
18 | def withMeta(newMeta MalVal) MalVal { | |
19 | var res = self.clone | |
20 | res._setMeta(newMeta) | |
21 | return res | |
22 | } | |
23 | def clone MalVal | |
24 | } | |
25 | ||
26 | namespace MalVal { | |
27 | def fromHashKey(key string) MalVal { | |
28 | if key.startsWith("S_") { return MalString.new(key.slice(2)) } | |
29 | else if key.startsWith("K_") { return MalKeyword.new(key.slice(2)) } | |
30 | else { throw "Illegal hash key string" } | |
31 | } | |
32 | def fromBool(b bool) MalVal { return b ? gTrue : gFalse } | |
33 | } | |
34 | ||
35 | class MalNil : MalVal { | |
36 | over print(readable bool) string { return "nil" } | |
37 | over equal(o MalVal) bool { return o is MalNil } | |
38 | over seq MalVal { return gNil } | |
39 | over clone MalVal { return self } | |
40 | } | |
41 | const gNil = MalNil.new | |
42 | ||
43 | class MalTrue : MalVal { | |
44 | over print(readable bool) string { return "true" } | |
45 | over equal(o MalVal) bool { return o is MalTrue } | |
46 | over clone MalVal { return self } | |
47 | } | |
48 | const gTrue = MalTrue.new | |
49 | ||
50 | class MalFalse : MalVal { | |
51 | over print(readable bool) string { return "false" } | |
52 | over equal(o MalVal) bool { return o is MalFalse } | |
53 | over clone MalVal { return self } | |
54 | } | |
55 | const gFalse = MalFalse.new | |
56 | ||
57 | class MalNumber : MalVal { | |
58 | const _data int | |
59 | over print(readable bool) string { return _data.toString } | |
60 | def val int { return _data } | |
61 | over equal(o MalVal) bool { return o is MalNumber && (o as MalNumber).val == val } | |
62 | over clone MalVal { return self } | |
63 | } | |
64 | ||
65 | class MalSymbol : MalVal { | |
66 | const _data string | |
67 | over print(readable bool) string { return _data } | |
68 | def val string { return _data } | |
69 | over equal(o MalVal) bool { return o is MalSymbol && (o as MalSymbol).val == val } | |
70 | over isSymbol(name string) bool { return _data == name } | |
71 | over clone MalVal { return MalSymbol.new(_data) } | |
72 | } | |
73 | ||
74 | class MalString : MalVal { | |
75 | const _data string | |
76 | over print(readable bool) string { return readable ? "\"\(escaped_data)\"" : _data } | |
77 | over toHashKey string { return "S_\(_data)" } | |
78 | def val string { return _data } | |
79 | over equal(o MalVal) bool { return o is MalString && (o as MalString).val == val } | |
80 | def escaped_data string { | |
81 | return _data.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"").replaceAll("\n", "\\n") | |
82 | } | |
83 | over seq MalVal { return _data.count == 0 ? gNil : MalList.new(_data.split("").map<MalVal>(e => MalString.new(e))) } | |
84 | over clone MalVal { return MalString.new(_data) } | |
85 | } | |
86 | ||
87 | class MalKeyword : MalVal { | |
88 | const _data string | |
89 | over print(readable bool) string { return ":\(_data)" } | |
90 | over toHashKey string { return "K_\(_data)" } | |
91 | def val string { return _data } | |
92 | over equal(o MalVal) bool { return o is MalKeyword && (o as MalKeyword).val == val } | |
93 | over clone MalVal { return MalKeyword.new(_data) } | |
94 | } | |
95 | ||
96 | class MalSequential : MalVal { | |
97 | const _data List<MalVal> | |
98 | def val List<MalVal> { return _data } | |
99 | def isEmpty bool { return _data.isEmpty } | |
100 | def asOneString(readable bool) string { | |
101 | return " ".join(_data.map<string>(v => v.print(readable))) | |
102 | } | |
103 | def count int { return _data.count } | |
104 | def [](index int) MalVal { return _data[index] } | |
105 | over equal(o MalVal) bool { | |
106 | if !(o is MalSequential) { return false } | |
107 | const oval = (o as MalSequential).val | |
108 | if val.count != oval.count { return false } | |
109 | for i in 0..val.count { | |
110 | if !val[i].equal(oval[i]) { return false } | |
111 | } | |
112 | return true | |
113 | } | |
114 | def nth(position int) MalVal { | |
115 | if position >= count { throw MalError.new("nth: index out of range") } | |
116 | return val[position] | |
117 | } | |
118 | def first MalVal { | |
119 | if isEmpty { return gNil } | |
120 | return val[0] | |
121 | } | |
122 | def rest MalVal { | |
123 | if isEmpty { return MalList.new([]) } | |
124 | return MalList.new(val.slice(1)) | |
125 | } | |
126 | def conj(args List<MalVal>) MalVal | |
127 | } | |
128 | ||
129 | class MalList : MalSequential { | |
130 | over print(readable bool) string { return "(" + asOneString(readable) + ")" } | |
131 | over seq MalVal { return isEmpty ? gNil : self } | |
132 | over conj(args List<MalVal>) MalVal { | |
133 | var res = args.clone | |
134 | res.reverse | |
135 | res.append(_data) | |
136 | return MalList.new(res) | |
137 | } | |
138 | over clone MalVal { return MalList.new(_data) } | |
139 | } | |
140 | ||
141 | class MalVector : MalSequential { | |
142 | over print(readable bool) string { return "[" + asOneString(readable) + "]" } | |
143 | over seq MalVal { return isEmpty ? gNil : MalList.new(_data) } | |
144 | over conj(args List<MalVal>) MalVal { | |
145 | var res = _data.clone | |
146 | res.append(args) | |
147 | return MalVector.new(res) | |
148 | } | |
149 | over clone MalVal { return MalVector.new(_data) } | |
150 | } | |
151 | ||
152 | class MalHashMap : MalVal { | |
153 | const _data StringMap<MalVal> | |
154 | over print(readable bool) string { | |
155 | var pairs List<string> = [] | |
156 | _data.each((k string, v MalVal) => pairs.append("\(MalVal.fromHashKey(k).print(readable)) \(v.print(readable))")) | |
157 | return "{" + " ".join(pairs) + "}" | |
158 | } | |
159 | def val StringMap<MalVal> { return _data } | |
160 | over equal(o MalVal) bool { | |
161 | if !(o is MalHashMap) { return false } | |
162 | const oh = o as MalHashMap | |
163 | if oh.val.count != val.count { return false } | |
164 | var allEqual = true | |
165 | _data.each((k string, v MalVal) => { | |
166 | if !(k in oh.val) || !(v.equal(oh.val[k])) { | |
167 | allEqual = false | |
168 | } | |
169 | }) | |
170 | return allEqual | |
171 | } | |
172 | def assoc(kv_list List<MalVal>) MalVal { | |
173 | var new_data = _data.clone | |
174 | for i = 0; i < kv_list.count; i += 2 { | |
175 | new_data[kv_list[i].toHashKey] = kv_list[i + 1] | |
176 | } | |
177 | return MalHashMap.new(new_data) | |
178 | } | |
179 | def dissoc(keys List<MalVal>) MalVal { | |
180 | var new_data = _data.clone | |
181 | for key in keys { | |
182 | new_data.remove(key.toHashKey) | |
183 | } | |
184 | return MalHashMap.new(new_data) | |
185 | } | |
186 | def get(key MalVal) MalVal { return _data.get(key.toHashKey, gNil) } | |
187 | def contains(key MalVal) bool { return key.toHashKey in _data } | |
188 | def keys List<MalVal> { | |
189 | return _data.keys.map<MalVal>(k => MalVal.fromHashKey(k)) | |
190 | } | |
191 | def vals List<MalVal> { return _data.values } | |
192 | over clone MalVal { return MalHashMap.new(_data) } | |
193 | } | |
194 | ||
195 | namespace MalHashMap { | |
196 | def fromList(kv_list List<MalVal>) MalHashMap { | |
197 | var result StringMap<MalVal> = {} | |
198 | for i = 0; i < kv_list.count; i += 2 { | |
199 | result[kv_list[i].toHashKey] = kv_list[i + 1] | |
200 | } | |
201 | return MalHashMap.new(result) | |
202 | } | |
203 | } | |
204 | ||
205 | class MalCallable : MalVal { | |
206 | const func fn(List<MalVal>) MalVal | |
207 | def call(args List<MalVal>) MalVal { | |
208 | return func(args) | |
209 | } | |
210 | } | |
211 | ||
212 | class MalNativeFunc : MalCallable { | |
213 | over print(readable bool) string { return "#<NativeFunction>" } | |
214 | over equal(o MalVal) bool { return false } | |
215 | over clone MalVal { return MalNativeFunc.new(func) } | |
216 | } | |
217 | ||
218 | class MalFunc : MalCallable { | |
219 | const ast MalVal | |
220 | const params MalSequential | |
221 | const env Env | |
222 | var _macro bool = false | |
223 | def new(aAst MalVal, aParams MalSequential, aEnv Env, aFunc fn(List<MalVal>) MalVal) { | |
224 | super(aFunc) | |
225 | ast = aAst | |
226 | params = aParams | |
227 | env = aEnv | |
228 | } | |
229 | def isMacro bool { return _macro } | |
230 | def setAsMacro { _macro = true } | |
231 | over print(readable bool) string { return "#<Function args=" + params.print(true) + ">" } | |
232 | over equal(o MalVal) bool { return false } | |
233 | over clone MalVal { | |
234 | var f = MalFunc.new(ast, params, env, func) | |
235 | if isMacro { f.setAsMacro } | |
236 | return f | |
237 | } | |
238 | } | |
239 | ||
240 | class MalAtom : MalVal { | |
241 | var _data MalVal | |
242 | over print(readable bool) string { return "(atom \(_data.print(readable)))" } | |
243 | def val MalVal { return _data } | |
244 | over equal(o MalVal) bool { return o is MalAtom && val.equal((o as MalAtom).val) } | |
245 | def resetBang(newData MalVal) MalVal { | |
246 | _data = newData | |
247 | return _data | |
248 | } | |
249 | over clone MalVal { return MalAtom.new(_data) } | |
250 | } |