about summary refs log tree commit diff stats
path: root/073list.mu
blob: 1dedf573ba0f1554e2f36f8c4f5b07e08c159a7a (plain) (blame)
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
]

recipe 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
  reply result  # needed explicitly because we need to replace 'in' with 'result'
]

recipe first in:address:shared:list:_elem -> result:_elem [
  local-scope
  load-ingredients
  result <- get *in, value:offset
]

recipe 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
  ]
]

recipe 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)
recipe 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
]

recipe 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
    reply
  }
  # 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
  reply-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
    reply
  }
  {
    break-unless remaining
    # limited recursion
    remaining <- subtract remaining, 1
    buf <- to-buffer next, buf, remaining
    reply
  }
  # 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 -> ...
  ]
]