about summary refs log tree commit diff stats
path: root/subx/apps/crenshaw2-1.subx
blob: 0c3f180ba5269dc08f6153eff31ca40ef552c0b3 (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
<
# Port of https://github.com/akkartik/crenshaw/blob/master/tutor2.1.pas
# which corresponds to the section "single digits" in https://compilers.iecc.com/crenshaw/tutor2.txt
# except that we support hex digits.
#
# To run (from the subx/ directory):
#   $ ./subx translate *.subx apps/crenshaw2-1.subx -o apps/crenshaw2-1
#   $ echo '3'  |./subx run apps/crenshaw2-1
# Expected output:
#   # syscall(exit, 3)
#   bb/copy-to-EBX  3/imm32
#   b8/copy-to-EAX  1/imm32/exit
#   cd/syscall  0x80/imm8
#
# To run the generated output:
#   $ echo '3'  |./subx run apps/crenshaw2-1 > z1.subx
#   $ ./subx translate z1.subx -o z1
#   $ ./subx run z1
#   $ echo $?
#   3
#
# Stdin must contain just a single hex digit. Other input will print an error:
#   $ echo 'xyz'  |./subx run apps/crenshaw2-1
#   Error: integer expected
#
# Names in this file sometimes follow Crenshaw's original rather than my usual
# naming conventions.

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

Entry:  # run tests if necessary, call 'compile' if not
    # initialize heap
    # . Heap = new-segment(64KB)
    # . . push args
    68/push  Heap/imm32
    68/push  0x10000/imm32/64KB
    # . . call
    e8/call  new-segment/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP

    # . prolog
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # - if argc > 1 and argv[1] == "test", then return run_tests()
    # . argc > 1
    81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0/disp8         1/imm32           # compare *EBP
    7e/jump-if-lesser-or-equal  $run-main/disp8
    # . argv[1] == "test"
    # . . push args
    68/push  "test"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
    # . . call
    e8/call  kernel-string-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # . check result
    3d/compare-EAX-and  1/imm32
    75/jump-if-not-equal  $run-main/disp8
    # . run-tests()
    e8/call  run-tests/disp32
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           3/r32/EBX   Num-test-failures/disp32          # copy *Num-test-failures to EBX
    eb/jump  $main:end/disp8
$run-main:
    # - otherwise read a program from stdin and emit its translation to stdout
    # var ed/EAX : exit-descriptor
    81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
    89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EAX
    # configure ed to really exit()
    # . ed->target = 0
    c7          0/subop/copy        0/mod/direct    0/rm32/EAX    .           .             .           .           .               0/imm32           # copy to *EAX
    # return compile(Stdin, 1/stdout, 2/stderr, ed)
    # . . push args
    50/push-EAX/ed
    68/push  2/imm32/stderr
    68/push  1/imm32/stdout
    68/push  Stdin/imm32
    # . . call
    e8/call  compile/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
    # . syscall(exit, 0)
    bb/copy-to-EBX  0/imm32
$main:end:
    b8/copy-to-EAX  1/imm32/exit
    cd/syscall  0x80/imm8

# the main entry point
compile:  # in : (address buffered-file), out : fd or (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
    # . prolog
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # . save registers
    50/push-EAX
    51/push-ECX
    # prime the pump
    # . Look = get-char(in)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8      .                    # push *(EBP+8)
    # . . call
    e8/call  get-char/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # var num/ECX : (address stream) on the stack
    # Numbers can be 32 bits or 8 hex bytes long. One of them will be in 'Look', so we need space for 7 bytes.
    # Sizing the stream just right buys us overflow-handling for free inside 'get-num'.
    # Add 12 bytes for 'read', 'write' and 'length' fields, for a total of 19 bytes, or 0x13 in hex.
    # The stack pointer is no longer aligned, so dump_stack() can be misleading past this point.
    81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x13/imm32        # subtract from ESP
    89/copy                         3/mod/direct    1/rm32/ECX    .           .             .           4/r32/ESP   .               .                 # copy ESP to ECX
    # initialize the stream
    # . num->length = 7
    c7          0/subop/copy        1/mod/*+disp8   1/rm32/ECX    .           .             .           .           8/disp8         7/imm32           # copy to *(ECX+8)
    # . clear-stream(num)
    # . . push args
    51/push-ECX
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # read a digit from 'in' into 'num'
    # . get-num(in, num, err, ed)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
    51/push-ECX/num
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8      .                    # push *(EBP+8)
    # . . call
    e8/call  get-num/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
    # render 'num' into the following template on 'out':
    #   bb/copy-to-EBX  _num_
    #   b8/copy-to-EAX  1/imm32/exit
    #   cd/syscall  0x80/imm8
    #
    # . write(out, "bb/copy-to-EBX  ")
    # . . push args
    68/push  "bb/copy-to-EBX  "/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # . write-stream(out, num)
    # . . push args
    51/push-ECX/num
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # . write(out, Newline)
    # . . push args
    68/push  Newline/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # . write(out, "b8/copy-to-EAX  1/imm32/exit\n")
    # . . push args
    68/push  "b8/copy-to-EAX  1/imm32/exit\n"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # . write(out, "cd/syscall  0x80/imm8\n")
    # . . push args
    68/push  "cd/syscall  0x80/imm8\n"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
$compile:end:
    # . restore registers
    59/pop-to-ECX
    58/pop-to-EAX
    # . epilog
    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    5d/pop-to-EBP
    c3/return

# Read a single digit into 'out'. Abort if there are none, or if there is no space in 'out'.
# Input comes from the global variable 'Look', and we leave the next byte from
# 'in' into it on exit.
get-num:  # in : (address buffered-file), out : (address stream), err : fd or (address stream), ed : (address exit-descriptor) -> <void>
    # pseudocode:
    #   if (!is-digit?(Look)) expected(ed, err, "integer")
    #   if out->write >= out->length
    #     write(err, "Error: too many digits in number\n")
    #     stop(ed, 1)
    #   out->data[out->write] = LSB(Look)
    #   ++out->write
    #   Look = get-char(in)
    #
    # registers:
    #   in: ESI
    #   out: EDI
    #   out->write: ECX (cached copy; need to keep in sync)
    #   out->length: EDX
    #   temporaries: EAX, EBX
    # We can't allocate Look to a register because it gets written implicitly in
    # get-char in each iteration of the loop. (Thereby demonstrating that it's
    # not the right interface for us. But we'll keep it just to follow Crenshaw.)
    #
    # . prolog
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # - if (is-digit?(Look)) expected(ed, err, "integer")
    # . EAX = is-digit?(Look)
    # . . push args
    ff          6/subop/push        0/mod/indirect  5/rm32/.disp32            .             .           .           Look/disp32     .                 # push *Look
    # . . call
    e8/call  is-digit?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . if (EAX == 0)
    3d/compare-EAX-and  0/imm32
    75/jump-if-not-equal  $get-num:main/disp8
    # . expected(ed, err, "integer")
    # . . push args
    68/push  "integer"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
    # . . call
    e8/call  expected/disp32  # never returns
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
$get-num:main:
    # - otherwise read a digit
    # . save registers
    50/push-EAX
    51/push-ECX
    52/push-EDX
    53/push-EBX
    56/push-ESI
    57/push-EDI
    # read necessary variables to registers
    # ESI = in
    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           6/r32/ESI   8/disp8         .                 # copy *(EBP+8) to ESI
    # EDI = out
    8b/copy                         1/mod/*+disp8   5/rm32/EBP    .           .             .           7/r32/EDI   0xc/disp8       .                 # copy *(EBP+12) to EDI
    # ECX = out->write
    8b/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy *EDI to ECX
    # EDX = out->length
    8b/copy                         1/mod/*+disp8   7/rm32/EDI    .           .             .           2/r32/EDX   8/disp8         .                 # copy *(EDI+8) to EDX
    # if (out->write >= out->length) error
    39/compare                      3/mod/direct    2/rm32/EDX    .           .             .           1/r32/ECX   .               .                 # compare EDX with ECX
    7d/jump-if-lesser  $get-num:stage2/disp8
    # . error(ed, err, msg)  # TODO: show full number
    # . . push args
    68/push  "get-num: too many digits in number"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x14/disp8      .                 # push *(EBP+20)
    # . . call
    e8/call  error/disp32  # never returns
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
$get-num:stage2:
    # out->data[out->write] = LSB(Look)
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    7/base/EDI  1/index/ECX   .           3/r32/EBX   0xc/disp8       .                 # copy EDI+ECX+12 to EBX
    8b/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/EAX   Look/disp32     .                 # copy *Look to EAX
    88/copy-byte                    0/mod/indirect  3/rm32/EBX    .           .             .           0/r32/AL    .               .                 # copy byte at AL to *EBX
    # ++out->write
    41/increment-ECX
    # Look = get-char(in)
    # . . push args
    56/push-ESI
    # . . call
    e8/call  get-char/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
$get-num:loop-end:
    # persist necessary variables from registers
    89/copy                         0/mod/indirect  7/rm32/EDI    .           .             .           1/r32/ECX   .               .                 # copy ECX to *EDI
$get-num:end:
    # . restore registers
    5f/pop-to-EDI
    5e/pop-to-ESI
    5b/pop-to-EBX
    5a/pop-to-EDX
    59/pop-to-ECX
    58/pop-to-EAX
    # . epilog
    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    5d/pop-to-EBP
    c3/return

test-get-num-reads-single-digit:
    # - check that get-num returns first character if it's a digit
    # This test uses exit-descriptors. Use EBP for setting up local variables.
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # clear all streams
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-buffered-file+4)
    # . . push args
    b8/copy-to-EAX  _test-buffered-file/imm32
    05/add-to-EAX  4/imm32
    50/push-EAX
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-error-stream)
    # . . push args
    68/push  _test-error-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # initialize 'in'
    # . write(_test-stream, "3")
    # . . push args
    68/push  "3"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # initialize exit-descriptor 'ed' for the call to 'get-num' below
    # . var ed/EAX : exit-descriptor
    81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
    89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EAX
    # . tailor-exit-descriptor(ed, 16)
    # . . push args
    68/push  0x10/imm32/nbytes-of-args-for-get-num
    50/push-EAX/ed
    # . . call
    e8/call  tailor-exit-descriptor/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # prime the pump
    # . get-char(_test-buffered-file)
    # . . push args
    68/push  _test-buffered-file/imm32
    # . . call
    e8/call  get-char/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # get-num(in, out, err, ed)
    # . . push args
    50/push-EAX/ed
    68/push  _test-error-stream/imm32
    68/push  _test-output-stream/imm32
    68/push  _test-buffered-file/imm32
    # . . call
    e8/call  get-num/disp32
    # registers except ESP may be clobbered at this point
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
    # check-ints-equal(*_test-output-stream->data, '3', msg)
    # . . push args
    68/push  "F - test-get-num-reads-single-digit"/imm32
    68/push  0x33/imm32
    b8/copy-to-EAX  _test-output-stream/imm32
    ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           0xc/disp8       .                 # push *(EAX+12)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    5d/pop-to-EBP
    c3/return

test-get-num-aborts-on-non-digit-in-Look:
    # - check that get-num returns first character if it's a digit
    # This test uses exit-descriptors. Use EBP for setting up local variables.
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # clear all streams
    # . clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-buffered-file+4)
    # . . push args
    b8/copy-to-EAX  _test-buffered-file/imm32
    05/add-to-EAX  4/imm32
    50/push-EAX
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-output-stream)
    # . . push args
    68/push  _test-output-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # . clear-stream(_test-error-stream)
    # . . push args
    68/push  _test-error-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # initialize 'in'
    # . write(_test-stream, "3")
    # . . push args
    68/push  "3"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # initialize exit-descriptor 'ed' for the call to 'get-num' below
    # . var ed/EAX : (address exit-descriptor)
    81          5/subop/subtract    3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # subtract from ESP
    89/copy                         3/mod/direct    0/rm32/EAX    .           .             .           4/r32/ESP   .               .                 # copy ESP to EAX
    # . tailor-exit-descriptor(ed, 16)
    # . . push args
    68/push  0x10/imm32/nbytes-of-args-for-get-num
    50/push-EAX/ed
    # . . call
    e8/call  tailor-exit-descriptor/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # *don't* prime the pump
    # get-num(in, out, err, ed)
    # . . push args
    50/push-EAX/ed
    68/push  _test-error-stream/imm32
    68/push  _test-output-stream/imm32
    68/push  _test-buffered-file/imm32
    # . . call
    e8/call  get-num/disp32
    # registers except ESP may be clobbered at this point
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0x10/imm32        # add to ESP
    # check that get-num tried to call exit(1)
    # . check-ints-equal(ed->value, 2, msg)  # i.e. stop was called with value 1
    # . . push args
    68/push  "F - test-get-num-aborts-on-non-digit-in-Look"/imm32
    68/push  2/imm32
    # . . push ed->value
    ff          6/subop/push        1/mod/*+disp8   0/rm32/EAX    .           .             .           .           4/disp8         .                 # push *(EAX+4)
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               0xc/imm32         # add to ESP
    # . reclaim locals
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    5d/pop-to-EBP
    c3/return

## helpers

# write(f, "Error: "+s+" expected\n") then stop(ed, 1)
expected:  # ed : (address exit-descriptor), f : fd or (address stream), s : (address array byte) -> <void>
    # . prolog
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # write(f, "Error: ")
    # . . push args
    68/push  "Error: "/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # write(f, s)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0x10/disp8      .                 # push *(EBP+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # write(f, " expected")
    # . . push args
    68/push  " expected\n"/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           0xc/disp8       .                 # push *(EBP+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               8/imm32           # add to ESP
    # stop(ed, 1)
    # . . push args
    68/push  1/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
    # . . call
    e8/call  stop/disp32
    # should never get past this point
$expected:dead-end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    5d/pop-to-EBP
    c3/return

# read a byte from 'f', and save it in 'Look'
get-char:  # f : (address buffered-file) -> <void>
    # . prolog
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # . save registers
    50/push-EAX
    # EAX = read-byte-buffered(f)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         .                 # push *(EBP+8)
    # . . call
    e8/call  read-byte-buffered/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/ESP    .           .             .           .           .               4/imm32           # add to ESP
    # save EAX to Look
    89/copy                         0/mod/indirect  5/rm32/.disp32            .             .           0/r32/EAX   Look/disp32     .                 # copy EAX to *Look
$get-char:end:
    # . restore registers
    58/pop-to-EAX
    # . epilog
    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    5d/pop-to-EBP
    c3/return

is-digit?:  # c : int -> EAX : boolean
    # . prolog
    55/push-EBP
    89/copy                         3/mod/direct    5/rm32/EBP    .           .             .           4/r32/ESP   .               .                 # copy ESP to EBP
    # EAX = false
    b8/copy-to-EAX  0/imm32
    # if (c < '0') return false
    81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x30/imm32        # compare *(EBP+8)
    7c/jump-if-lesser  $is-digit?:end/disp8
    # if (c > '9') return false
    81          7/subop/compare     1/mod/*+disp8   5/rm32/EBP    .           .             .           .           8/disp8         0x39/imm32        # compare *(EBP+8)
    7f/jump-if-greater  $is-digit?:end/disp8
    # otherwise return true
    b8/copy-to-EAX  1/imm32
$is-digit?:end:
    # . epilog
    89/copy                         3/mod/direct    4/rm32/ESP    .           .             .           5/r32/EBP   .               .                 # copy EBP to ESP
    5d/pop-to-EBP
    c3/return

== data

Look:  # (char with some extra padding)
    0/imm32

_test-output-stream:
    # current write index
    0/imm32
    # current read index
    0/imm32
    # length
    8/imm32
    # data
    00 00 00 00 00 00 00 00  # 8 bytes

_test-error-stream:
    # current write index
    0/imm32
    # current read index
    0/imm32
    # length
    0x40/imm32
    # data (4 lines x 16 bytes/line)
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

# . . vim:nowrap:textwidth=0
n>> <span id="L35" class="LineNr"> 35 </span><span class="Comment">//: to make it available to products of 'return-continuation-until-mark'.</span> <span id="L36" class="LineNr"> 36 </span><span class="Comment">//: See continuation5.mu.</span> <span id="L37" class="LineNr"> 37 </span><span class="Comment">//: * There can be multiple continuation marks on the stack at once;</span> <span id="L38" class="LineNr"> 38 </span><span class="Comment">//: 'call-with-continuation-mark' and 'return-continuation-until-mark' both</span> <span id="L39" class="LineNr"> 39 </span><span class="Comment">//: need to pass in a tag to coordinate on the correct mark. This allows us</span> <span id="L40" class="LineNr"> 40 </span><span class="Comment">//: to save multiple continuations for different purposes (say if one is</span> <span id="L41" class="LineNr"> 41 </span><span class="Comment">//: for exceptions) with overlapping stack frames. See exception.mu.</span> <span id="L42" class="LineNr"> 42 </span><span class="Comment">//:</span> <span id="L43" class="LineNr"> 43 </span><span class="Comment">//: Inspired by James and Sabry, &quot;Yield: Mainstream delimited continuations&quot;,</span> <span id="L44" class="LineNr"> 44 </span><span class="Comment">//: Workshop on the Theory and Practice of Delimited Continuations, 2011.</span> <span id="L45" class="LineNr"> 45 </span><span class="Comment">//: <a href="https://www.cs.indiana.edu/~sabry/papers/yield.pdf">https://www.cs.indiana.edu/~sabry/papers/yield.pdf</a></span> <span id="L46" class="LineNr"> 46 </span><span class="Comment">//:</span> <span id="L47" class="LineNr"> 47 </span><span class="Comment">//: Caveats:</span> <span id="L48" class="LineNr"> 48 </span><span class="Comment">//: * At the moment we can't statically type-check continuations. So we raise</span> <span id="L49" class="LineNr"> 49 </span><span class="Comment">//: runtime errors for a call that doesn't return a continuation when the</span> <span id="L50" class="LineNr"> 50 </span><span class="Comment">//: caller expects, or one that returns a continuation when the caller</span> <span id="L51" class="LineNr"> 51 </span><span class="Comment">//: doesn't expect it. This shouldn't cause memory corruption, though.</span> <span id="L52" class="LineNr"> 52 </span><span class="Comment">//: There should still be no way to lookup addresses that aren't allocated.</span> <span id="L53" class="LineNr"> 53 </span> <span id="L54" class="LineNr"> 54 </span><span class="Delimiter">:(before &quot;End Mu Types Initialization&quot;)</span> <span id="L55" class="LineNr"> 55 </span><a href='010vm.cc.html#L125'>type_ordinal</a> continuation = <span class="Special">Type_ordinal</span>[<span class="Constant">&quot;continuation&quot;</span>] = <span class="Special">Next_type_ordinal</span>++<span class="Delimiter">;</span> <span id="L56" class="LineNr"> 56 </span><span class="Special">Type</span>[continuation]<span class="Delimiter">.</span>name = <span class="Constant">&quot;continuation&quot;</span><span class="Delimiter">;</span> <span id="L57" class="LineNr"> 57 </span> <span id="L58" class="LineNr"> 58 </span><span class="Comment">//: A continuation can be called like a recipe.</span> <span id="L59" class="LineNr"> 59 </span><span class="Delimiter">:(before &quot;End <a href='072recipe.cc.html#L335'>is_mu_recipe</a> Atom Cases(r)&quot;)</span> <span id="L60" class="LineNr"> 60 </span><span class="Normal">if</span> <span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>name == <span class="Constant">&quot;continuation&quot;</span><span class="Delimiter">)</span> <span class="Identifier">return</span><span class="Constant"> true</span><span class="Delimiter">;</span> <span id="L61" class="LineNr"> 61 </span> <span id="L62" class="LineNr"> 62 </span><span class="Comment">//: However, it can't be type-checked like most recipes. Pretend it's like a</span> <span id="L63" class="LineNr"> 63 </span><span class="Comment">//: header-less recipe.</span> <span id="L64" class="LineNr"> 64 </span><span class="Delimiter">:(after &quot;Begin Reagent-&gt;Recipe(r, recipe_header)&quot;)</span> <span id="L65" class="LineNr"> 65 </span><span class="Normal">if</span> <span class="Delimiter">(</span>r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; r<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>name == <span class="Constant">&quot;continuation&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L66" class="LineNr"> 66 </span> result_header<span class="Delimiter">.</span>has_header =<span class="Constant"> false</span><span class="Delimiter">;</span> <span id="L67" class="LineNr"> 67 </span> <span class="Identifier">return</span> result_header<span class="Delimiter">;</span> <span id="L68" class="LineNr"> 68 </span><span class="Delimiter">}</span> <span id="L69" class="LineNr"> 69 </span> <span id="L70" class="LineNr"> 70 </span><span class="Delimiter">:(scenario delimited_continuation)</span> <span id="L71" class="LineNr"> 71 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L72" class="LineNr"> 72 </span> <span class="Constant">1</span>:continuation<span class="Special"> &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f<span class="Delimiter">,</span> <span class="Constant">77</span> <span class="Comment"># 77 is an argument to f</span> <span id="L73" class="LineNr"> 73 </span> <span class="Constant">2</span>:num<span class="Special"> &lt;- </span>copy <span class="Constant">5</span> <span id="L74" class="LineNr"> 74 </span> <span class="Delimiter">{</span> <span id="L75" class="LineNr"> 75 </span> <span class="Constant">2</span>:num<span class="Special"> &lt;- </span>call <span class="Constant">1</span>:continuation<span class="Delimiter">,</span> <span class="Constant">2</span>:num <span class="Comment"># jump to 'return-continuation-until-mark' below</span> <span id="L76" class="LineNr"> 76 </span> <span class="Constant">3</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>greater-<span class="Normal">or</span>-equal <span class="Constant">2</span>:num<span class="Delimiter">,</span> <span class="Constant">8</span> <span id="L77" class="LineNr"> 77 </span> <span class="Identifier">break</span>-<span class="Normal">if</span> <span class="Constant">3</span>:<span class="Normal">bool</span> <span id="L78" class="LineNr"> 78 </span> loop <span id="L79" class="LineNr"> 79 </span> <span class="Delimiter">}</span> <span id="L80" class="LineNr"> 80 </span>] <span id="L81" class="LineNr"> 81 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> f [ <span id="L82" class="LineNr"> 82 </span> <span class="Constant">11</span>:num<span class="Special"> &lt;- </span>next-ingredient <span id="L83" class="LineNr"> 83 </span> <span class="Constant">12</span>:num<span class="Special"> &lt;- </span>g <span class="Constant">11</span>:num <span id="L84" class="LineNr"> 84 </span> <span class="Identifier">return</span> <span class="Constant">12</span>:num <span id="L85" class="LineNr"> 85 </span>] <span id="L86" class="LineNr"> 86 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> g [ <span id="L87" class="LineNr"> 87 </span> <span class="Constant">21</span>:num<span class="Special"> &lt;- </span>next-ingredient <span id="L88" class="LineNr"> 88 </span> <span class="Constant">22</span>:num<span class="Special"> &lt;- </span><span class="Identifier">return</span>-continuation-until-mark <span class="Constant">233</span>/mark <span id="L89" class="LineNr"> 89 </span> <span class="Constant">23</span>:num<span class="Special"> &lt;- </span>add <span class="Constant">22</span>:num<span class="Delimiter">,</span> <span class="Constant">1</span> <span id="L90" class="LineNr"> 90 </span> <span class="Identifier">return</span> <span class="Constant">23</span>:num <span id="L91" class="LineNr"> 91 </span>] <span id="L92" class="LineNr"> 92 </span><span class="Comment"># first call of 'g' executes the part before return-continuation-until-mark</span> <span id="L93" class="LineNr"> 93 </span><span class="traceContains">+mem: storing 77 in location 21</span> <span id="L94" class="LineNr"> 94 </span><span class="traceContains">+run: {2: &quot;number&quot;} &lt;- copy {5: &quot;literal&quot;}</span> <span id="L95" class="LineNr"> 95 </span><span class="traceContains">+mem: storing 5 in location 2</span> <span id="L96" class="LineNr"> 96 </span><span class="Comment"># calls of the continuation execute the part after return-continuation-until-mark</span> <span id="L97" class="LineNr"> 97 </span><span class="traceContains">+run: {2: &quot;number&quot;} &lt;- call {1: &quot;continuation&quot;}, {2: &quot;number&quot;}</span> <span id="L98" class="LineNr"> 98 </span><span class="traceContains">+mem: storing 5 in location 22</span> <span id="L99" class="LineNr"> 99 </span><span class="traceContains">+mem: storing 6 in location 2</span> <span id="L100" class="LineNr">100 </span><span class="traceContains">+run: {2: &quot;number&quot;} &lt;- call {1: &quot;continuation&quot;}, {2: &quot;number&quot;}</span> <span id="L101" class="LineNr">101 </span><span class="traceContains">+mem: storing 6 in location 22</span> <span id="L102" class="LineNr">102 </span><span class="traceContains">+mem: storing 7 in location 2</span> <span id="L103" class="LineNr">103 </span><span class="traceContains">+run: {2: &quot;number&quot;} &lt;- call {1: &quot;continuation&quot;}, {2: &quot;number&quot;}</span> <span id="L104" class="LineNr">104 </span><span class="traceContains">+mem: storing 7 in location 22</span> <span id="L105" class="LineNr">105 </span><span class="traceContains">+mem: storing 8 in location 2</span> <span id="L106" class="LineNr">106 </span><span class="Comment"># first call of 'g' does not execute the part after return-continuation-until-mark</span> <span id="L107" class="LineNr">107 </span><span class="traceAbsent">-mem: storing 77 in location 22</span> <span id="L108" class="LineNr">108 </span><span class="Comment"># calls of the continuation don't execute the part before return-continuation-until-mark</span> <span id="L109" class="LineNr">109 </span><span class="traceAbsent">-mem: storing 5 in location 21</span> <span id="L110" class="LineNr">110 </span><span class="traceAbsent">-mem: storing 6 in location 21</span> <span id="L111" class="LineNr">111 </span><span class="traceAbsent">-mem: storing 7 in location 21</span> <span id="L112" class="LineNr">112 </span><span class="Comment"># termination</span> <span id="L113" class="LineNr">113 </span><span class="traceAbsent">-mem: storing 9 in location 2</span> <span id="L114" class="LineNr">114 </span> <span id="L115" class="LineNr">115 </span><span class="Delimiter">:(before &quot;End call Fields&quot;)</span> <span id="L116" class="LineNr">116 </span><span class="Normal">int</span> continuation_mark_tag<span class="Delimiter">;</span> <span id="L117" class="LineNr">117 </span><span class="Delimiter">:(before &quot;End call Constructor&quot;)</span> <span id="L118" class="LineNr">118 </span>continuation_mark_tag = <span class="Constant">0</span><span class="Delimiter">;</span> <span id="L119" class="LineNr">119 </span> <span id="L120" class="LineNr">120 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> <span id="L121" class="LineNr">121 </span>CALL_WITH_CONTINUATION_MARK<span class="Delimiter">,</span> <span id="L122" class="LineNr">122 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> <span id="L123" class="LineNr">123 </span><span class="Special">Recipe_ordinal</span>[<span class="Constant">&quot;call-with-continuation-mark&quot;</span>] = CALL_WITH_CONTINUATION_MARK<span class="Delimiter">;</span> <span id="L124" class="LineNr">124 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span id="L125" class="LineNr">125 </span><span class="Normal">case</span> CALL_WITH_CONTINUATION_MARK: <span class="Delimiter">{</span> <span id="L126" class="LineNr">126 </span> <span class="Normal">if</span> <span class="Delimiter">(</span><a href='001help.cc.html#L141'>SIZE</a><span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> &lt; <span class="Constant">2</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L127" class="LineNr">127 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span>get<span class="Delimiter">(</span><span class="Special">Recipe</span><span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'&quot;</span> &lt;&lt; to_original_string<span class="Delimiter">(</span>inst<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;' requires at least two ingredients: a mark number and a <a href='010vm.cc.html#L19'>recipe</a> to call\n&quot;</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L128" class="LineNr">128 </span> <span class="Delimiter">}</span> <span id="L129" class="LineNr">129 </span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span id="L130" class="LineNr">130 </span><span class="Delimiter">}</span> <span id="L131" class="LineNr">131 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span id="L132" class="LineNr">132 </span><span class="Normal">case</span> CALL_WITH_CONTINUATION_MARK: <span class="Delimiter">{</span> <span id="L133" class="LineNr">133 </span> <span class="Comment">// like call, but mark the current call as a 'base of continuation' call</span> <span id="L134" class="LineNr">134 </span> <span class="Comment">// before pushing the next one on it</span> <span id="L135" class="LineNr">135 </span> <span class="Normal">if</span> <span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L136" class="LineNr">136 </span> ++<span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth<span class="Delimiter">;</span> <span id="L137" class="LineNr">137 </span> <a href='003trace.cc.html#L189'>trace</a><span class="Delimiter">(</span><span class="Constant">&quot;trace&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;delimited continuation; incrementing callstack depth to &quot;</span> &lt;&lt; <span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L138" class="LineNr">138 </span> assert<span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth &lt; <span class="Constant">9000</span><span class="Delimiter">);</span> <span class="Comment">// 9998-101 plus cushion</span> <span id="L139" class="LineNr">139 </span> <span class="Delimiter">}</span> <span id="L140" class="LineNr">140 </span> <a href='010vm.cc.html#L33'>instruction</a><span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> caller_instruction = <a href='026call.cc.html#L89'>current_instruction</a><span class="Delimiter">();</span> <span id="L141" class="LineNr">141 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>front<span class="Delimiter">().</span>continuation_mark_tag = <a href='026call.cc.html#L89'>current_instruction</a><span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>value<span class="Delimiter">;</span> <span id="L142" class="LineNr">142 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>push_front<span class="Delimiter">(</span>call<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)));</span> <span id="L143" class="LineNr">143 </span> <span class="Comment">// drop the mark</span> <span id="L144" class="LineNr">144 </span> caller_instruction<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>caller_instruction<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">());</span> <span id="L145" class="LineNr">145 </span> ingredients<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">());</span> <span id="L146" class="LineNr">146 </span> <span class="Comment">// drop the callee</span> <span id="L147" class="LineNr">147 </span> caller_instruction<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>caller_instruction<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">());</span> <span id="L148" class="LineNr">148 </span> ingredients<span class="Delimiter">.</span>erase<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">());</span> <span id="L149" class="LineNr">149 </span> finish_call_housekeeping<span class="Delimiter">(</span>caller_instruction<span class="Delimiter">,</span> ingredients<span class="Delimiter">);</span> <span id="L150" class="LineNr">150 </span> <span class="Identifier">continue</span><span class="Delimiter">;</span> <span id="L151" class="LineNr">151 </span><span class="Delimiter">}</span> <span id="L152" class="LineNr">152 </span> <span id="L153" class="LineNr">153 </span><span class="Delimiter">:(scenario next_ingredient_inside_continuation)</span> <span id="L154" class="LineNr">154 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L155" class="LineNr">155 </span> call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f<span class="Delimiter">,</span><span class="Constant"> true</span> <span id="L156" class="LineNr">156 </span>] <span id="L157" class="LineNr">157 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> f [ <span id="L158" class="LineNr">158 </span> <span class="Constant">10</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>next-input <span id="L159" class="LineNr">159 </span>] <span id="L160" class="LineNr">160 </span><span class="traceContains">+mem: storing 1 in location 10</span> <span id="L161" class="LineNr">161 </span> <span id="L162" class="LineNr">162 </span><span class="Delimiter">:(scenario delimited_continuation_out_of_recipe_variable)</span> <span id="L163" class="LineNr">163 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L164" class="LineNr">164 </span> <span class="Normal">x</span>:<a href='010vm.cc.html#L19'>recipe</a><span class="Special"> &lt;- </span>copy f <span id="L165" class="LineNr">165 </span> call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> x<span class="Delimiter">,</span><span class="Constant"> true</span> <span id="L166" class="LineNr">166 </span>] <span id="L167" class="LineNr">167 </span><span class="muRecipe"><a href='010vm.cc.html#L19'>recipe</a></span> f [ <span id="L168" class="LineNr">168 </span> <span class="Constant">10</span>:<span class="Normal">bool</span><span class="Special"> &lt;- </span>next-input <span id="L169" class="LineNr">169 </span>] <span id="L170" class="LineNr">170 </span><span class="traceContains">+mem: storing 1 in location 10</span> <span id="L171" class="LineNr">171 </span> <span id="L172" class="LineNr">172 </span><span class="Comment">//: save the slice of current call stack until the 'call-with-continuation-mark'</span> <span id="L173" class="LineNr">173 </span><span class="Comment">//: call, and return it as the result.</span> <span id="L174" class="LineNr">174 </span><span class="Comment">//: todo: implement delimited continuations in Mu's memory</span> <span id="L175" class="LineNr">175 </span><span class="Delimiter">:(before &quot;End Types&quot;)</span> <span id="L176" class="LineNr">176 </span><span class="Normal">struct</span> delimited_continuation <span class="Delimiter">{</span> <span id="L177" class="LineNr">177 </span> call_stack frames<span class="Delimiter">;</span> <span id="L178" class="LineNr">178 </span> <span class="Normal">int</span> nrefs<span class="Delimiter">;</span> <span id="L179" class="LineNr">179 </span> delimited_continuation<span class="Delimiter">(</span>call_stack::iterator begin<span class="Delimiter">,</span> call_stack::iterator <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">)</span> :frames<span class="Delimiter">(</span>call_stack<span class="Delimiter">(</span>begin<span class="Delimiter">,</span> <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">)),</span> nrefs<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> <span class="Delimiter">{}</span> <span id="L180" class="LineNr">180 </span><span class="Delimiter">};</span> <span id="L181" class="LineNr">181 </span><span class="Delimiter">:(before &quot;End Globals&quot;)</span> <span id="L182" class="LineNr">182 </span>map&lt;<span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span><span class="Delimiter">,</span> delimited_continuation&gt; <span class="Special">Delimited_continuation</span><span class="Delimiter">;</span> <span id="L183" class="LineNr">183 </span><span class="Normal">long</span> <span class="Normal">long</span> <span class="Normal">int</span> <span class="Special">Next_delimited_continuation_id</span> = <span class="Constant">1</span><span class="Delimiter">;</span> <span class="Comment">// 0 is null just like an address</span> <span id="L184" class="LineNr">184 </span><span class="Delimiter">:(before &quot;End Reset&quot;)</span> <span id="L185" class="LineNr">185 </span><span class="Special">Delimited_continuation</span><span class="Delimiter">.</span><a href='050scenario.cc.html#L60'>clear</a><span class="Delimiter">();</span> <span id="L186" class="LineNr">186 </span><span class="Special">Next_delimited_continuation_id</span> = <span class="Constant">1</span><span class="Delimiter">;</span> <span id="L187" class="LineNr">187 </span> <span id="L188" class="LineNr">188 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Declarations&quot;)</span> <span id="L189" class="LineNr">189 </span>RETURN_CONTINUATION_UNTIL_MARK<span class="Delimiter">,</span> <span id="L190" class="LineNr">190 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Numbers&quot;)</span> <span id="L191" class="LineNr">191 </span><span class="Special">Recipe_ordinal</span>[<span class="Constant">&quot;return-continuation-until-mark&quot;</span>] = RETURN_CONTINUATION_UNTIL_MARK<span class="Delimiter">;</span> <span id="L192" class="LineNr">192 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Checks&quot;)</span> <span id="L193" class="LineNr">193 </span><span class="Normal">case</span> RETURN_CONTINUATION_UNTIL_MARK: <span class="Delimiter">{</span> <span id="L194" class="LineNr">194 </span> <span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>empty<span class="Delimiter">())</span> <span class="Delimiter">{</span> <span id="L195" class="LineNr">195 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span>get<span class="Delimiter">(</span><span class="Special">Recipe</span><span class="Delimiter">,</span> r<span class="Delimiter">).</span>name<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;'&quot;</span> &lt;&lt; to_original_string<span class="Delimiter">(</span>inst<span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;' requires at least one ingredient: a mark tag (number)\n&quot;</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L196" class="LineNr">196 </span> <span class="Delimiter">}</span> <span id="L197" class="LineNr">197 </span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span id="L198" class="LineNr">198 </span><span class="Delimiter">}</span> <span id="L199" class="LineNr">199 </span><span class="Delimiter">:(before &quot;End Primitive Recipe Implementations&quot;)</span> <span id="L200" class="LineNr">200 </span><span class="Normal">case</span> RETURN_CONTINUATION_UNTIL_MARK: <span class="Delimiter">{</span> <span id="L201" class="LineNr">201 </span> <span class="Comment">// I don't know how to think about next-ingredient in combination with</span> <span id="L202" class="LineNr">202 </span> <span class="Comment">// continuations, so seems cleaner to just kill it. Functions have to read</span> <span id="L203" class="LineNr">203 </span> <span class="Comment">// their inputs before ever returning a continuation.</span> <span id="L204" class="LineNr">204 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>front<span class="Delimiter">().</span>ingredient_atoms<span class="Delimiter">.</span><a href='050scenario.cc.html#L60'>clear</a><span class="Delimiter">();</span> <span id="L205" class="LineNr">205 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>front<span class="Delimiter">().</span>next_ingredient_to_process = <span class="Constant">0</span><span class="Delimiter">;</span> <span id="L206" class="LineNr">206 </span> <span class="Comment">// copy the current call stack until the most recent marked call</span> <span id="L207" class="LineNr">207 </span> call_stack::iterator find_base_of_continuation<span class="Delimiter">(</span>call_stack&amp;<span class="Delimiter">,</span> <span class="Normal">int</span><span class="Delimiter">);</span> <span class="Comment">// manual prototype containing '::'</span> <span id="L208" class="LineNr">208 </span> call_stack::iterator base = find_base_of_continuation<span class="Delimiter">(</span><span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">,</span> <span class="Comment">/*</span><span class="Comment">mark tag</span><span class="Comment">*/</span><a href='026call.cc.html#L89'>current_instruction</a><span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>value<span class="Delimiter">);</span> <span id="L209" class="LineNr">209 </span> <span class="Normal">if</span> <span class="Delimiter">(</span>base == <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">())</span> <span class="Delimiter">{</span> <span id="L210" class="LineNr">210 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span><a href='026call.cc.html#L87'>current_recipe_name</a><span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;couldn't find a 'call-with-continuation-mark' to return to with tag &quot;</span> &lt;&lt; current_instruction<span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; end<span class="Delimiter">();</span> <span id="L211" class="LineNr">211 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span><a href='026call.cc.html#L87'>current_recipe_name</a><span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;call stack:\n&quot;</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L212" class="LineNr">212 </span> <span class="Normal">for</span> <span class="Delimiter">(</span>call_stack::iterator p = <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span id="L213" class="LineNr">213 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span><a href='026call.cc.html#L87'>current_recipe_name</a><span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot; &quot;</span> &lt;&lt; get<span class="Delimiter">(</span><span class="Special">Recipe</span><span class="Delimiter">,</span> p<span class="Delimiter">-&gt;</span>running_recipe<span class="Delimiter">).</span>name &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L214" class="LineNr">214 </span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span id="L215" class="LineNr">215 </span> <span class="Delimiter">}</span> <span id="L216" class="LineNr">216 </span> <a href='003trace.cc.html#L189'>trace</a><span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;creating continuation &quot;</span> &lt;&lt; <span class="Special">Next_delimited_continuation_id</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L217" class="LineNr">217 </span> <a href='001help.cc.html#L221'>put</a><span class="Delimiter">(</span><span class="Special">Delimited_continuation</span><span class="Delimiter">,</span> <span class="Special">Next_delimited_continuation_id</span><span class="Delimiter">,</span> delimited_continuation<span class="Delimiter">(</span><span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>begin<span class="Delimiter">(),</span> base<span class="Delimiter">));</span> <span id="L218" class="LineNr">218 </span> <span class="Normal">while</span> <span class="Delimiter">(</span><span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>begin<span class="Delimiter">()</span> != base<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L219" class="LineNr">219 </span> <span class="Normal">if</span> <span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L220" class="LineNr">220 </span> --<span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth<span class="Delimiter">;</span> <span id="L221" class="LineNr">221 </span> assert<span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth &gt;= <span class="Constant">0</span><span class="Delimiter">);</span> <span id="L222" class="LineNr">222 </span> <span class="Delimiter">}</span> <span id="L223" class="LineNr">223 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>pop_front<span class="Delimiter">();</span> <span id="L224" class="LineNr">224 </span> <span class="Delimiter">}</span> <span id="L225" class="LineNr">225 </span> <span class="Comment">// return it as the result of the marked call</span> <span id="L226" class="LineNr">226 </span> products<span class="Delimiter">.</span>resize<span class="Delimiter">(</span><span class="Constant">1</span><span class="Delimiter">);</span> <span id="L227" class="LineNr">227 </span> products<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>push_back<span class="Delimiter">(</span><span class="Special">Next_delimited_continuation_id</span><span class="Delimiter">);</span> <span id="L228" class="LineNr">228 </span> <span class="Comment">// return any other ingredients passed in</span> <span id="L229" class="LineNr">229 </span> copy<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip mark tag</span><span class="Comment">*/</span>++ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">(),</span> ingredients<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">(),</span> inserter<span class="Delimiter">(</span>products<span class="Delimiter">,</span> products<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">()));</span> <span id="L230" class="LineNr">230 </span> ++<span class="Special">Next_delimited_continuation_id</span><span class="Delimiter">;</span> <span id="L231" class="LineNr">231 </span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Comment">// continue to process rest of marked call</span> <span id="L232" class="LineNr">232 </span><span class="Delimiter">}</span> <span id="L233" class="LineNr">233 </span> <span id="L234" class="LineNr">234 </span><span class="Delimiter">:(code)</span> <span id="L235" class="LineNr">235 </span>call_stack::iterator find_base_of_continuation<span class="Delimiter">(</span>call_stack&amp; c<span class="Delimiter">,</span> <span class="Normal">int</span> mark_tag<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L236" class="LineNr">236 </span> <span class="Normal">for</span> <span class="Delimiter">(</span>call_stack::iterator p = c<span class="Delimiter">.</span>begin<span class="Delimiter">();</span> p != c<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span id="L237" class="LineNr">237 </span> <span class="Normal">if</span> <span class="Delimiter">(</span>p<span class="Delimiter">-&gt;</span>continuation_mark_tag == mark_tag<span class="Delimiter">)</span> <span class="Identifier">return</span> p<span class="Delimiter">;</span> <span id="L238" class="LineNr">238 </span> <span class="Identifier">return</span> c<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L239" class="LineNr">239 </span><span class="Delimiter">}</span> <span id="L240" class="LineNr">240 </span> <span id="L241" class="LineNr">241 </span><span class="Comment">//: overload 'call' for continuations</span> <span id="L242" class="LineNr">242 </span><span class="Delimiter">:(after &quot;Begin Call&quot;)</span> <span id="L243" class="LineNr">243 </span><span class="Normal">if</span> <span class="Delimiter">(</span>is_mu_continuation<span class="Delimiter">(</span><a href='026call.cc.html#L89'>current_instruction</a><span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> <span id="L244" class="LineNr">244 </span> <span class="Comment">// copy multiple calls on to current call stack</span> <span id="L245" class="LineNr">245 </span> assert<span class="Delimiter">(</span>scalar<span class="Delimiter">(</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)));</span> <span id="L246" class="LineNr">246 </span> <a href='003trace.cc.html#L189'>trace</a><span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;calling continuation &quot;</span> &lt;&lt; ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L247" class="LineNr">247 </span> <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span><span class="Special">Delimited_continuation</span><span class="Delimiter">,</span> ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)))</span> <span id="L248" class="LineNr">248 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <a href='013update_operation.cc.html#L25'>maybe</a><span class="Delimiter">(</span><a href='026call.cc.html#L87'>current_recipe_name</a><span class="Delimiter">())</span> &lt;&lt; <span class="Constant">&quot;no such delimited continuation &quot;</span> &lt;&lt; <a href='026call.cc.html#L89'>current_instruction</a><span class="Delimiter">().</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>original_string &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L249" class="LineNr">249 </span> <span class="Normal">const</span> call_stack&amp; new_frames = get<span class="Delimiter">(</span><span class="Special">Delimited_continuation</span><span class="Delimiter">,</span> ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">).</span>at<span class="Delimiter">(</span><span class="Constant">0</span><span class="Delimiter">)).</span>frames<span class="Delimiter">;</span> <span id="L250" class="LineNr">250 </span> <span class="Normal">for</span> <span class="Delimiter">(</span>call_stack::const_reverse_iterator p = new_frames<span class="Delimiter">.</span>rbegin<span class="Delimiter">();</span> p != new_frames<span class="Delimiter">.</span>rend<span class="Delimiter">();</span> ++p<span class="Delimiter">)</span> <span id="L251" class="LineNr">251 </span> <span class="Special">Current_routine</span><span class="Delimiter">-&gt;</span>calls<span class="Delimiter">.</span>push_front<span class="Delimiter">(</span>*p<span class="Delimiter">);</span> <span id="L252" class="LineNr">252 </span> <span class="Normal">if</span> <span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L253" class="LineNr">253 </span> <span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth += <a href='001help.cc.html#L141'>SIZE</a><span class="Delimiter">(</span>new_frames<span class="Delimiter">);</span> <span id="L254" class="LineNr">254 </span> <a href='003trace.cc.html#L189'>trace</a><span class="Delimiter">(</span><span class="Constant">&quot;trace&quot;</span><span class="Delimiter">)</span> &lt;&lt; <span class="Constant">&quot;calling delimited continuation; growing callstack depth to &quot;</span> &lt;&lt; <span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L255" class="LineNr">255 </span> assert<span class="Delimiter">(</span><span class="Special">Trace_stream</span><span class="Delimiter">-&gt;</span>callstack_depth &lt; <span class="Constant">9000</span><span class="Delimiter">);</span> <span class="Comment">// 9998-101 plus cushion</span> <span id="L256" class="LineNr">256 </span> <span class="Delimiter">}</span> <span id="L257" class="LineNr">257 </span> <span class="Comment">// no call housekeeping; continuations don't support next-ingredient</span> <span id="L258" class="LineNr">258 </span> copy<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">drop continuation</span><span class="Comment">*/</span>++ingredients<span class="Delimiter">.</span>begin<span class="Delimiter">(),</span> ingredients<span class="Delimiter">.</span><a href='003trace.cc.html#L225'>end</a><span class="Delimiter">(),</span> inserter<span class="Delimiter">(</span>products<span class="Delimiter">,</span> products<span class="Delimiter">.</span>begin<span class="Delimiter">()));</span> <span id="L259" class="LineNr">259 </span> <span class="Identifier">break</span><span class="Delimiter">;</span> <span class="Comment">// record results of resuming 'return-continuation-until-mark' instruction</span> <span id="L260" class="LineNr">260 </span><span class="Delimiter">}</span> <span id="L261" class="LineNr">261 </span> <span id="L262" class="LineNr">262 </span><span class="Delimiter">:(scenario continuations_can_return_values)</span> <span id="L263" class="LineNr">263 </span><span class="muRecipe">def</span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L264" class="LineNr">264 </span> local-scope <span id="L265" class="LineNr">265 </span> <span class="Normal">k</span>:continuation<span class="Delimiter">,</span> <span class="Constant">1</span>:num/<span class="Special">raw &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f <span id="L266" class="LineNr">266 </span>] <span id="L267" class="LineNr">267 </span><span class="muRecipe">def</span> f [ <span id="L268" class="LineNr">268 </span> local-scope <span id="L269" class="LineNr">269 </span> g <span id="L270" class="LineNr">270 </span>] <span id="L271" class="LineNr">271 </span><span class="muRecipe">def</span> g [ <span id="L272" class="LineNr">272 </span> local-scope <span id="L273" class="LineNr">273 </span> <span class="Identifier">return</span>-continuation-until-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> <span class="Constant">34</span> <span id="L274" class="LineNr">274 </span> stash [continuation called] <span id="L275" class="LineNr">275 </span>] <span id="L276" class="LineNr">276 </span><span class="traceContains">+mem: storing 34 in location 1</span> <span id="L277" class="LineNr">277 </span> <span id="L278" class="LineNr">278 </span><span class="Delimiter">:(scenario continuations_continue_to_matching_mark)</span> <span id="L279" class="LineNr">279 </span><span class="muRecipe">def</span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L280" class="LineNr">280 </span> local-scope <span id="L281" class="LineNr">281 </span> <span class="Normal">k</span>:continuation<span class="Delimiter">,</span> <span class="Constant">1</span>:num/<span class="Special">raw &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f <span id="L282" class="LineNr">282 </span> add <span class="Constant">1</span><span class="Delimiter">,</span> <span class="Constant">1</span> <span id="L283" class="LineNr">283 </span>] <span id="L284" class="LineNr">284 </span><span class="muRecipe">def</span> f [ <span id="L285" class="LineNr">285 </span> local-scope <span id="L286" class="LineNr">286 </span> <span class="Normal">k2</span>:continuation<span class="Special"> &lt;- </span>call-with-continuation-mark <span class="Constant">234</span>/mark<span class="Delimiter">,</span> g <span id="L287" class="LineNr">287 </span> add <span class="Constant">2</span><span class="Delimiter">,</span> <span class="Constant">2</span> <span id="L288" class="LineNr">288 </span>] <span id="L289" class="LineNr">289 </span><span class="muRecipe">def</span> g [ <span id="L290" class="LineNr">290 </span> local-scope <span id="L291" class="LineNr">291 </span> <span class="Identifier">return</span>-continuation-until-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> <span class="Constant">34</span> <span id="L292" class="LineNr">292 </span> stash [continuation called] <span id="L293" class="LineNr">293 </span>] <span id="L294" class="LineNr">294 </span><span class="traceContains">+run: add {1: &quot;literal&quot;}, {1: &quot;literal&quot;}</span> <span id="L295" class="LineNr">295 </span><span class="traceAbsent">-run: add {2: &quot;literal&quot;}, {2: &quot;literal&quot;}</span> <span id="L296" class="LineNr">296 </span> <span id="L297" class="LineNr">297 </span><span class="Comment">//: Allow shape-shifting recipes to return continuations.</span> <span id="L298" class="LineNr">298 </span> <span id="L299" class="LineNr">299 </span><span class="Delimiter">:(scenario call_shape_shifting_recipe_with_continuation_mark)</span> <span id="L300" class="LineNr">300 </span><span class="muRecipe">def</span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L301" class="LineNr">301 </span> <span class="Constant">1</span>:num<span class="Special"> &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f<span class="Delimiter">,</span> <span class="Constant">34</span> <span id="L302" class="LineNr">302 </span>] <span id="L303" class="LineNr">303 </span><span class="muRecipe">def</span> f x:_elem<span class="muRecipe"> -&gt; </span>y:_elem [ <span id="L304" class="LineNr">304 </span> local-scope <span id="L305" class="LineNr">305 </span> load-ingredients <span id="L306" class="LineNr">306 </span> y<span class="Special"> &lt;- </span>copy x <span id="L307" class="LineNr">307 </span>] <span id="L308" class="LineNr">308 </span><span class="traceContains">+mem: storing 34 in location 1</span> <span id="L309" class="LineNr">309 </span> <span id="L310" class="LineNr">310 </span><span class="Delimiter">:(before &quot;End resolve_ambiguous_call(r, index, inst, caller_recipe) Special-cases&quot;)</span> <span id="L311" class="LineNr">311 </span><span class="Normal">if</span> <span class="Delimiter">(</span>inst<span class="Delimiter">.</span>name == <span class="Constant">&quot;call-with-continuation-mark&quot;</span><span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L312" class="LineNr">312 </span> <span class="Normal">if</span> <span class="Delimiter">(</span><a href='001help.cc.html#L141'>SIZE</a><span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">)</span> &gt; <span class="Constant">1</span> &amp;&amp; <a href='072recipe.cc.html#L208'>is_recipe_literal</a><span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip mark</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">)))</span> <span class="Delimiter">{</span> <span id="L313" class="LineNr">313 </span> resolve_indirect_continuation_call<span class="Delimiter">(</span>r<span class="Delimiter">,</span> index<span class="Delimiter">,</span> inst<span class="Delimiter">,</span> caller_recipe<span class="Delimiter">);</span> <span id="L314" class="LineNr">314 </span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span id="L315" class="LineNr">315 </span> <span class="Delimiter">}</span> <span id="L316" class="LineNr">316 </span><span class="Delimiter">}</span> <span id="L317" class="LineNr">317 </span><span class="Delimiter">:(code)</span> <span id="L318" class="LineNr">318 </span><span class="Normal">void</span> resolve_indirect_continuation_call<span class="Delimiter">(</span><span class="Normal">const</span> <a href='010vm.cc.html#L14'>recipe_ordinal</a> r<span class="Delimiter">,</span> <span class="Normal">int</span> index<span class="Delimiter">,</span> instruction&amp; inst<span class="Delimiter">,</span> <span class="Normal">const</span> recipe&amp; caller_recipe<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L319" class="LineNr">319 </span> <a href='010vm.cc.html#L33'>instruction</a> inst2<span class="Delimiter">;</span> <span id="L320" class="LineNr">320 </span> inst2<span class="Delimiter">.</span>name = inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip mark</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">).</span>name<span class="Delimiter">;</span> <span id="L321" class="LineNr">321 </span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Comment">/*</span><span class="Comment">skip mark and <a href='010vm.cc.html#L19'>recipe</a></span><span class="Comment">*/</span><span class="Constant">2</span><span class="Delimiter">;</span> i &lt; <a href='001help.cc.html#L141'>SIZE</a><span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span id="L322" class="LineNr">322 </span> inst2<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span id="L323" class="LineNr">323 </span> <span class="Normal">for</span> <span class="Delimiter">(</span><span class="Normal">int</span> i = <span class="Comment">/*</span><span class="Comment">skip continuation</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">;</span> i &lt; <a href='001help.cc.html#L141'>SIZE</a><span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">);</span> ++i<span class="Delimiter">)</span> <span id="L324" class="LineNr">324 </span> inst2<span class="Delimiter">.</span>products<span class="Delimiter">.</span>push_back<span class="Delimiter">(</span>inst<span class="Delimiter">.</span>products<span class="Delimiter">.</span>at<span class="Delimiter">(</span>i<span class="Delimiter">));</span> <span id="L325" class="LineNr">325 </span> <a href='054static_dispatch.cc.html#L173'>resolve_ambiguous_call</a><span class="Delimiter">(</span>r<span class="Delimiter">,</span> index<span class="Delimiter">,</span> inst2<span class="Delimiter">,</span> caller_recipe<span class="Delimiter">);</span> <span id="L326" class="LineNr">326 </span> inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip mark</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">).</span>name = inst2<span class="Delimiter">.</span>name<span class="Delimiter">;</span> <span id="L327" class="LineNr">327 </span> inst<span class="Delimiter">.</span>ingredients<span class="Delimiter">.</span>at<span class="Delimiter">(</span><span class="Comment">/*</span><span class="Comment">skip mark</span><span class="Comment">*/</span><span class="Constant">1</span><span class="Delimiter">).</span><a href='010vm.cc.html#L67'>set_value</a><span class="Delimiter">(</span>get<span class="Delimiter">(</span><span class="Special">Recipe_ordinal</span><span class="Delimiter">,</span> inst2<span class="Delimiter">.</span>name<span class="Delimiter">));</span> <span id="L328" class="LineNr">328 </span><span class="Delimiter">}</span> <span id="L329" class="LineNr">329 </span> <span id="L330" class="LineNr">330 </span><span class="Delimiter">:(scenario call_shape_shifting_recipe_with_continuation_mark_and_no_outputs)</span> <span id="L331" class="LineNr">331 </span><span class="muRecipe">def</span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L332" class="LineNr">332 </span> <span class="Constant">1</span>:continuation<span class="Special"> &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> f<span class="Delimiter">,</span> <span class="Constant">34</span> <span id="L333" class="LineNr">333 </span>] <span id="L334" class="LineNr">334 </span><span class="muRecipe">def</span> f x:_elem [ <span id="L335" class="LineNr">335 </span> local-scope <span id="L336" class="LineNr">336 </span> load-ingredients <span id="L337" class="LineNr">337 </span> <span class="Identifier">return</span>-continuation-until-mark <span class="Constant">233</span>/mark <span id="L338" class="LineNr">338 </span>] <span id="L339" class="LineNr">339 </span>$error: <span class="Constant">0</span> <span id="L340" class="LineNr">340 </span> <span id="L341" class="LineNr">341 </span><span class="Delimiter">:(scenario continuation1)</span> <span id="L342" class="LineNr">342 </span><span class="muRecipe">def</span> <a href='000organization.cc.html#L113'>main</a> [ <span id="L343" class="LineNr">343 </span> local-scope <span id="L344" class="LineNr">344 </span> <span class="Normal">k</span>:continuation<span class="Special"> &lt;- </span>call-with-continuation-mark <span class="Constant">233</span>/mark<span class="Delimiter">,</span> create-yielder <span id="L345" class="LineNr">345 </span> <span class="Constant">10</span>:num/<span class="Special">raw &lt;- </span>call k <span id="L346" class="LineNr">346 </span>] <span id="L347" class="LineNr">347 </span><span class="muRecipe">def</span> create-yielder<span class="muRecipe"> -&gt; </span>n:num [ <span id="L348" class="LineNr">348 </span> local-scope <span id="L349" class="LineNr">349 </span> load-inputs <span id="L350" class="LineNr">350 </span> <span class="Identifier">return</span>-continuation-until-mark <span class="Constant">233</span>/mark <span id="L351" class="LineNr">351 </span> <span class="Identifier">return</span> <span class="Constant">1</span> <span id="L352" class="LineNr">352 </span>] <span id="L353" class="LineNr">353 </span><span class="traceContains">+mem: storing 1 in location 10</span> <span id="L354" class="LineNr">354 </span>$error: <span class="Constant">0</span> <span id="L355" class="LineNr">355 </span> <span id="L356" class="LineNr">356 </span><span class="Delimiter">:(code)</span> <span id="L357" class="LineNr">357 </span><span class="Normal">bool</span> is_mu_continuation<span class="Delimiter">(</span>reagent<span class="Comment">/*</span><span class="Comment">copy</span><span class="Comment">*/</span> x<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L358" class="LineNr">358 </span> canonize_type<span class="Delimiter">(</span>x<span class="Delimiter">);</span> <span id="L359" class="LineNr">359 </span> <span class="Identifier">return</span> x<span class="Delimiter">.</span>type &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>atom &amp;&amp; x<span class="Delimiter">.</span>type<span class="Delimiter">-&gt;</span>value == get<span class="Delimiter">(</span><span class="Special">Type_ordinal</span><span class="Delimiter">,</span> <span class="Constant">&quot;continuation&quot;</span><span class="Delimiter">);</span> <span id="L360" class="LineNr">360 </span><span class="Delimiter">}</span> <span id="L361" class="LineNr">361 </span> <span id="L362" class="LineNr">362 </span><span class="Comment">// helper for debugging</span> <span id="L363" class="LineNr">363 </span><span class="Normal">void</span> dump<span class="Delimiter">(</span><span class="Normal">const</span> <span class="Normal">int</span> continuation_id<span class="Delimiter">)</span> <span class="Delimiter">{</span> <span id="L364" class="LineNr">364 </span> <span class="Normal">if</span> <span class="Delimiter">(</span>!contains_key<span class="Delimiter">(</span><span class="Special">Delimited_continuation</span><span class="Delimiter">,</span> continuation_id<span class="Delimiter">))</span> <span class="Delimiter">{</span> <span id="L365" class="LineNr">365 </span> <a href='003trace.cc.html#L196'>raise</a> &lt;&lt; <span class="Constant">&quot;missing delimited continuation: &quot;</span> &lt;&lt; continuation_id &lt;&lt; <span class="cSpecial">'\n'</span> &lt;&lt; <a href='003trace.cc.html#L225'>end</a><span class="Delimiter">();</span> <span id="L366" class="LineNr">366 </span> <span class="Identifier">return</span><span class="Delimiter">;</span> <span id="L367" class="LineNr">367 </span> <span class="Delimiter">}</span> <span id="L368" class="LineNr">368 </span> delimited_continuation&amp; curr = get<span class="Delimiter">(</span><span class="Special">Delimited_continuation</span><span class="Delimiter">,</span> continuation_id<span class="Delimiter">);</span> <span id="L369" class="LineNr">369 </span> dump<span class="Delimiter">(</span>curr<span class="Delimiter">.</span>frames<span class="Delimiter">);</span> <span id="L370" class="LineNr">370 </span><span class="Delimiter">}</span> </pre> </body> </html> <!-- vim: set foldmethod=manual : -->