Finished metadata
[jackhill/mal.git] / kotlin / src / mal / types.kt
CommitLineData
53c2ea70
JFI
1package mal
2
3import java.util.*
4
041bb7eb 5// TODO clean up exception hierarchy
8337e32c
JFI
6open 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
14class MalContinue() : MalException("continue") { }
15class MalReaderException(message: String) : MalException(message) { }
16class MalPrinterException(message: String) : MalException(message) { }
8337e32c
JFI
17class 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 25interface MalType {
8337e32c
JFI
26 var metadata: MalType // TODO make immutable
27 fun with_meta(meta: MalType): MalType
53c2ea70
JFI
28}
29
30open 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
43class 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 61class 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
73open 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
81class 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
89interface ILambda : MalType {
90 fun apply(seq: ISeq): MalType
91}
92
ac8e072f 93open 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
107class 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
115interface 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
125interface IMutableSeq : ISeq {
126 fun conj_BANG(form: MalType)
127}
128
129class 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
149class 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
185class 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 217class 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
239val NIL = MalConstant("nil")
240val TRUE = MalConstant("true")
241val FALSE = MalConstant("false")
26f0b60f 242val ZERO = MalInteger(0)