Merge pull request #387 from asarhaddon/test-macroexpand-no-quasiquote
[jackhill/mal.git] / skew / types.sk
CommitLineData
034e82ad
DM
1class MalError {
2 const message string
3}
4
5class MalUserError {
6 const data MalVal
7}
8
9class 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
26namespace 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
35class 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}
41const gNil = MalNil.new
42
43class 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}
48const gTrue = MalTrue.new
49
50class 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}
55const gFalse = MalFalse.new
56
57class 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
65class 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
74class 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
87class 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
96class 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
129class 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
141class 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
152class 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
195namespace 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
205class MalCallable : MalVal {
206 const func fn(List<MalVal>) MalVal
207 def call(args List<MalVal>) MalVal {
208 return func(args)
209 }
210}
211
212class 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
218class 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
240class 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}