Commit | Line | Data |
---|---|---|
f6146aef JM |
1 | # |
2 | # Exceptions | |
3 | # | |
4 | Class MalException : Exception { | |
5 | [Object] $object | |
6 | ||
7 | MalException($obj) { | |
8 | $this.object = $obj | |
9 | } | |
10 | } | |
11 | ||
12 | function mal_throw($obj) { | |
13 | throw [MalException] $obj | |
14 | } | |
15 | ||
16 | # | |
17 | # Symbols | |
18 | # | |
19 | ||
d7d197f9 JM |
20 | Class Symbol { |
21 | [String] $value | |
22 | ||
23 | Symbol([String] $val) { | |
24 | $this.value = $val | |
25 | } | |
f6146aef JM |
26 | |
27 | copy() { $this } | |
d7d197f9 JM |
28 | } |
29 | ||
f6146aef | 30 | function new-symbol([String] $val) { |
d7d197f9 JM |
31 | [Symbol]::new($val) |
32 | } | |
33 | ||
f6146aef JM |
34 | function symbol?($obj) { |
35 | $obj -is [Symbol] | |
36 | } | |
37 | ||
38 | # | |
39 | # Strings | |
40 | # | |
41 | ||
42 | function string?($obj) { | |
43 | ($obj -is [String]) -and ($obj[0] -ne "$([char]0x29e)") | |
44 | } | |
45 | ||
46 | # | |
47 | # Keywords | |
48 | # | |
49 | ||
50 | function new-keyword($obj) { | |
51 | if (keyword? $obj) { | |
52 | $obj | |
53 | } else { | |
54 | "$([char]0x29e)$obj" | |
55 | } | |
56 | } | |
57 | ||
58 | function keyword?($obj) { | |
59 | ($obj -is [String]) -and ($obj[0] -eq "$([char]0x29e)") | |
60 | } | |
61 | ||
62 | ||
63 | # | |
64 | # Lists | |
65 | # | |
66 | ||
d7d197f9 | 67 | Class List { |
f6146aef | 68 | #[System.Collections.ArrayList] $values |
d7d197f9 | 69 | [Object[]] $values |
f6146aef JM |
70 | [Object] $meta |
71 | ||
72 | List() { | |
73 | $this.values = @() | |
74 | #$this.values = New-Object System.Collections.ArrayList | |
75 | } | |
d7d197f9 JM |
76 | |
77 | List([Object[]] $vals) { | |
f6146aef | 78 | #List([System.Collections.ArrayList] $vals) { |
d7d197f9 JM |
79 | $this.values = $vals |
80 | } | |
81 | ||
f6146aef JM |
82 | [List] copy() { |
83 | return [List]::new($this.values) | |
84 | } | |
85 | ||
d7d197f9 | 86 | [void] push([Object] $val) { |
f6146aef | 87 | $this.values.Add($val) |
d7d197f9 JM |
88 | } |
89 | ||
90 | [Object] first() { | |
91 | return $this.values[0] | |
92 | } | |
93 | ||
f6146aef JM |
94 | [List] rest() { |
95 | if ($this.values.Count -le 1) { | |
96 | return [List]::new(@()) | |
97 | } else { | |
98 | return [List]::new($this.values[1..($this.values.Count)]) | |
99 | } | |
100 | } | |
101 | ||
102 | [Object] last() { | |
103 | if ($this.values.Count -eq 0) { | |
104 | return $null | |
105 | } else { | |
106 | return $this.values[$this.values.Count-1] | |
107 | } | |
d7d197f9 JM |
108 | } |
109 | ||
f6146aef | 110 | [Object] nth([int64] $idx) { |
d7d197f9 JM |
111 | return $this.values[$idx] |
112 | } | |
113 | } | |
114 | ||
115 | function new-list([Object[]] $vals) { | |
f6146aef JM |
116 | #function new-list([System.Collections.ArrayList] $vals) { |
117 | if ($vals.Count -eq 0) { | |
118 | return [List]::new() | |
119 | } else { | |
120 | return [List]::new($vals) | |
121 | } | |
d7d197f9 JM |
122 | } |
123 | ||
124 | function list?($obj) { | |
f6146aef JM |
125 | $obj -is [List] -and -not ($obj -is [Vector]) |
126 | } | |
127 | ||
128 | ||
129 | # | |
130 | # Vectors | |
131 | # | |
132 | ||
133 | Class Vector : List { | |
134 | Vector() { | |
135 | $this.values = @() | |
136 | #$this.values = New-Object System.Collections.ArrayList | |
137 | } | |
138 | ||
139 | Vector([Object[]] $vals) { | |
140 | #Vector([System.Collections.ArrayList] $vals) { | |
141 | $this.values = $vals | |
142 | } | |
143 | ||
144 | [Vector] copy() { | |
145 | return [Vector]::new($this.values) | |
146 | } | |
147 | ||
148 | } | |
149 | ||
150 | function new-vector([Object[]] $vals) { | |
151 | if ($vals.Count -eq 0) { | |
152 | return [Vector]::new() | |
153 | } else { | |
154 | return [Vector]::new($vals) | |
155 | } | |
156 | } | |
157 | ||
158 | function vector?($obj) { | |
159 | $obj -is [Vector] | |
160 | } | |
161 | ||
162 | ||
163 | # | |
164 | # HashMaps | |
165 | # | |
166 | ||
167 | Class HashMap { | |
168 | [Hashtable] $values | |
169 | [Object] $meta | |
170 | ||
171 | HashMap() { | |
172 | # Case-sensitive hashtable | |
173 | $this.values = New-Object System.Collections.HashTable | |
174 | } | |
175 | ||
176 | HashMap([Hashtable] $vals) { | |
177 | $this.values = $vals | |
178 | } | |
179 | ||
180 | [HashMap] copy() { | |
181 | return [HashMap]::new($this.values.clone()) | |
182 | } | |
183 | ||
184 | } | |
185 | ||
186 | function assoc_BANG($hm, $kvs) { | |
187 | $ht = $hm.values | |
188 | for ($i = 0; $i -lt $kvs.Count; $i+=2) { | |
189 | $ht[$kvs[$i]] = $kvs[($i+1)] | |
190 | } | |
191 | return $hm | |
192 | } | |
193 | ||
194 | function dissoc_BANG($hm, $ks) { | |
195 | $ht = $hm.values | |
196 | foreach ($k in $ks) { | |
197 | $ht.Remove($k) | |
198 | } | |
199 | return $hm | |
200 | } | |
201 | ||
202 | ||
203 | function new-hashmap([Object[]] $vals) { | |
204 | $hm = [HashMap]::new() | |
205 | assoc_BANG $hm $vals | |
206 | } | |
207 | ||
208 | function hashmap?($obj) { | |
209 | $obj -is [HashMap] | |
210 | } | |
211 | ||
212 | function keys($hm) { | |
213 | return new-list ($hm.values.GetEnumerator() | ForEach { $_.Key }) | |
214 | } | |
215 | ||
216 | function vals($hm) { | |
217 | return new-list ($hm.values.GetEnumerator() | ForEach { $_.Value }) | |
218 | } | |
219 | ||
220 | ||
221 | # | |
222 | # Atoms | |
223 | ||
224 | Class Atom { | |
225 | [Object] $value | |
226 | ||
227 | Atom([Object] $val) { | |
228 | $this.value = $val | |
229 | } | |
230 | } | |
231 | ||
232 | function new-atom([Object] $val) { | |
233 | [Atom]::new($val) | |
234 | } | |
235 | ||
236 | function atom?($obj) { | |
237 | $obj -is [Atom] | |
238 | } | |
239 | ||
240 | ||
241 | # Functions | |
242 | ||
243 | Class MalFunc { | |
244 | [Object] $ast | |
245 | [Object[]] $params | |
246 | [Object] $env | |
247 | [scriptBlock] $fn | |
248 | [Boolean] $macro | |
249 | [Object] $meta | |
250 | ||
251 | MalFunc($ast, $params, $env, $fn, $macro, $meta){ | |
252 | $this.ast = $ast | |
253 | $this.params = $params | |
254 | $this.env = $env | |
255 | $this.fn = $fn | |
256 | $this.macro = $macro | |
257 | $this.meta = $meta | |
258 | } | |
259 | ||
260 | [MalFunc] copy() { | |
261 | return [MalFunc]::new($this.ast, $this.params, $this.env, $this.fn, | |
262 | $this.macro, $this.meta) | |
263 | } | |
264 | ||
265 | } | |
266 | ||
267 | function new-malfunc($ast, $params, $env, $fn, $macro, $meta) { | |
268 | [MalFunc]::new($ast, $params, $env, $fn, $macro, $meta) | |
269 | } | |
270 | ||
271 | function malfunc?($obj) { | |
272 | $obj -is [MalFunc] | |
273 | } | |
a58f416a VS |
274 | |
275 | function fn?($obj) { | |
276 | $obj -is [System.Management.Automation.ScriptBlock] | |
277 | } | |
f6146aef JM |
278 | # |
279 | # General functions | |
280 | # | |
281 | function equal?($a, $b) { | |
282 | if ($a -eq $null -and $b -eq $null) { | |
283 | return $true | |
284 | } elseif ($a -eq $null -or $b -eq $null) { | |
285 | return $false | |
286 | } | |
287 | $ta, $tb = $a.GetType().Name, $b.GetType().Name | |
288 | if (-not (($ta -eq $tb) -or ((sequential?($a)) -and (sequential?($b))))) { | |
289 | return $false | |
290 | } | |
291 | switch ($ta) { | |
292 | { $_ -eq "List" -or $_ -eq "Vector" } { | |
293 | if ($a.values.Count -ne $b.values.Count) { | |
294 | return $false | |
295 | } | |
296 | for ($i = 0; $i -lt $a.value.Count; $i++) { | |
297 | if (-not (equal? $a.values[$i] $b.values[$i])) { | |
298 | return $false | |
299 | } | |
300 | } | |
301 | return $true | |
302 | } | |
303 | "HashMap" { | |
304 | $hta, $htb = $a.values, $b.values | |
305 | $alen = ($hta.GetEnumerator | Measure-Object).Count | |
306 | $blen = ($htb.GetEnumerator | Measure-Object).Count | |
307 | if ($alen -ne $blen) { | |
308 | return $false | |
309 | } | |
310 | foreach ($kv in $hta.GetEnumerator()) { | |
311 | if (-not (equal? $kv.Value $htb[$kv.Key])) { | |
312 | return $false | |
313 | } | |
314 | } | |
315 | return $true | |
316 | } | |
317 | "Symbol" { | |
318 | return $a.value -ceq $b.value | |
319 | } | |
320 | default { | |
321 | return $a -ceq $b | |
322 | } | |
323 | } | |
324 | } | |
325 | ||
326 | ||
327 | # | |
328 | # Sequence functions | |
329 | # | |
330 | function sequential?($obj) { | |
d7d197f9 JM |
331 | $obj -is [List] |
332 | } | |
333 | ||
334 | function empty?($obj) { | |
335 | $obj.values.Count -eq 0 | |
336 | } | |
f6146aef JM |
337 | |
338 |