1
2
3
4
5
6
7
8
9
10 scenario convert-lambda [
11 run [
12 ¦ local-scope
13 ¦ 1:text/raw <- lambda-to-mu [(add a (multiply b c))]
14 ¦ 2:@:char/raw <- copy *1:text/raw
15 ]
16 memory-should-contain [
17 ¦ 2:array:character <- [t1 <- multiply b c
18 result <- add a t1]
19 ]
20 ]
21
22 def lambda-to-mu in:text -> out:text [
23 local-scope
24 load-ingredients
25 out <- copy 0
26 cells:&:cell <- parse in
27 out <- to-mu cells
28 ]
29
30
31 exclusive-container cell [
32 atom:text
33 pair:pair
34 ]
35
36
37 container pair [
38 first:&:cell
39 rest:&:cell
40 ]
41
42 def new-atom name:text -> result:&:cell [
43 local-scope
44 load-ingredients
45 result <- new cell:type
46 *result <- merge 0/tag:atom, name
47 ]
48
49 def new-pair a:&:cell, b:&:cell -> result:&:cell [
50 local-scope
51 load-ingredients
52 result <- new cell:type
53 *result <- merge 1/tag:pair, a/first, b/rest
54 ]
55
56 def is-atom? x:&:cell -> result:bool [
57 local-scope
58 load-ingredients
59 return-unless x, 0/false
60 _, result <- maybe-convert *x, atom:variant
61 ]
62
63 def is-pair? x:&:cell -> result:bool [
64 local-scope
65 load-ingredients
66 return-unless x, 0/false
67 _, result <- maybe-convert *x, pair:variant
68 ]
69
70 scenario atom-is-not-pair [
71 local-scope
72 s:text <- new [a]
73 x:&:cell <- new-atom s
74 10:bool/raw <- is-atom? x
75 11:bool/raw <- is-pair? x
76 memory-should-contain [
77 ¦ 10 <- 1
78 ¦ 11 <- 0
79 ]
80 ]
81
82 scenario pair-is-not-atom [
83 local-scope
84
85 s:text <- new [a]
86 x:&:cell <- new-atom s
87 y:&:cell <- new-pair x, 0/nil
88 10:bool/raw <- is-atom? y
89 11:bool/raw <- is-pair? y
90 memory-should-contain [
91 ¦ 10 <- 0
92 ¦ 11 <- 1
93 ]
94 ]
95
96 def atom-match? x:&:cell, pat:text -> result:bool [
97 local-scope
98 load-ingredients
99 s:text, is-atom?:bool <- maybe-convert *x, atom:variant
100 return-unless is-atom?, 0/false
101 result <- equal pat, s
102 ]
103
104 scenario atom-match [
105 local-scope
106 x:&:cell <- new-atom [abc]
107 10:bool/raw <- atom-match? x, [abc]
108 memory-should-contain [
109 ¦ 10 <- 1
110 ]
111 ]
112
113 def first x:&:cell -> result:&:cell [
114 local-scope
115 load-ingredients
116 pair:pair, pair?:bool <- maybe-convert *x, pair:variant
117 return-unless pair?, 0/nil
118 result <- get pair, first:offset
119 ]
120
121 def rest x:&:cell -> result:&:cell [
122 local-scope
123 load-ingredients
124 pair:pair, pair?:bool <- maybe-convert *x, pair:variant
125 return-unless pair?, 0/nil
126 result <- get pair, rest:offset
127 ]
128
129 def set-first base:&:cell, new-first:&:cell -> base:&:cell [
130 local-scope
131 load-ingredients
132 pair:pair, is-pair?:bool <- maybe-convert *base, pair:variant
133 return-unless is-pair?
134 pair <- put pair, first:offset, new-first
135 *base <- merge 1/pair, pair
136 ]
137
138 def set-rest base:&:cell, new-rest:&:cell -> base:&:cell [
139 local-scope
140 load-ingredients
141 pair:pair, is-pair?:bool <- maybe-convert *base, pair:variant
142 return-unless is-pair?
143 pair <- put pair, rest:offset, new-rest
144 *base <- merge 1/pair, pair
145 ]
146
147 scenario cell-operations-on-atom [
148 local-scope
149 s:text <- new [a]
150 x:&:cell <- new-atom s
151 10:&:cell/raw <- first x
152 11:&:cell/raw <- rest x
153 memory-should-contain [
154 ¦ 10 <- 0
155 ¦ 11 <- 0
156 ]
157 ]
158
159 scenario cell-operations-on-pair [
160 local-scope
161
162 s:text <- new [a]
163 x:&:cell <- new-atom s
164 y:&:cell <- new-pair x, 0/nil
165 x2:&:cell <- first y
166 10:bool/raw <- equal x, x2
167 11:&:cell/raw <- rest y
168 memory-should-contain [
169 ¦ 10 <- 1
170 ¦ 11 <- 0
171 ]
172 ]
173
174
175
176 def parse in:text -> out:&:cell [
177 local-scope
178 load-ingredients
179 s:&:stream:char <- new-stream in
180 out, s <- parse s
181 trace 2, [app/parse], out
182 ]
183
184 def parse in:&:stream:char -> out:&:cell, in:&:stream:char [
185 local-scope
186 load-ingredients
187
188 in <- skip-whitespace in
189 c:char, eof?:bool <- peek in
190 return-if eof?, 0/nil
191 pair?:bool <- equal c, 40/open-paren
192 {
193 ¦ break-if pair?
194 ¦
195 ¦ buf:&:buffer <- new-buffer 30
196 ¦ {
197 ¦ ¦ done?:bool <- end-of-stream? in
198 ¦ ¦ break-if done?
199 ¦ ¦
200 ¦ ¦ c:char <- peek in
201 ¦ ¦ done? <- equal c, 41/close-paren
202 ¦ ¦ break-if done?
203 ¦ ¦ done? <- space? c
204 ¦ ¦ break-if done?
205 ¦ ¦ c <- read in
206 ¦ ¦ buf <- append buf, c
207 ¦ ¦ loop
208 ¦ }
209 ¦ s:text <- buffer-to-array buf
210 ¦ out <- new-atom s
211 }
212 {
213 ¦ break-unless pair?
214 ¦
215 ¦ read in
216 ¦ out <- new cell:type
217 ¦
218 ¦ {
219 ¦ ¦ end?:bool <- end-of-stream? in
220 ¦ ¦ not-end?:bool <- not end?
221 ¦ ¦ assert not-end?, [unbalanced '(' in expression]
222 ¦ ¦ c <- peek in
223 ¦ ¦ close-paren?:bool <- equal c, 41/close-paren
224 ¦ ¦ break-if close-paren?
225 ¦ ¦ first:&:cell, in <- parse in
226 ¦ ¦ *out <- merge 1/pair, first, 0/nil
227 ¦ }
228 ¦
229 ¦ curr:&:cell <- copy out
230 ¦ {
231 ¦ ¦ in <- skip-whitespace in
232 ¦ ¦ end?:bool <- end-of-stream? in
233 ¦ ¦ not-end?:bool <- not end?
234 ¦ ¦ assert not-end?, [unbalanced '(' in expression]
235 ¦ ¦
236 ¦ ¦ c <- peek in
237 ¦ ¦ {
238 ¦ ¦ ¦ close-paren?:bool <- equal c, 41/close-paren
239 ¦ ¦ ¦ break-unless close-paren?
240 ¦ ¦ ¦ read in
241 ¦ ¦ ¦ break +end-pair
242 ¦ ¦ }
243 ¦ ¦
244 ¦ ¦ next:&:cell, in <- parse in
245 ¦ ¦ is-dot?:bool <- atom-match? next, [.]
246 ¦ ¦ {
247 ¦ ¦ ¦ break-if is-dot?
248 ¦ ¦ ¦ next-curr:&:cell <- new-pair next, 0/nil
249 ¦ ¦ ¦ curr <- set-rest curr, next-curr
250 ¦ ¦ ¦ curr <- rest curr
251 ¦ ¦ }
252 ¦ ¦ {
253 ¦ ¦ ¦ break-unless is-dot?
254 ¦ ¦ ¦
255 ¦ ¦ ¦ in <- skip-whitespace in
256 ¦ ¦ ¦ c <- peek in
257 ¦ ¦ ¦ not-close-paren?:bool <- not-equal c, 41/close-paren
258 ¦ ¦ ¦ assert not-close-paren?, [')' cannot immediately follow '.']
259 ¦ ¦ ¦ final:&:cell <- parse in
260 ¦ ¦ ¦ curr <- set-rest curr, final
261 ¦ ¦ ¦
262 ¦ ¦ ¦
263 ¦ ¦ ¦ in <- skip-whitespace in
264 ¦ ¦ ¦ c <- peek in
265 ¦ ¦ ¦ close-paren?:bool <- equal c, 41/close-paren
266 ¦ ¦ ¦ assert close-paren?, ['.' must be followed by exactly one expression before ')']
267 ¦ ¦ }
268 ¦ ¦ loop
269 ¦ }
270 ¦ +end-pair
271 }
272 ]
273
274 def skip-whitespace in:&:stream:char -> in:&:stream:char [
275 local-scope
276 load-ingredients
277 {
278 ¦ done?:bool <- end-of-stream? in
279 ¦ return-if done?, 0/null
280 ¦ c:char <- peek in
281 ¦ space?:bool <- space? c
282 ¦ break-unless space?
283 ¦ read in
284 ¦ loop
285 }
286 ]
287
288 def to-text x:&:cell -> out:text [
289 local-scope
290 load-ingredients
291 buf:&:buffer <- new-buffer 30
292 buf <- to-buffer x, buf
293 out <- buffer-to-array buf
294 ]
295
296 def to-buffer x:&:cell, buf:&:buffer -> buf:&:buffer [
297 local-scope
298 load-ingredients
299
300 {
301 ¦ break-if x
302 ¦ buf <- append buf, [<>]
303 ¦ return
304 }
305
306 {
307 ¦ s:text, atom?:bool <- maybe-convert *x, atom:variant
308 ¦ break-unless atom?
309 ¦ buf <- append buf, s
310 ¦ return
311 }
312
313 buf <- append buf, [< ]
314 first:&:cell <- first x
315 buf <- to-buffer first, buf
316 buf <- append buf, [ | ]
317 rest:&:cell <- rest x
318 buf <- to-buffer rest, buf
319 buf <- append buf, [ >]
320 ]
321
322 scenario parse-single-letter-atom [
323 local-scope
324 s:text <- new [a]
325 x:&:cell <- parse s
326 s2:text, 10:bool/raw <- maybe-convert *x, atom:variant
327 11:@:char/raw <- copy *s2
328 memory-should-contain [
329 ¦ 10 <- 1
330 ¦ 11:array:character <- [a]
331 ]
332 ]
333
334 scenario parse-atom [
335 local-scope
336 s:text <- new [abc]
337 x:&:cell <- parse s
338 s2:text, 10:bool/raw <- maybe-convert *x, atom:variant
339 11:@:char/raw <- copy *s2
340 memory-should-contain [
341 ¦ 10 <- 1
342 ¦ 11:array:character <- [abc]
343 ]
344 ]
345
346 scenario parse-list-of-two-atoms [
347 local-scope
348 s:text <- new [(abc def)]
349 x:&:cell <- parse s
350 trace-should-contain [
351 ¦ app/parse: < abc | < def | <> > >
352 ]
353 10:bool/raw <- is-pair? x
354 x1:&:cell <- first x
355 x2:&:cell <- rest x
356 s1:text, 11:bool/raw <- maybe-convert *x1, atom:variant
357 12:bool/raw <- is-pair? x2
358 x3:&:cell <- first x2
359 s2:text, 13:bool/raw <- maybe-convert *x3, atom:variant
360 14:&:cell/raw <- rest x2
361 20:@:char/raw <- copy *s1
362 30:@:char/raw <- copy *s2
363 memory-should-contain [
364 ¦ 10 <- 1
365 ¦ 11 <- 1
366 ¦ 12 <- 1
367 ¦ 13 <- 1
368 ¦ 14 <- 0
369 ¦ 20:array:character <- [abc]
370 ¦ 30:array:character <- [def]
371 ]
372 ]
373
374 scenario parse-list-with-extra-spaces [
375 local-scope
376 s:text <- new [ ( abc def ) ]
377 x:&:cell <- parse s
378 trace-should-contain [
379 ¦ app/parse: < abc | < def | <> > >
380 ]
381 10:bool/raw <- is-pair? x
382 x1:&:cell <- first x
383 x2:&:cell <- rest x
384 s1:text, 11:bool/raw <- maybe-convert *x1, atom:variant
385 12:bool/raw <- is-pair? x2
386 x3:&:cell <- first x2
387 s2:text, 13:bool/raw <- maybe-convert *x3, atom:variant
388 14:&:cell/raw <- rest x2
389 20:@:char/raw <- copy *s1
390 30:@:char/raw <- copy *s2
391 memory-should-contain [
392 ¦ 10 <- 1
393 ¦ 11 <- 1
394 ¦ 12 <- 1
395 ¦ 13 <- 1
396 ¦ 14 <- 0
397 ¦ 20:array:character <- [abc]
398 ¦ 30:array:character <- [def]
399 ]
400 ]
401
402 scenario parse-list-of-more-than-two-atoms [
403 local-scope
404 s:text <- new [(abc def ghi)]
405 x:&:cell <- parse s
406 trace-should-contain [
407 ¦ app/parse: < abc | < def | < ghi | <> > > >
408 ]
409 10:bool/raw <- is-pair? x
410 x1:&:cell <- first x
411 x2:&:cell <- rest x
412 s1:text, 11:bool/raw <- maybe-convert *x1, atom:variant
413 12:bool/raw <- is-pair? x2
414 x3:&:cell <- first x2
415 s2:text, 13:bool/raw <- maybe-convert *x3, atom:variant
416 x4:&:cell <- rest x2
417 14:bool/raw <- is-pair? x4
418 x5:&:cell <- first x4
419 s3:text, 15:bool/raw <- maybe-convert *x5, atom:variant
420 16:&:cell/raw <- rest x4
421 20:@:char/raw <- copy *s1
422 30:@:char/raw <- copy *s2
423 40:@:char/raw <- copy *s3
424 memory-should-contain [
425 ¦ 10 <- 1
426 ¦ 11 <- 1
427 ¦ 12 <- 1
428 ¦ 13 <- 1
429 ¦ 14 <- 1
430 ¦ 15 <- 1
431 ¦ 16 <- 0
432 ¦ 20:array:character <- [abc]
433 ¦ 30:array:character <- [def]
434 ¦ 40:array:character <- [ghi]
435 ]
436 ]
437
438 scenario parse-nested-list [
439 local-scope
440 s:text <- new [((abc))]
441 x:&:cell <- parse s
442 trace-should-contain [
443 ¦ app/parse: < < abc | <> > | <> >
444 ]
445 10:bool/raw <- is-pair? x
446 x1:&:cell <- first x
447 11:bool/raw <- is-pair? x
448 x2:&:cell <- first x1
449 s1:text, 12:bool/raw <- maybe-convert *x2, atom:variant
450 13:&:cell/raw <- rest x1
451 14:&:cell/raw <- rest x
452 20:@:char/raw <- copy *s1
453 memory-should-contain [
454 ¦ 10 <- 1
455 ¦ 11 <- 1
456 ¦ 12 <- 1
457 ¦ 13 <- 0
458 ¦ 14 <- 0
459 ¦ 20:array:character <- [abc]
460 ]
461 ]
462
463 scenario parse-nested-list-2 [
464 local-scope
465 s:text <- new [((abc) def)]
466 x:&:cell <- parse s
467 trace-should-contain [
468 ¦ app/parse: < < abc | <> > | < def | <> > >
469 ]
470 10:bool/raw <- is-pair? x
471 x1:&:cell <- first x
472 11:bool/raw <- is-pair? x
473 x2:&:cell <- first x1
474 s1:text, 12:bool/raw <- maybe-convert *x2, atom:variant
475 13:&:cell/raw <- rest x1
476 x3:&:cell <- rest x
477 x4:&:cell <- first x3
478 s2:text, 14:bool/raw <- maybe-convert *x4, atom:variant
479 15:&:cell/raw <- rest x3
480 20:@:char/raw <- copy *s1
481 30:@:char/raw <- copy *s2
482 memory-should-contain [
483 ¦ 10 <- 1
484 ¦ 11 <- 1
485 ¦ 12 <- 1
486 ¦ 13 <- 0
487 ¦ 14 <- 1
488 ¦ 15 <- 0
489 ¦ 20:array:character <- [abc]
490 ¦ 30:array:character <- [def]
491 ]
492 ]
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518 scenario parse-dotted-list-of-two-atoms [
519 local-scope
520 s:text <- new [(abc . def)]
521 x:&:cell <- parse s
522 trace-should-contain [
523 ¦ app/parse: < abc | def >
524 ]
525 10:bool/raw <- is-pair? x
526 x1:&:cell <- first x
527 x2:&:cell <- rest x
528 s1:text, 11:bool/raw <- maybe-convert *x1, atom:variant
529 s2:text, 12:bool/raw <- maybe-convert *x2, atom:variant
530 20:@:char/raw <- copy *s1
531 30:@:char/raw <- copy *s2
532 memory-should-contain [
533 ¦
534 ¦ 10 <- 1
535 ¦ 11 <- 1
536 ¦ 12 <- 1
537 ¦ 20:array:character <- [abc]
538 ¦ 30:array:character <- [def]
539 ]
540 ]
541
542 scenario parse-dotted-list-of-more-than-two-atoms [
543 local-scope
544 s:text <- new [(abc def . ghi)]
545 x:&:cell <- parse s
546 trace-should-contain [
547 ¦ app/parse: < abc | < def | ghi > >
548 ]
549 10:bool/raw <- is-pair? x
550 x1:&:cell <- first x
551 x2:&:cell <- rest x
552 s1:text, 11:bool/raw <- maybe-convert *x1, atom:variant
553 12:bool/raw <- is-pair? x2
554 x3:&:cell <- first x2
555 s2:text, 13:bool/raw <- maybe-convert *x3, atom:variant
556 x4:&:cell <- rest x2
557 s3:text, 14:bool/raw <- maybe-convert *x4, atom:variant
558 20:@:char/raw <- copy *s1
559 30:@:char/raw <- copy *s2
560 40:@:char/raw <- copy *s3
561 memory-should-contain [
562 ¦ 10 <- 1
563 ¦ 11 <- 1
564 ¦ 12 <- 1
565 ¦ 13 <- 1
566 ¦ 14 <- 1
567 ¦ 20:array:character <- [abc]
568 ¦ 30:array:character <- [def]
569 ¦ 40:array:character <- [ghi]
570 ]
571 ]
572
573
574
575 def to-mu in:&:cell -> out:text [
576 local-scope
577 load-ingredients
578 buf:&:buffer <- new-buffer 30
579 buf <- to-mu in, buf
580 out <- buffer-to-array buf
581 ]
582
583 def to-mu in:&:cell, buf:&:buffer -> buf:&:buffer, result-name:text [
584 local-scope
585 load-ingredients
586
587
588
589 result-name <- copy 0
590 ]