1
2
3 container duplex-list:_elem [
4 value:_elem
5 next:&:duplex-list:_elem
6 prev:&:duplex-list:_elem
7 ]
8
9 def push x:_elem, in:&:duplex-list:_elem/contained-in:result -> result:&:duplex-list:_elem [
10 local-scope
11 load-inputs
12 result:&:duplex-list:_elem <- new {(duplex-list _elem): type}
13 *result <- merge x, in, 0
14 return-unless in
15 put *in, prev:offset, result
16 ]
17
18 def first in:&:duplex-list:_elem -> result:_elem [
19 local-scope
20 load-inputs
21 return-unless in, 0
22 result <- get *in, value:offset
23 ]
24
25 def next in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
26 local-scope
27 load-inputs
28 return-unless in, 0
29 result <- get *in, next:offset
30 ]
31
32 def prev in:&:duplex-list:_elem -> result:&:duplex-list:_elem/contained-in:in [
33 local-scope
34 load-inputs
35 return-unless in, 0
36 result <- get *in, prev:offset
37 return result
38 ]
39
40 scenario duplex-list-handling [
41 run [
42 ¦ local-scope
43 ¦
44 ¦ 10:num/raw <- copy 34
45 ¦ 11:num/raw <- copy 35
46 ¦ list:&:duplex-list:num <- push 3, 0
47 ¦ list <- push 4, list
48 ¦ list <- push 5, list
49 ¦ list2:&:duplex-list:num <- copy list
50 ¦ 20:num/raw <- first list2
51 ¦ list2 <- next list2
52 ¦ 21:num/raw <- first list2
53 ¦ list2 <- next list2
54 ¦ 22:num/raw <- first list2
55 ¦ 30:&:duplex-list:num/raw <- next list2
56 ¦ 31:num/raw <- first 30:&:duplex-list:num/raw
57 ¦ 32:&:duplex-list:num/raw <- next 30:&:duplex-list:num/raw
58 ¦ 33:&:duplex-list:num/raw <- prev 30:&:duplex-list:num/raw
59 ¦ list2 <- prev list2
60 ¦ 40:num/raw <- first list2
61 ¦ list2 <- prev list2
62 ¦ 41:num/raw <- first list2
63 ¦ 50:bool/raw <- equal list, list2
64 ]
65 memory-should-contain [
66 ¦ 0 <- 0
67 ¦ 10 <- 34
68 ¦ 11 <- 35
69 ¦ 20 <- 5
70 ¦ 21 <- 4
71 ¦ 22 <- 3
72 ¦ 30 <- 0
73 ¦ 31 <- 0
74 ¦ 32 <- 0
75 ¦ 33 <- 0
76 ¦ 40 <- 4
77 ¦ 41 <- 5
78 ¦ 50 <- 1
79 ]
80 ]
81
82 def length l:&:duplex-list:_elem -> result:num [
83 local-scope
84 load-inputs
85 result <- copy 0
86 {
87 ¦ break-unless l
88 ¦ result <- add result, 1
89 ¦ l <- next l
90 ¦ loop
91 }
92 ]
93
94
95 def insert x:_elem, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
96 local-scope
97 load-inputs
98 new-node:&:duplex-list:_elem <- new {(duplex-list _elem): type}
99 *new-node <- put *new-node, value:offset, x
100
101 next-node:&:duplex-list:_elem <- get *in, next:offset
102 *in <- put *in, next:offset, new-node
103 *new-node <- put *new-node, prev:offset, in
104 *new-node <- put *new-node, next:offset, next-node
105 return-unless next-node
106 *next-node <- put *next-node, prev:offset, new-node
107 ]
108
109 scenario inserting-into-duplex-list [
110 local-scope
111 list:&:duplex-list:num <- push 3, 0
112 list <- push 4, list
113 list <- push 5, list
114 run [
115 ¦ list2:&:duplex-list:num <- next list
116 ¦ list2 <- insert 6, list2
117 ¦
118 ¦ list2 <- copy list
119 ¦ 10:num/raw <- first list2
120 ¦ list2 <- next list2
121 ¦ 11:num/raw <- first list2
122 ¦ list2 <- next list2
123 ¦ 12:num/raw <- first list2
124 ¦ list2 <- next list2
125 ¦ 13:num/raw <- first list2
126 ¦ list2 <- prev list2
127 ¦ 20:num/raw <- first list2
128 ¦ list2 <- prev list2
129 ¦ 21:num/raw <- first list2
130 ¦ list2 <- prev list2
131 ¦ 22:num/raw <- first list2
132 ¦ 30:bool/raw <- equal list, list2
133 ]
134 memory-should-contain [
135 ¦ 10 <- 5
136 ¦ 11 <- 4
137 ¦ 12 <- 6
138 ¦ 13 <- 3
139 ¦ 20 <- 6
140 ¦ 21 <- 4
141 ¦ 22 <- 5
142 ¦ 30 <- 1
143 ]
144 ]
145
146 scenario inserting-at-end-of-duplex-list [
147 local-scope
148 list:&:duplex-list:num <- push 3, 0
149 list <- push 4, list
150 list <- push 5, list
151 run [
152 ¦ list2:&:duplex-list:num <- next list
153 ¦ list2 <- next list2
154 ¦ list2 <- insert 6, list2
155 ¦
156 ¦ list2 <- copy list
157 ¦ 10:num/raw <- first list2
158 ¦ list2 <- next list2
159 ¦ 11:num/raw <- first list2
160 ¦ list2 <- next list2
161 ¦ 12:num/raw <- first list2
162 ¦ list2 <- next list2
163 ¦ 13:num/raw <- first list2
164 ¦ list2 <- prev list2
165 ¦ 20:num/raw <- first list2
166 ¦ list2 <- prev list2
167 ¦ 21:num/raw <- first list2
168 ¦ list2 <- prev list2
169 ¦ 22:num/raw <- first list2
170 ¦ 30:bool/raw <- equal list, list2
171 ]
172 memory-should-contain [
173 ¦ 10 <- 5
174 ¦ 11 <- 4
175 ¦ 12 <- 3
176 ¦ 13 <- 6
177 ¦ 20 <- 3
178 ¦ 21 <- 4
179 ¦ 22 <- 5
180 ¦ 30 <- 1
181 ]
182 ]
183
184 scenario inserting-after-start-of-duplex-list [
185 local-scope
186 list:&:duplex-list:num <- push 3, 0
187 list <- push 4, list
188 list <- push 5, list
189 run [
190 ¦ list <- insert 6, list
191 ¦
192 ¦ list2:&:duplex-list:num <- copy list
193 ¦ 10:num/raw <- first list2
194 ¦ list2 <- next list2
195 ¦ 11:num/raw <- first list2
196 ¦ list2 <- next list2
197 ¦ 12:num/raw <- first list2
198 ¦ list2 <- next list2
199 ¦ 13:num/raw <- first list2
200 ¦ list2 <- prev list2
201 ¦ 20:num/raw <- first list2
202 ¦ list2 <- prev list2
203 ¦ 21:num/raw <- first list2
204 ¦ list2 <- prev list2
205 ¦ 22:num/raw <- first list2
206 ¦ 30:bool/raw <- equal list, list2
207 ]
208 memory-should-contain [
209 ¦ 10 <- 5
210 ¦ 11 <- 6
211 ¦ 12 <- 4
212 ¦ 13 <- 3
213 ¦ 20 <- 4
214 ¦ 21 <- 6
215 ¦ 22 <- 5
216 ¦ 30 <- 1
217 ]
218 ]
219
220
221
222
223
224 def remove x:&:duplex-list:_elem/contained-in:in, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
225 local-scope
226 load-inputs
227
228 return-unless x
229 next-node:&:duplex-list:_elem <- get *x, next:offset
230 prev-node:&:duplex-list:_elem <- get *x, prev:offset
231
232 *x <- put *x, next:offset, 0
233 *x <- put *x, prev:offset, 0
234
235 {
236 ¦ break-unless next-node
237 ¦ *next-node <- put *next-node, prev:offset, prev-node
238 }
239
240 {
241 ¦ break-unless prev-node
242 ¦ *prev-node <- put *prev-node, next:offset, next-node
243 ¦ return
244 }
245
246
247 return next-node
248 ]
249
250 scenario removing-from-duplex-list [
251 local-scope
252 list:&:duplex-list:num <- push 3, 0
253 list <- push 4, list
254 list <- push 5, list
255 run [
256 ¦ list2:&:duplex-list:num <- next list
257 ¦ list <- remove list2, list
258 ¦ 10:bool/raw <- equal list2, 0
259 ¦
260 ¦ list2 <- copy list
261 ¦ 11:num/raw <- first list2
262 ¦ list2 <- next list2
263 ¦ 12:num/raw <- first list2
264 ¦ 20:&:duplex-list:num/raw <- next list2
265 ¦ list2 <- prev list2
266 ¦ 30:num/raw <- first list2
267 ¦ 40:bool/raw <- equal list, list2
268 ]
269 memory-should-contain [
270 ¦ 10 <- 0
271 ¦ 11 <- 5
272 ¦ 12 <- 3
273 ¦ 20 <- 0
274 ¦ 30 <- 5
275 ¦ 40 <- 1
276 ]
277 ]
278
279 scenario removing-from-start-of-duplex-list [
280 local-scope
281 list:&:duplex-list:num <- push 3, 0
282 list <- push 4, list
283 list <- push 5, list
284 run [
285 ¦ list <- remove list, list
286 ¦
287 ¦ list2:&:duplex-list:num <- copy list
288 ¦ 10:num/raw <- first list2
289 ¦ list2 <- next list2
290 ¦ 11:num/raw <- first list2
291 ¦ 20:&:duplex-list:num/raw <- next list2
292 ¦ list2 <- prev list2
293 ¦ 30:num/raw <- first list2
294 ¦ 40:bool/raw <- equal list, list2
295 ]
296 memory-should-contain [
297 ¦ 10 <- 4
298 ¦ 11 <- 3
299 ¦ 20 <- 0
300 ¦ 30 <- 4
301 ¦ 40 <- 1
302 ]
303 ]
304
305 scenario removing-from-end-of-duplex-list [
306 local-scope
307 list:&:duplex-list:num <- push 3, 0
308 list <- push 4, list
309 list <- push 5, list
310 run [
311 ¦
312 ¦ list2:&:duplex-list:num <- next list
313 ¦ list2 <- next list2
314 ¦ list <- remove list2, list
315 ¦ 10:bool/raw <- equal list2, 0
316 ¦
317 ¦ list2 <- copy list
318 ¦ 11:num/raw <- first list2
319 ¦ list2 <- next list2
320 ¦ 12:num/raw <- first list2
321 ¦ 20:&:duplex-list:num/raw <- next list2
322 ¦ list2 <- prev list2
323 ¦ 30:num/raw <- first list2
324 ¦ 40:bool/raw <- equal list, list2
325 ]
326 memory-should-contain [
327 ¦ 10 <- 0
328 ¦ 11 <- 5
329 ¦ 12 <- 4
330 ¦ 20 <- 0
331 ¦ 30 <- 5
332 ¦ 40 <- 1
333 ]
334 ]
335
336 scenario removing-from-singleton-duplex-list [
337 local-scope
338 list:&:duplex-list:num <- push 3, 0
339 run [
340 ¦ list <- remove list, list
341 ¦ 1:num/raw <- copy list
342 ]
343 memory-should-contain [
344 ¦ 1 <- 0
345 ]
346 ]
347
348 def remove x:&:duplex-list:_elem/contained-in:in, n:num, in:&:duplex-list:_elem -> in:&:duplex-list:_elem [
349 local-scope
350 load-inputs
351 i:num <- copy 0
352 curr:&:duplex-list:_elem <- copy x
353 {
354 ¦ done?:bool <- greater-or-equal i, n
355 ¦ break-if done?
356 ¦ break-unless curr
357 ¦ next:&:duplex-list:_elem <- next curr
358 ¦ in <- remove curr, in
359 ¦ curr <- copy next
360 ¦ i <- add i, 1
361 ¦ loop
362 }
363 ]
364
365 scenario removing-multiple-from-duplex-list [
366 local-scope
367 list:&:duplex-list:num <- push 3, 0
368 list <- push 4, list
369 list <- push 5, list
370 run [
371 ¦ list2:&:duplex-list:num <- next list
372 ¦ list <- remove list2, 2, list
373 ¦ stash list
374 ]
375 trace-should-contain [
376 ¦ app: 5
377 ]
378 ]
379
380
381
382
383
384
385 def remove-between start:&:duplex-list:_elem, end:&:duplex-list:_elem/contained-in:start -> start:&:duplex-list:_elem [
386 local-scope
387 load-inputs
388 next:&:duplex-list:_elem <- get *start, next:offset
389 nothing-to-delete?:bool <- equal next, end
390 return-if nothing-to-delete?
391 assert next, [malformed duplex list]
392
393
394 *next <- put *next, prev:offset, 0
395 *start <- put *start, next:offset, end
396 return-unless end
397
398
399 prev:&:duplex-list:_elem <- get *end, prev:offset
400 assert prev, [malformed duplex list - 2]
401 *prev <- put *prev, next:offset, 0
402 *end <- put *end, prev:offset, start
403 ]
404
405 scenario remove-range [
406
407 local-scope
408 list:&:duplex-list:num <- push 18, 0
409 list <- push 17, list
410 list <- push 16, list
411 list <- push 15, list
412 list <- push 14, list
413 list <- push 13, list
414 run [
415 ¦
416 ¦
417 ¦ list2:&:duplex-list:num <- next list
418 ¦ list2 <- next list2
419 ¦ list2 <- remove-between list2, 0
420 ¦
421 ¦ 10:num/raw <- get *list, value:offset
422 ¦ list <- next list
423 ¦ 11:num/raw <- get *list, value:offset
424 ¦ list <- next list
425 ¦ 12:num/raw <- get *list, value:offset
426 ¦ 20:&:duplex-list:num/raw <- next list
427 ]
428 memory-should-contain [
429 ¦ 10 <- 13
430 ¦ 11 <- 14
431 ¦ 12 <- 15
432 ¦ 20 <- 0
433 ]
434 ]
435
436 scenario remove-range-to-final [
437 local-scope
438
439 list:&:duplex-list:num <- push 18, 0
440 list <- push 17, list
441 list <- push 16, list
442 list <- push 15, list
443 list <- push 14, list
444 list <- push 13, list
445 run [
446 ¦
447 ¦
448 ¦ list2:&:duplex-list:num <- next list
449 ¦
450 ¦ end:&:duplex-list:num <- next list2
451 ¦ end <- next end
452 ¦ end <- next end
453 ¦ end <- next end
454 ¦ remove-between list2, end
455 ¦
456 ¦ 10:num/raw <- get *list, value:offset
457 ¦ list <- next list
458 ¦ 11:num/raw <- get *list, value:offset
459 ¦ list <- next list
460 ¦ 12:num/raw <- get *list, value:offset
461 ¦ 20:&:duplex-list:num/raw <- next list
462 ]
463 memory-should-contain [
464 ¦ 10 <- 13
465 ¦ 11 <- 14
466 ¦ 12 <- 18
467 ¦ 20 <- 0
468 ]
469 ]
470
471 scenario remove-range-empty [
472 local-scope
473
474 list:&:duplex-list:num <- push 15, 0
475 list <- push 14, list
476 list <- push 13, list
477 run [
478 ¦
479 ¦ list2:&:duplex-list:num <- next list
480 ¦ remove-between list, list2
481 ¦
482 ¦ 10:num/raw <- get *list, value:offset
483 ¦ list <- next list
484 ¦ 11:num/raw <- get *list, value:offset
485 ¦ list <- next list
486 ¦ 12:num/raw <- get *list, value:offset
487 ¦ 20:&:duplex-list:num/raw <- next list
488 ]
489
490 memory-should-contain [
491 ¦ 10 <- 13
492 ¦ 11 <- 14
493 ¦ 12 <- 15
494 ¦ 20 <- 0
495 ]
496 ]
497
498 scenario remove-range-to-end [
499 local-scope
500
501 list:&:duplex-list:num <- push 18, 0
502 list <- push 17, list
503 list <- push 16, list
504 list <- push 15, list
505 list <- push 14, list
506 list <- push 13, list
507 run [
508 ¦
509 ¦ list2:&:duplex-list:num <- next list
510 ¦ remove-between list2, 0
511 ¦
512 ¦ 10:num/raw <- get *list, value:offset
513 ¦ list <- next list
514 ¦ 11:num/raw <- get *list, value:offset
515 ¦ 20:&:duplex-list:num/raw <- next list
516 ]
517 memory-should-contain [
518 ¦ 10 <- 13
519 ¦ 11 <- 14
520 ¦ 20 <- 0
521 ]
522 ]
523
524
525 def splice in:&:duplex-list:_elem, start:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
526 local-scope
527 load-inputs
528 return-unless in
529 return-unless start
530 end:&:duplex-list:_elem <- last start
531 next:&:duplex-list:_elem <- next in
532 {
533 ¦ break-unless next
534 ¦ *end <- put *end, next:offset, next
535 ¦ *next <- put *next, prev:offset, end
536 }
537 *in <- put *in, next:offset, start
538 *start <- put *start, prev:offset, in
539 ]
540
541
542 def insert in:&:duplex-list:_elem, new:&:@:_elem -> in:&:duplex-list:_elem [
543 local-scope
544 load-inputs
545 return-unless in
546 return-unless new
547 len:num <- length *new
548 return-unless len
549 curr:&:duplex-list:_elem <- copy in
550 idx:num <- copy 0
551 {
552 ¦ done?:bool <- greater-or-equal idx, len
553 ¦ break-if done?
554 ¦ c:_elem <- index *new, idx
555 ¦ insert c, curr
556 ¦
557 ¦ curr <- next curr
558 ¦ idx <- add idx, 1
559 ¦ loop
560 }
561 ]
562
563 def append in:&:duplex-list:_elem, new:&:duplex-list:_elem/contained-in:in -> in:&:duplex-list:_elem [
564 local-scope
565 load-inputs
566 last:&:duplex-list:_elem <- last in
567 *last <- put *last, next:offset, new
568 return-unless new
569 *new <- put *new, prev:offset, last
570 ]
571
572 def last in:&:duplex-list:_elem -> result:&:duplex-list:_elem [
573 local-scope
574 load-inputs
575 result <- copy in
576 {
577 ¦ next:&:duplex-list:_elem <- next result
578 ¦ break-unless next
579 ¦ result <- copy next
580 ¦ loop
581 }
582 ]
583
584
585 def match x:&:duplex-list:_elem, y:&:@:_elem -> result:bool [
586 local-scope
587 load-inputs
588 i:num <- copy 0
589 max:num <- length *y
590 {
591 ¦ done?:bool <- greater-or-equal i, max
592 ¦ break-if done?
593 ¦ expected:_elem <- index *y, i
594 ¦ return-unless x, 0/no-match
595 ¦ curr:_elem <- first x
596 ¦ curr-matches?:bool <- equal curr, expected
597 ¦ return-unless curr-matches?, 0/no-match
598 ¦ x <- next x
599 ¦ i <- add i, 1
600 ¦ loop
601 }
602 return 1/successful-match
603 ]
604
605 scenario duplex-list-match [
606 local-scope
607 list:&:duplex-list:char <- push 97/a, 0
608 list <- push 98/b, list
609 list <- push 99/c, list
610 list <- push 100/d, list
611 run [
612 ¦ 10:bool/raw <- match list, []
613 ¦ 11:bool/raw <- match list, [d]
614 ¦ 12:bool/raw <- match list, [dc]
615 ¦ 13:bool/raw <- match list, [dcba]
616 ¦ 14:bool/raw <- match list, [dd]
617 ¦ 15:bool/raw <- match list, [dcbax]
618 ]
619 memory-should-contain [
620 ¦ 10 <- 1
621 ¦ 11 <- 1
622 ¦ 12 <- 1
623 ¦ 13 <- 1
624 ¦ 14 <- 0
625 ¦ 15 <- 0
626 ]
627 ]
628
629
630 def dump-from x:&:duplex-list:_elem [
631 local-scope
632 load-inputs
633 $print x, [: ]
634 {
635 ¦ break-unless x
636 ¦ c:_elem <- get *x, value:offset
637 ¦ $print c, [ ]
638 ¦ x <- next x
639 ¦ {
640 ¦ ¦ is-newline?:bool <- equal c, 10/newline
641 ¦ ¦ break-unless is-newline?
642 ¦ ¦ $print 10/newline
643 ¦ ¦ $print x, [: ]
644 ¦ }
645 ¦ loop
646 }
647 $print 10/newline, [---], 10/newline
648 ]
649
650 scenario stash-duplex-list [
651 local-scope
652 list:&:duplex-list:num <- push 1, 0
653 list <- push 2, list
654 list <- push 3, list
655 run [
656 ¦ stash [list:], list
657 ]
658 trace-should-contain [
659 ¦ app: list: 3 <-> 2 <-> 1
660 ]
661 ]
662
663 def to-text in:&:duplex-list:_elem -> result:text [
664 local-scope
665 load-inputs
666 buf:&:buffer:char <- new-buffer 80
667 buf <- to-buffer in, buf
668 result <- buffer-to-array buf
669 ]
670
671
672 def to-text-line in:&:duplex-list:_elem -> result:text [
673 local-scope
674 load-inputs
675 buf:&:buffer:char <- new-buffer 80
676 buf <- to-buffer in, buf, 6
677 result <- buffer-to-array buf
678 ]
679
680 def to-buffer in:&:duplex-list:_elem, buf:&:buffer:char -> buf:&:buffer:char [
681 local-scope
682 load-inputs
683 {
684 ¦ break-if in
685 ¦ buf <- append buf, [[]]
686 ¦ return
687 }
688
689 val:_elem <- get *in, value:offset
690 buf <- append buf, val
691
692 next:&:duplex-list:_elem <- next in
693 nextn:num <- copy next
694 return-unless next
695 buf <- append buf, [ <-> ]
696
697 remaining:num, optional-input-found?:bool <- next-input
698 {
699 ¦ break-if optional-input-found?
700 ¦
701 ¦ buf <- to-buffer next, buf
702 ¦ return
703 }
704 {
705 ¦ break-unless remaining
706 ¦
707 ¦ remaining <- subtract remaining, 1
708 ¦ buf <- to-buffer next, buf, remaining
709 ¦ return
710 }
711
712 append buf, [...]
713 ]
714
715 scenario stash-empty-duplex-list [
716 local-scope
717 x:&:duplex-list:num <- copy 0
718 run [
719 ¦ stash x
720 ]
721 trace-should-contain [
722 ¦ app: []
723 ]
724 ]