Commit | Line | Data |
---|---|---|
53c2ea70 JFI |
1 | package mal |
2 | ||
4121b4ee JFI |
3 | import java.io.File |
4 | ||
53c2ea70 JFI |
5 | val ns = hashMapOf( |
6 | Pair(MalSymbol("+"), MalFunction({ a: ISeq -> a.seq().reduce({ x, y -> x as MalInteger + y as MalInteger }) })), | |
7 | Pair(MalSymbol("-"), MalFunction({ a: ISeq -> a.seq().reduce({ x, y -> x as MalInteger - y as MalInteger }) })), | |
8 | Pair(MalSymbol("*"), MalFunction({ a: ISeq -> a.seq().reduce({ x, y -> x as MalInteger * y as MalInteger }) })), | |
9 | Pair(MalSymbol("/"), MalFunction({ a: ISeq -> a.seq().reduce({ x, y -> x as MalInteger / y as MalInteger }) })), | |
10 | ||
11 | Pair(MalSymbol("list"), MalFunction({ a: ISeq -> MalList(a) })), | |
12 | Pair(MalSymbol("list?"), MalFunction({ a: ISeq -> if (a.first() is MalList) TRUE else FALSE })), | |
13 | Pair(MalSymbol("empty?"), MalFunction({ | |
14 | a: ISeq -> if (a.first() !is ISeq || !(a.first() as ISeq).seq().any()) TRUE else FALSE | |
15 | })), | |
16 | Pair(MalSymbol("count"), MalFunction({ | |
17 | a: ISeq -> if (a.first() is ISeq) MalInteger((a.first() as ISeq).seq().count()) else MalInteger(0) | |
18 | })), | |
19 | ||
20 | Pair(MalSymbol("="), MalFunction({ a: ISeq -> pairwiseEquals(a) })), | |
21 | Pair(MalSymbol("<"), MalFunction({ a: ISeq -> pairwise(a, { x, y -> x.value < y.value }) })), | |
22 | Pair(MalSymbol("<="), MalFunction({ a: ISeq -> pairwise(a, { x, y -> x.value <= y.value }) })), | |
23 | Pair(MalSymbol(">"), MalFunction({ a: ISeq -> pairwise(a, { x, y -> x.value > y.value }) })), | |
24 | Pair(MalSymbol(">="), MalFunction({ a: ISeq -> pairwise(a, { x, y -> x.value >= y.value }) })), | |
25 | ||
26 | Pair(MalSymbol("pr-str"), MalFunction({ | |
27 | a: ISeq -> MalString(a.seq().map({ it -> pr_str(it, print_readably = true) }).joinToString(" ")) | |
28 | })), | |
29 | Pair(MalSymbol("str"), MalFunction({ | |
30 | a: ISeq -> MalString(a.seq().map({ it -> pr_str(it, print_readably = false) }).joinToString("")) | |
31 | })), | |
32 | Pair(MalSymbol("prn"), MalFunction({ | |
33 | a: ISeq -> println(a.seq().map({ it -> pr_str(it, print_readably = true) }).joinToString(" ")); NIL | |
34 | })), | |
35 | Pair(MalSymbol("println"), MalFunction({ | |
36 | a: ISeq -> println(a.seq().map({ it -> pr_str(it, print_readably = false) }).joinToString(" ")); NIL | |
4121b4ee JFI |
37 | })), |
38 | ||
39 | Pair(MalSymbol("read-string"), MalFunction({ a: ISeq -> | |
40 | val string = a.first() as? MalString ?: throw MalException("slurp requires a string parameter") | |
41 | read_str(string.value) | |
42 | })), | |
43 | Pair(MalSymbol("slurp"), MalFunction({ a: ISeq -> | |
44 | val name = a.first() as? MalString ?: throw MalException("slurp requires a filename parameter") | |
45 | val text = File(name.value).readText() | |
46 | MalString(text) | |
940bb6ff JFI |
47 | })), |
48 | ||
49 | Pair(MalSymbol("cons"), MalFunction({ a: ISeq -> | |
50 | val list = a.nth(1) as? ISeq ?: throw MalException("cons requires a list as its second parameter") | |
51 | val mutableList = list.seq().toLinkedList() | |
52 | mutableList.addFirst(a.nth(0)) | |
53 | MalList(mutableList) | |
54 | })), | |
55 | Pair(MalSymbol("concat"), MalFunction({ a: ISeq -> | |
56 | MalList(a.seq().flatMap({ it -> (it as ISeq).seq() }).toLinkedList()) | |
d8e5df5d JFI |
57 | })), |
58 | ||
59 | Pair(MalSymbol("nth"), MalFunction({ a: ISeq -> | |
60 | val list = a.nth(0) as? ISeq ?: throw MalException("nth requires a list as its first parameter") | |
61 | val index = a.nth(1) as? MalInteger ?: throw MalException("nth requires an integer as its second parameter") | |
62 | if (index.value >= list.seq().count()) throw MalException("index out of bounds") | |
63 | list.nth(index.value) | |
64 | })), | |
65 | Pair(MalSymbol("first"), MalFunction({ a: ISeq -> | |
66 | if (a.nth(0) == NIL) NIL | |
67 | else { | |
68 | val list = a.nth(0) as? ISeq ?: throw MalException("first requires a list parameter") | |
69 | if (list.seq().any()) list.first() else NIL | |
70 | } | |
71 | })), | |
72 | Pair(MalSymbol("rest"), MalFunction({ a: ISeq -> | |
73 | val list = a.nth(0) as? ISeq ?: throw MalException("rest requires a list parameter") | |
74 | MalList(list.rest()) | |
041bb7eb JFI |
75 | })), |
76 | ||
77 | Pair(MalSymbol("throw"), MalFunction({ a: ISeq -> | |
78 | val throwable = a.nth(0) | |
79 | throw MalCoreException(pr_str(throwable), throwable) | |
80 | })), | |
81 | ||
82 | Pair(MalSymbol("apply"), MalFunction({ a: ISeq -> | |
83 | val function = a.nth(0) as MalFunction | |
84 | val params = MalList() | |
85 | a.seq().drop(1).forEach({ it -> | |
86 | if (it is ISeq) { | |
87 | it.seq().forEach({ x -> params.conj_BANG(x) }) | |
88 | } else { | |
89 | params.conj_BANG(it) | |
90 | } | |
91 | }) | |
92 | function.apply(params) | |
93 | })), | |
94 | ||
95 | Pair(MalSymbol("map"), MalFunction({ a: ISeq -> | |
96 | val function = a.nth(0) as MalFunction | |
97 | MalList((a.nth(1) as ISeq).seq().map({ it -> | |
98 | val params = MalList() | |
99 | params.conj_BANG(it) | |
100 | function.apply(params) | |
101 | }).toLinkedList()) | |
102 | })), | |
103 | ||
104 | Pair(MalSymbol("nil?"), MalFunction({ a: ISeq -> if (a.nth(0) == NIL) TRUE else FALSE })), | |
105 | Pair(MalSymbol("true?"), MalFunction({ a: ISeq -> if (a.nth(0) == TRUE) TRUE else FALSE })), | |
106 | Pair(MalSymbol("false?"), MalFunction({ a: ISeq -> if (a.nth(0) == FALSE) TRUE else FALSE })), | |
107 | Pair(MalSymbol("symbol?"), MalFunction({ a: ISeq -> if (a.nth(0) is MalSymbol) TRUE else FALSE })), | |
108 | ||
109 | Pair(MalSymbol("symbol"), MalFunction({ a: ISeq -> MalSymbol((a.nth(0) as MalString).value) })), | |
110 | Pair(MalSymbol("keyword"), MalFunction({ a: ISeq -> | |
111 | val param = a.nth(0) | |
112 | if (param is MalKeyword) param else MalKeyword((a.nth(0) as MalString).value) | |
113 | })), | |
114 | Pair(MalSymbol("keyword?"), MalFunction({ a: ISeq -> if (a.nth(0) is MalKeyword) TRUE else FALSE })), | |
115 | Pair(MalSymbol("vector"), MalFunction({ a: ISeq -> MalVector(a) })), | |
116 | Pair(MalSymbol("vector?"), MalFunction({ a: ISeq -> if (a.nth(0) is MalVector) TRUE else FALSE })), | |
117 | ||
26f0b60f JFI |
118 | Pair(MalSymbol("hash-map"), MalFunction({ a: ISeq -> |
119 | val map = MalHashMap() | |
120 | val (keys, vals) = a.seq().withIndex().partition({ it -> it.index % 2 == 0 }) | |
121 | keys.map({ it -> it.value as MalString }).zip(vals.map({ it -> it.value })).forEach({ it -> | |
122 | map.assoc_BANG(it.first, it.second) | |
123 | }) | |
124 | map | |
125 | })), | |
041bb7eb | 126 | Pair(MalSymbol("map?"), MalFunction({ a: ISeq -> if (a.nth(0) is MalHashMap) TRUE else FALSE })), |
26f0b60f JFI |
127 | Pair(MalSymbol("assoc"), MalFunction({ a: ISeq -> |
128 | val map = MalHashMap(a.nth(0) as MalHashMap) | |
129 | val (keys, vals) = a.seq().drop(1).withIndex().partition({ it -> it.index % 2 == 0 }) | |
130 | keys.map({ it -> it.value as MalString }).zip(vals.map({ it -> it.value })).forEach({ it -> | |
131 | map.assoc_BANG(it.first, it.second) | |
132 | }) | |
133 | map | |
134 | })), | |
135 | Pair(MalSymbol("dissoc"), MalFunction({ a: ISeq -> | |
136 | val map = MalHashMap(a.nth(0) as MalHashMap) | |
137 | a.seq().drop(1).forEach({ it -> map.dissoc_BANG(it as MalString) }) | |
138 | map | |
139 | })), | |
140 | Pair(MalSymbol("get"), MalFunction({ a: ISeq -> | |
141 | val map = a.nth(0) as? MalHashMap | |
142 | val key = a.nth(1) as MalString | |
143 | map?.elements?.get(key) ?: NIL | |
144 | })), | |
145 | Pair(MalSymbol("contains?"), MalFunction({ a: ISeq -> | |
146 | val map = a.nth(0) as? MalHashMap | |
147 | val key = a.nth(1) as MalString | |
148 | if (map?.elements?.get(key) != null) TRUE else FALSE | |
149 | })), | |
150 | Pair(MalSymbol("keys"), MalFunction({ a: ISeq -> | |
151 | val map = a.nth(0) as MalHashMap | |
152 | // Another situation where kotlinc breaks if I don't add this unnecessary cast | |
153 | MalList(map.elements.keys.map({ it -> it as MalType }).asSequence().toLinkedList()) | |
154 | })), | |
155 | Pair(MalSymbol("vals"), MalFunction({ a: ISeq -> | |
156 | val map = a.nth(0) as MalHashMap | |
157 | MalList(map.elements.values.asSequence().toLinkedList()) | |
158 | })), | |
159 | Pair(MalSymbol("count"), MalFunction({ a: ISeq -> | |
160 | val seq = a.nth(0) as? ISeq | |
161 | if (seq != null) MalInteger(seq.seq().count()) else ZERO | |
162 | })), | |
041bb7eb | 163 | Pair(MalSymbol("sequential?"), MalFunction({ a: ISeq -> if (a.nth(0) is ISeq) TRUE else FALSE })) |
53c2ea70 JFI |
164 | ) |
165 | ||
166 | fun pairwiseEquals(s: ISeq): MalConstant = | |
167 | if (s.seq().zip(s.seq().drop(1)).all({ it -> it.first == it.second })) TRUE else FALSE | |
168 | ||
169 | fun pairwise(s: ISeq, pred: (MalInteger, MalInteger) -> Boolean): MalConstant = | |
170 | if (s.seq().zip(s.seq().drop(1)).all({ | |
171 | it -> pred(it.first as MalInteger, it.second as MalInteger) | |
172 | })) TRUE else FALSE |