1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
# A list links up multiple objects together to make them easier to manage.
#
# The objects must be of the same type. If you want to store multiple types in
# a single list, use an exclusive-container.
container list:_elem [
value:_elem
next:address:shared:list:_elem
]
def push x:_elem, in:address:shared:list:_elem -> in:address:shared:list:_elem [
local-scope
load-ingredients
result:address:shared:list:_elem <- new {(list _elem): type}
val:address:_elem <- get-address *result, value:offset
*val <- copy x
next:address:address:shared:list:_elem <- get-address *result, next:offset
*next <- copy in
return result # needed explicitly because we need to replace 'in' with 'result'
]
def first in:address:shared:list:_elem -> result:_elem [
local-scope
load-ingredients
result <- get *in, value:offset
]
def rest in:address:shared:list:_elem -> result:address:shared:list:_elem/contained-in:in [
local-scope
load-ingredients
result <- get *in, next:offset
]
scenario list-handling [
run [
1:address:shared:list:number <- push 3, 0
1:address:shared:list:number <- push 4, 1:address:shared:list:number
1:address:shared:list:number <- push 5, 1:address:shared:list:number
2:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
3:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
4:number <- first 1:address:shared:list:number
1:address:shared:list:number <- rest 1:address:shared:list:number
]
memory-should-contain [
1 <- 0 # empty to empty, dust to dust..
2 <- 5
3 <- 4
4 <- 3
]
]
def to-text in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
buf <- to-buffer in, buf
result <- buffer-to-array buf
]
# variant of 'to-text' which stops printing after a few elements (and so is robust to cycles)
def to-text-line in:address:shared:list:_elem -> result:address:shared:array:character [
local-scope
load-ingredients
buf:address:shared:buffer <- new-buffer 80
buf <- to-buffer in, buf, 6 # max elements to display
result <- buffer-to-array buf
]
def to-buffer in:address:shared:list:_elem, buf:address:shared:buffer -> buf:address:shared:buffer [
local-scope
load-ingredients
{
break-if in
buf <- append buf, 48/0
return
}
# append in.value to buf
val:_elem <- get *in, value:offset
buf <- append buf, val
# now prepare next
next:address:shared:list:_elem <- rest in
nextn:number <- copy next
return-unless next
space:character <- copy 32/space
buf <- append buf, space:character
s:address:shared:array:character <- new [-> ]
n:number <- length *s
buf <- append buf, s
# and recurse
remaining:number, optional-ingredient-found?:boolean <- next-ingredient
{
break-if optional-ingredient-found?
# unlimited recursion
buf <- to-buffer next, buf
return
}
{
break-unless remaining
# limited recursion
remaining <- subtract remaining, 1
buf <- to-buffer next, buf, remaining
return
}
# past recursion depth; insert ellipses and stop
s:address:shared:array:character <- new [...]
append buf, s
]
scenario stash-on-list-converts-to-text [
run [
x:address:shared:list:number <- push 4, 0
x <- push 5, x
x <- push 6, x
stash [foo foo], x
]
trace-should-contain [
app: foo foo 6 -> 5 -> 4
]
]
scenario stash-handles-list-with-cycle [
run [
x:address:shared:list:number <- push 4, 0
y:address:address:shared:list:number <- get-address *x, next:offset
*y <- copy x
stash [foo foo], x
]
trace-should-contain [
app: foo foo 4 -> 4 -> 4 -> 4 -> 4 -> 4 -> 4 -> ...
]
]
|