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