Commit | Line | Data |
---|---|---|
53c2ea70 JFI |
1 | package mal |
2 | ||
3 | import java.util.* | |
4 | ||
041bb7eb | 5 | // TODO clean up exception hierarchy |
8337e32c JFI |
6 | open class MalException(message: String?) : Exception(message), MalType { |
7 | override var metadata: MalType = NIL | |
8 | override fun with_meta(meta: MalType): MalType { | |
9 | val exception = MalException(message) | |
10 | exception.metadata = meta | |
11 | return exception | |
12 | } | |
13 | } | |
53c2ea70 JFI |
14 | class MalContinue() : MalException("continue") { } |
15 | class MalReaderException(message: String) : MalException(message) { } | |
16 | class MalPrinterException(message: String) : MalException(message) { } | |
8337e32c JFI |
17 | class MalCoreException(message: String, val value: MalType) : MalException(message) { // TODO rename |
18 | override fun with_meta(meta: MalType): MalType { | |
19 | val exception = MalCoreException(message as String, value) | |
20 | exception.metadata = meta | |
21 | return exception | |
22 | } | |
23 | } | |
041bb7eb | 24 | |
53c2ea70 | 25 | interface MalType { |
8337e32c JFI |
26 | var metadata: MalType // TODO make immutable |
27 | fun with_meta(meta: MalType): MalType | |
53c2ea70 JFI |
28 | } |
29 | ||
30 | open class MalConstant(val value: String) : MalType { | |
8337e32c JFI |
31 | override var metadata: MalType = NIL |
32 | ||
53c2ea70 | 33 | override fun equals(other: Any?): Boolean = other is MalConstant && value.equals(other.value) |
26f0b60f | 34 | override fun hashCode(): Int = value.hashCode() |
8337e32c JFI |
35 | |
36 | override fun with_meta(meta: MalType): MalType { | |
37 | val obj = MalConstant(value) | |
38 | obj.metadata = meta | |
39 | return obj | |
40 | } | |
53c2ea70 JFI |
41 | } |
42 | ||
43 | class MalInteger(val value: Int) : MalType { | |
8337e32c JFI |
44 | override var metadata: MalType = NIL |
45 | ||
53c2ea70 JFI |
46 | operator fun plus(a: MalInteger): MalInteger = MalInteger(value + a.value) |
47 | operator fun minus(a: MalInteger): MalInteger = MalInteger(value - a.value) | |
48 | operator fun times(a: MalInteger): MalInteger = MalInteger(value * a.value) | |
49 | operator fun div(a: MalInteger): MalInteger = MalInteger(value / a.value) | |
50 | operator fun compareTo(a: MalInteger): Int = value.compareTo(a.value) | |
51 | ||
52 | override fun equals(other: Any?): Boolean = other is MalInteger && value.equals(other.value) | |
8337e32c JFI |
53 | |
54 | override fun with_meta(meta: MalType): MalType { | |
55 | val obj = MalInteger(value) | |
56 | obj.metadata = meta | |
57 | return obj | |
58 | } | |
53c2ea70 JFI |
59 | } |
60 | ||
940bb6ff | 61 | class MalSymbol(val value: String) : MalType { |
8337e32c JFI |
62 | override var metadata: MalType = NIL |
63 | ||
940bb6ff | 64 | override fun equals(other: Any?): Boolean = other is MalSymbol && value.equals(other.value) |
8337e32c JFI |
65 | |
66 | override fun with_meta(meta: MalType): MalType { | |
67 | val obj = MalSymbol(value) | |
68 | obj.metadata = meta | |
69 | return obj | |
70 | } | |
940bb6ff | 71 | } |
53c2ea70 | 72 | |
8337e32c JFI |
73 | open class MalString(value: String) : MalConstant(value) { |
74 | override fun with_meta(meta: MalType): MalType { | |
75 | val obj = MalString(value) | |
76 | obj.metadata = meta | |
77 | return obj | |
78 | } | |
79 | } | |
53c2ea70 | 80 | |
8337e32c JFI |
81 | class MalKeyword(value: String) : MalString("\u029E" + value) { |
82 | override fun with_meta(meta: MalType): MalType { | |
83 | val obj = MalKeyword(value) | |
84 | obj.metadata = meta | |
85 | return obj | |
86 | } | |
87 | } | |
53c2ea70 JFI |
88 | |
89 | interface ILambda : MalType { | |
90 | fun apply(seq: ISeq): MalType | |
91 | } | |
92 | ||
ac8e072f | 93 | open class MalFunction(val lambda: (ISeq) -> MalType) : MalType, ILambda { |
2ec7fa0b | 94 | // TODO make this stuff immutable? |
d8e5df5d | 95 | var is_macro: Boolean = false |
8337e32c | 96 | override var metadata: MalType = NIL |
d8e5df5d | 97 | |
53c2ea70 | 98 | override fun apply(seq: ISeq): MalType = lambda(seq) |
8337e32c JFI |
99 | |
100 | override fun with_meta(meta: MalType): MalType { | |
101 | val obj = MalFunction(lambda) | |
102 | obj.metadata = meta | |
103 | return obj | |
104 | } | |
53c2ea70 JFI |
105 | } |
106 | ||
8337e32c JFI |
107 | class MalFnFunction(val ast: MalType, val params: Sequence<MalSymbol>, val env: Env, lambda: (ISeq) -> MalType) : MalFunction(lambda) { |
108 | override fun with_meta(meta: MalType): MalType { | |
109 | val obj = MalFnFunction(ast, params, env, lambda) | |
110 | obj.metadata = meta | |
111 | return obj | |
112 | } | |
113 | } | |
ac8e072f | 114 | |
53c2ea70 JFI |
115 | interface ISeq : MalType { |
116 | fun seq(): Sequence<MalType> | |
117 | fun first(): MalType | |
118 | fun rest(): ISeq | |
119 | fun nth(n: Int): MalType | |
ac8e072f | 120 | fun slice(fromIndex: Int, toIndex: Int): ISeq |
2ec7fa0b | 121 | fun conj(s: ISeq): ISeq |
53c2ea70 JFI |
122 | } |
123 | ||
2ec7fa0b | 124 | // TODO could we get rid of this and make conj work on immutables? |
53c2ea70 JFI |
125 | interface IMutableSeq : ISeq { |
126 | fun conj_BANG(form: MalType) | |
127 | } | |
128 | ||
129 | class MalSequence(val elements : Sequence<MalType>) : MalType, ISeq { | |
8337e32c JFI |
130 | override var metadata: MalType = NIL |
131 | ||
53c2ea70 JFI |
132 | override fun seq(): Sequence<MalType> = elements |
133 | override fun first(): MalType = elements.first() | |
134 | override fun rest(): ISeq = MalSequence(elements.drop(1)) | |
135 | override fun nth(n: Int): MalType = elements.elementAt(n) | |
ac8e072f JFI |
136 | |
137 | override fun slice(fromIndex: Int, toIndex: Int): MalList = | |
138 | MalList(elements.toLinkedList().subList(fromIndex, toIndex)) | |
2ec7fa0b JFI |
139 | |
140 | override fun conj(s: ISeq): ISeq = MalList(elements.toLinkedList()).conj(s) | |
8337e32c JFI |
141 | |
142 | override fun with_meta(meta: MalType): MalType { | |
143 | val obj = MalSequence(elements) | |
144 | obj.metadata = meta | |
145 | return obj | |
146 | } | |
53c2ea70 JFI |
147 | } |
148 | ||
149 | class MalList(val elements: MutableList<MalType>) : MalType, IMutableSeq { | |
8337e32c JFI |
150 | override var metadata: MalType = NIL |
151 | ||
53c2ea70 JFI |
152 | constructor() : this(LinkedList<MalType>()) |
153 | constructor(s: ISeq) : this(s.seq().toLinkedList()) | |
154 | ||
155 | override fun seq(): Sequence<MalType> = elements.asSequence() | |
156 | override fun first(): MalType = elements.first() | |
157 | override fun rest(): ISeq = MalSequence(elements.drop(1).asSequence()) | |
158 | override fun nth(n: Int): MalType = elements.elementAt(n) | |
159 | ||
160 | override fun conj_BANG(form: MalType) { | |
161 | elements.add(form) | |
162 | } | |
163 | ||
164 | override fun equals(other: Any?): Boolean = | |
165 | (other is ISeq) | |
166 | && elements.size == other.seq().count() // TODO optimize counting? | |
167 | && elements.asSequence().zip(other.seq()).all({ it -> it.first == it.second }) | |
ac8e072f JFI |
168 | |
169 | override fun slice(fromIndex: Int, toIndex: Int): MalList = | |
170 | MalList(elements.subList(fromIndex, toIndex)) | |
2ec7fa0b JFI |
171 | |
172 | override fun conj(s: ISeq): ISeq { | |
173 | val list = LinkedList<MalType>(elements) | |
174 | s.seq().forEach({ it -> list.addFirst(it) }) | |
175 | return MalList(list) | |
176 | } | |
8337e32c JFI |
177 | |
178 | override fun with_meta(meta: MalType): MalType { | |
179 | val obj = MalList(elements) | |
180 | obj.metadata = meta | |
181 | return obj | |
182 | } | |
53c2ea70 JFI |
183 | } |
184 | ||
185 | class MalVector(val elements: MutableList<MalType>) : MalType, IMutableSeq { | |
8337e32c JFI |
186 | override var metadata: MalType = NIL |
187 | ||
53c2ea70 JFI |
188 | constructor() : this(ArrayList<MalType>()) |
189 | constructor(s: ISeq) : this(s.seq().toArrayList()) | |
190 | ||
191 | override fun seq(): Sequence<MalType> = elements.asSequence() | |
192 | override fun first(): MalType = elements.first() | |
193 | override fun rest(): ISeq = MalSequence(elements.drop(1).asSequence()) | |
194 | override fun nth(n: Int): MalType = elements.elementAt(n) | |
195 | ||
196 | override fun conj_BANG(form: MalType) { | |
197 | elements.add(form) | |
198 | } | |
199 | ||
200 | override fun equals(other: Any?): Boolean = | |
201 | (other is ISeq) | |
202 | && elements.size == other.seq().count() // TODO optimize counting? | |
203 | && elements.asSequence().zip(other.seq()).all({ it -> it.first == it.second }) | |
ac8e072f JFI |
204 | |
205 | override fun slice(fromIndex: Int, toIndex: Int): MalVector = | |
206 | MalVector(elements.subList(fromIndex, toIndex)) | |
2ec7fa0b JFI |
207 | |
208 | override fun conj(s: ISeq): ISeq = MalVector(elements.plus(s.seq()).toArrayList()) | |
8337e32c JFI |
209 | |
210 | override fun with_meta(meta: MalType): MalType { | |
211 | val obj = MalVector(elements) | |
212 | obj.metadata = meta | |
213 | return obj | |
214 | } | |
53c2ea70 JFI |
215 | } |
216 | ||
26f0b60f | 217 | class MalHashMap() : MalType { |
8337e32c JFI |
218 | override var metadata: MalType = NIL |
219 | ||
53c2ea70 JFI |
220 | val elements = HashMap<MalString, MalType>() |
221 | ||
26f0b60f JFI |
222 | constructor(other: MalHashMap) : this() { |
223 | other.elements.forEach({ it -> assoc_BANG(it.key, it.value) }) | |
224 | } | |
225 | ||
53c2ea70 | 226 | fun assoc_BANG(key: MalString, value: MalType) = elements.put(key, value) |
26f0b60f JFI |
227 | fun dissoc_BANG(key: MalString) { |
228 | elements.remove(key) | |
229 | } | |
8337e32c JFI |
230 | |
231 | override fun with_meta(meta: MalType): MalType { | |
232 | val obj = MalHashMap(this) | |
233 | obj.metadata = meta | |
234 | return obj | |
235 | } | |
53c2ea70 JFI |
236 | } |
237 | ||
238 | // TODO add truthiness checking | |
239 | val NIL = MalConstant("nil") | |
240 | val TRUE = MalConstant("true") | |
241 | val FALSE = MalConstant("false") | |
26f0b60f | 242 | val ZERO = MalInteger(0) |