hy, php, powershell, scala: Add number?, fn?, macro?
[jackhill/mal.git] / powershell / types.psm1
CommitLineData
f6146aef
JM
1#
2# Exceptions
3#
4Class MalException : Exception {
5 [Object] $object
6
7 MalException($obj) {
8 $this.object = $obj
9 }
10}
11
12function mal_throw($obj) {
13 throw [MalException] $obj
14}
15
16#
17# Symbols
18#
19
d7d197f9
JM
20Class 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 30function new-symbol([String] $val) {
d7d197f9
JM
31 [Symbol]::new($val)
32}
33
f6146aef
JM
34function symbol?($obj) {
35 $obj -is [Symbol]
36}
37
38#
39# Strings
40#
41
42function string?($obj) {
43 ($obj -is [String]) -and ($obj[0] -ne "$([char]0x29e)")
44}
45
46#
47# Keywords
48#
49
50function new-keyword($obj) {
51 if (keyword? $obj) {
52 $obj
53 } else {
54 "$([char]0x29e)$obj"
55 }
56}
57
58function keyword?($obj) {
59 ($obj -is [String]) -and ($obj[0] -eq "$([char]0x29e)")
60}
61
62
63#
64# Lists
65#
66
d7d197f9 67Class 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
115function 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
124function list?($obj) {
f6146aef
JM
125 $obj -is [List] -and -not ($obj -is [Vector])
126}
127
128
129#
130# Vectors
131#
132
133Class 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
150function new-vector([Object[]] $vals) {
151 if ($vals.Count -eq 0) {
152 return [Vector]::new()
153 } else {
154 return [Vector]::new($vals)
155 }
156}
157
158function vector?($obj) {
159 $obj -is [Vector]
160}
161
162
163#
164# HashMaps
165#
166
167Class 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
186function 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
194function dissoc_BANG($hm, $ks) {
195 $ht = $hm.values
196 foreach ($k in $ks) {
197 $ht.Remove($k)
198 }
199 return $hm
200}
201
202
203function new-hashmap([Object[]] $vals) {
204 $hm = [HashMap]::new()
205 assoc_BANG $hm $vals
206}
207
208function hashmap?($obj) {
209 $obj -is [HashMap]
210}
211
212function keys($hm) {
213 return new-list ($hm.values.GetEnumerator() | ForEach { $_.Key })
214}
215
216function vals($hm) {
217 return new-list ($hm.values.GetEnumerator() | ForEach { $_.Value })
218}
219
220
221#
222# Atoms
223
224Class Atom {
225 [Object] $value
226
227 Atom([Object] $val) {
228 $this.value = $val
229 }
230}
231
232function new-atom([Object] $val) {
233 [Atom]::new($val)
234}
235
236function atom?($obj) {
237 $obj -is [Atom]
238}
239
240
241# Functions
242
243Class 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
267function new-malfunc($ast, $params, $env, $fn, $macro, $meta) {
268 [MalFunc]::new($ast, $params, $env, $fn, $macro, $meta)
269}
270
271function malfunc?($obj) {
272 $obj -is [MalFunc]
273}
a58f416a
VS
274
275function fn?($obj) {
276 $obj -is [System.Management.Automation.ScriptBlock]
277}
f6146aef
JM
278#
279# General functions
280#
281function 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#
330function sequential?($obj) {
d7d197f9
JM
331 $obj -is [List]
332}
333
334function empty?($obj) {
335 $obj.values.Count -eq 0
336}
f6146aef
JM
337
338