-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathInteractive Debugger.i7x
4627 lines (4047 loc) · 291 KB
/
Interactive Debugger.i7x
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
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Version 1 of Interactive Debugger (for Glulx only) by Brady Garvin begins here.
"Commands to see what goes on inside an executing story."
Include Runtime Checks by Brady Garvin.
Include Low-Level Operations by Brady Garvin.
Include Low-Level Text by Brady Garvin.
Include Low-Level Linked Lists by Brady Garvin.
Include Low-Level Hash Tables by Brady Garvin.
Include Glk Window Wrappers by Brady Garvin.
Include Out-of-Band State Protection by Brady Garvin.
Include Output Interception by Brady Garvin.
Include Punctuated Word Parsing Engine by Brady Garvin.
Include Human-Friendly Function Names by Brady Garvin.
Include Glulx Runtime Instrumentation Framework by Brady Garvin.
Include Debug File Parsing by Brady Garvin.
Include Call Stack Tracking by Brady Garvin.
Include Breakpoints by Brady Garvin.
Include Verbose Diagnostics by Brady Garvin.
Include Printing according to Kind Names by Brady Garvin.
Use authorial modesty.
Book "Copyright and License"
[Copyright 2013 Brady J. Garvin]
[This extension is released under the Creative Commons Attribution 3.0 Unported License (CC BY 3.0) so that it can qualify as a public Inform extension. See the LICENSE file included in the release for further details.]
Book "Extension Information"
[For each of the kinds defined by Interactive Debugger you will see a sentence like
A stream log is an invalid stream log.
This bewildering statement actually sets up stream logs as a qualitative value with default value the stream log at address one, which, as we say, is invalid. (We could have gone with a quantitative kind for default zero, but then we would open up the possibility for arithmetic on the pointers.) I wish it weren't necessary, but at least in this build Inform doesn't let us provide a default value any other way, and, moreover, we need a default value or else only I6 substitutions are allowed to decide on stream logs.]
Chapter "Use Options"
Use no more than one line input request at a time translates as (- Constant ID_SERIALIZE_LINE_REQUESTS; -).
Use an ideal emulated timer resolution of at least 50 translates as (- Constant ID_IDEAL_TIMER_RESOLUTION={N}; -).
To decide what number is the ideal emulated timer resolution: (- ID_IDEAL_TIMER_RESOLUTION -).
Use the right of the window for the debugger translates as (- Constant ID_RIGHT; -).
Use the left of the window for the debugger translates as (- Constant ID_LEFT; -).
Use the bottom of the window for the debugger translates as (- Constant ID_BOTTOM; -).
Use the top of the window for the debugger translates as (- Constant ID_TOP; -).
Use a debug command buffer size of at least 1024 translates as (- Constant ID_MAX_COMMAND_LENGTH={N}; -).
Use a minimum stream log capacity of at least 1024 translates as (- Constant ID_MIN_STREAM_LOG_CAPACITY={N}; -).
To decide what number is the minimum stream log capacity: (- ID_MIN_STREAM_LOG_CAPACITY -).
Use a user breakpoint hash table size of at least 23 translates as (- Constant ID_USER_BREAKPOINT_HASH_SIZE={N}; -).
Use a user breaktext hash table size of at least 23 translates as (- Constant ID_USER_BREAKTEXT_HASH_SIZE={N}; -).
Use a stream log hash table size of at least 23 translates as (- Constant ID_STREAM_LOG_HASH_SIZE={N}; -).
Use a debugger disambiguation hash table size of at least 11 translates as (- Constant ID_DISAMBIGUATION_HASH_SIZE={N}; -).
Use of debug command parse tree vertex hash table size of at least 23 translates as (- Constant ID_COMMAND_VERTEX_HASH_SIZE={N}; -).
Use of debug command parseme hash table size of at least 311 translates as (- Constant ID_COMMAND_PARSEME_HASH_SIZE={N}; -).
To decide what number is the user breakpoint hash table size: (- ID_USER_BREAKPOINT_HASH_SIZE -).
To decide what number is the user breaktext hash table size: (- ID_USER_BREAKTEXT_HASH_SIZE -).
To decide what number is the stream log hash table size: (- ID_STREAM_LOG_HASH_SIZE -).
To decide what number is the debugger disambiguation hash table size: (- ID_DISAMBIGUATION_HASH_SIZE -).
To decide what number is the debug command parse tree vertex hash table size: (- ID_COMMAND_VERTEX_HASH_SIZE -).
To decide what number is the debug command parseme hash table size: (- ID_COMMAND_PARSEME_HASH_SIZE -).
Use a disambiguation listing length of at least 4 translates as (- Constant ID_DISAMBIGUATION_LISTING_LENGTH={N}; -).
Use a listing window of at least 10 translates as (- Constant ID_LISTING_WINDOW={N}; -).
Use a threshold for lengthy listings of at least 32 translates as (- Constant ID_LENGTHY_LISTING={N}; -).
To decide what number is the disambiguation listing length: (- ID_DISAMBIGUATION_LISTING_LENGTH -).
To decide what number is the listing window radius: (- (ID_LISTING_WINDOW/2) -).
To decide what number is the threshold for lengthy listings: (- ID_LENGTHY_LISTING -).
Chapter "Forced Use Options"
Use universal breakpoint flags of at least 2. [Index zero for Inform internals, index one for everything else.]
Chapter "Constants" - unindexed
To decide what number is the effectively infinite listing limit: (- 134217727 -).
Chapter "Temporary Workarounds" - unindexed
To handle the debug command rooted at (V - a parse tree vertex) using a workaround for Inform bug 825:
handle the debug command rooted at V.
Book "Runtime Checks"
Chapter "Messages" - unindexed
To fail at requesting multiple debug commands:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I tried to request a debug command before the previous request had been fulfilled.[terminating the story]".
To fail at using debug command disambiguating for a non-question:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I was asked to ask a debug command disambiguation question with only one possible answer; the disambiguation machinery must have gone awry.[terminating the story]".
To fail at finding a routine record for a sequence point with a source line record:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I tried to find the debug information for a function, but couldn't, even though I have debug information for lines within that function.[terminating the story]".
To fail at finding I7 in a line shared by several routines:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I tried to find the routine containing a line of I7, but found either zero or several routines.[terminating the story]".
To fail at encountering a divider in the last-seen call stack:
say "[low-level runtime failure in]Interactive Debugger[with explanation]As the call stack was not empty when I last showed the debug prompt, I would have expected one of its frames to have been selected at that time too. But my bookkeeping argues otherwise.[terminating the story]".
To fail at matching a divider when finish is ignoring an interruption:
say "[low-level runtime failure in]Interactive Debugger[with explanation]As the call stack was not enough of an argument to convince the debug command 'finish' to consider itself complete, I would have expected the frame that was selected when I last showed the debug prompt to still be around. But my bookkeeping argues otherwise.[terminating the story]".
To fail at finding a routine record for a kernel:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I was able to find a routine kernel, but no routine record for that kernel, which is awfully strange. Probably my bookkeeping has been corrupted.[terminating the story]".
To fail at finding a preamble for a routine shell:
say "[runtime failure in]Interactive Debugger[with explanation]I was able to find a routine shell, but no I7 preamble for that shell. Probably my bookkeeping has been corrupted.[continuing anyway]".
To fail at forcing a breakpoint from the debugger in an unknown coexecution state:
say "[runtime failure in]Interactive Debugger[with explanation]I failed to consistently determine the execution state of the story, and am unable to report any caveats that might apply to this forced breakpoint, or even whether it will apply at all.[continuing anyway]".
To fail at being the first to run the story:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I tried to run the story for the first time, but my bookkeeping indicates that it is already running. I must therefore be confused.[terminating the story]".
To fail at recovering the debugger windows:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I couldn't tell which of the existing windows are the ones belonging to the debugger, and am therefore unable to reclaim them.[terminating the story]".
To fail at iterating from a given sequence point:
say "[runtime failure in]Interactive Debugger[with explanation]I failed to find the assembly instruction at what I believed to be a sequence point; either the code has changed while the story was running or I have become confused.[continuing anyway]".
To fail at understanding a debugging language:
say "[runtime failure in]Interactive Debugger[with explanation]I failed to understand the given debugging language. Probably my grammar has been updated to include it, but the code for translating it to a debug mode has not.[continuing anyway]".
To fail at finding the text for a breaktext:
say "[runtime failure in]Interactive Debugger[with explanation]I failed to find (let alone understand) the given text when given a command to create a breaktext. Probably my grammar and my text extraction code disagree on formatting details.[continuing anyway]".
To fail at checking retired characters in a stream log:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I attempted to check recent output for a breaktext, but the stream log was too short. The code to rotate long output through short logs probably has a bug.[terminating the story]".
To fail at recognizing a debugger serialization format:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I attempted to deserialize the debugger state from a temporary file, but found that the file doesn't adhere to a format I recognize.[terminating the story]".
To fail at serializing the debugger's parse of a command:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I attempted to serialize a parse tree of one of your commands, but discovered in it unencodable inconsistencies.[terminating the story]".
To fail at deserializing the debugger's parse of a command:
say "[low-level runtime failure in]Interactive Debugger[with explanation]I attempted to deserialize a parse tree of one of your commands, but found it undecodable.[terminating the story]".
Book "Simulated Parallelism"
Part "Parallelism State" - unindexed
Chapter "Running and Continuing Flags" - unindexed
The debugger's story-restarted flag is a truth state that varies. The debugger's story-restarted flag is false.
The debugger's story-has-run flag is a truth state that varies. The debugger's story-has-run flag is false.
The debugger's story-running flag is a truth state that varies. The debugger's story-running flag is false.
The debugger's story-continuing flag is a truth state that varies. The debugger's story-continuing flag is false.
Chapter "Coexecution State" - unindexed
A debugger coexecution state is a kind of value.
The debugger coexecution states are story interrupted, story waiting for input, and story unpaused.
The current debugger coexecution state is a debugger coexecution state that varies. The current debugger coexecution state is story unpaused.
The debugger input event flushing flag is a truth state that varies. The debugger input event flushing flag is false.
The debugger prompting flag is a truth state that varies. The debugger prompting flag is true.
Part "Separation of the VM and Story Startup"
Chapter "Initial Breakpoint"
A last GRIF instrumented post-hijacking rule (this is the initial breakpoint rule):
force a breakpoint named "The initial breakpoint";
now the debugger's story-running flag is true.
Part "Separation of the VM and Story Shutdown"
Chapter "Idle on Quit" - unindexed
Include (-
Array id_ignoredEvent --> 4;
[ id_idleOnQuit;
(+ the debugger's story-running flag +)=false;
for(::){
glk_select(id_ignoredEvent);
}
];
-).
To decide what number is the address of the idle-on-quit routine: (- id_idleOnQuit -).
Chapter "Limiting Story Quits"
Section "Temporary Space for Limiting Story Quits" - unindexed
Include (-
Array id_glkPops --> 8;
-).
To decide what number is where stack pops from Glk invocations are temporarily saved for limiting story quits: (- id_glkPops -).
Section "Instruction Vertices for Limiting Story Quits" - unindexed
[ @callf <idle-on-quit-function> 0; ]
To decide what instruction vertex is a new idle-on-quit instruction vertex:
decide on a new artificial instruction vertex for a zero-argument call to the function at address the address of the idle-on-quit routine with return mode the zero-or-discard addressing mode.
[ @jeq <P-in-mode-M> 1 <constant>; ]
To decide what instruction vertex is a new conditional jump-to-idle-on-quit instruction vertex for mode (M - an addressing mode) and parameter (P - a number):
let the result be a new artificial instruction vertex;
write the operation code op-jeq to the result;
write the addressing mode M to parameter zero of the result;
write P to parameter zero of the result;
write the addressing mode constant addressing mode to parameter one of the result;
write one to parameter one of the result;
write the addressing mode constant addressing mode to parameter two of the result;
decide on the result.
Section "Instrumentation Rule for Limiting Story Quits"
A GRIF instrumentation rule (this is the limit effects of story quits to the story rule):
if the no more than one line input request at a time option is not active:
repeat with the instruction vertex running through occurrences of the operation code op-quit in the scratch space:
write the operation code op-callf to the instruction vertex;
write the addressing mode constant addressing mode to parameter zero of the instruction vertex;
write the address of the idle-on-quit routine to parameter zero of the instruction vertex;
write the addressing mode zero-or-discard addressing mode to parameter one of the instruction vertex;
repeat with the instruction vertex running through occurrences of the operation code op-glk in the scratch space:
let the addressing mode be the addressing mode of parameter zero of the instruction vertex;
if the addressing mode is the constant addressing mode:
if parameter zero of the instruction vertex is one:
write the operation code op-callf to the instruction vertex;
write the addressing mode constant addressing mode to parameter zero of the instruction vertex;
write the address of the idle-on-quit routine to parameter zero of the instruction vertex;
write the addressing mode zero-or-discard addressing mode to parameter one of the instruction vertex;
otherwise if the addressing mode is not the zero-or-discard addressing mode:
cleanse the instruction vertex of stack pops using the array at address where stack pops from Glk invocations are temporarily saved for limiting story quits;
now the addressing mode is the addressing mode of parameter zero of the instruction vertex;
let the parameter be parameter zero of the instruction vertex;
let the jump-to-idle-on-quit instruction vertex be a new conditional jump-to-idle-on-quit instruction vertex for mode the addressing mode and parameter the parameter;
let the idle-on-quit instruction vertex be a new idle-on-quit instruction vertex;
insert the jump-to-idle-on-quit instruction vertex before the instruction vertex;
insert the idle-on-quit instruction vertex at the end of the arrangement;
establish a jump link from the jump-to-idle-on-quit instruction vertex to the idle-on-quit instruction vertex.
Chapter "Limiting Story Restarts"
Section "Restart from Debugger" - unindexed
To clear pending requests from the extra Glk state (this is clearing pending requests from the extra Glk state):
repeat with the linked list vertex running through the extra Glk stream state hash table:
write the value the extra Glk stream state value of the linked list vertex with no character input pending with no line input pending to the linked list vertex.
Include (-
[ id_restart window;
(llo_getField((+ canceling any request for a debug input line +),1))();
for(window=0:window=glk_window_iterate(window,0):){
switch (glk_window_get_type(window)) {
wintype_Pair:
wintype_Blank:
wintype_TextBuffer:
glk_cancel_char_event(window);
glk_cancel_line_event(window,0);
glk_cancel_hyperlink_event(window);
wintype_TextGrid:
glk_cancel_char_event(window);
glk_cancel_line_event(window,0);
glk_cancel_mouse_event(window);
glk_cancel_hyperlink_event(window);
wintype_Graphics:
glk_cancel_mouse_event(window);
default:
glk_cancel_char_event(window);
glk_cancel_line_event(window,0);
glk_cancel_mouse_event(window);
glk_cancel_hyperlink_event(window);
}
}
(llo_getField((+ clearing pending requests from the extra Glk state +),1))();
(llo_getField((+ serializing protected state +),1))();
@restart;
];
-).
To decide what number is restarting the story from the debugger: (- id_restart -).
To restart the story from the debugger: (- id_restart(); -).
Section "Shielding for Limiting Story Restarts"
A GRIF shielding rule (this is the shield restarting the story from the debugger rule):
shield restarting the story from the debugger against instrumentation.
Section "Instrumentation Rule for Limiting Story Restarts"
A last GRIF instrumentation rule (this is the limit effects of story restarts to the story rule):
repeat with the instruction vertex running through occurrences of the operation code op-restart in the scratch space:
write the operation code op-callf to the instruction vertex;
write the addressing mode constant addressing mode to parameter zero of the instruction vertex;
write restarting the story from the debugger to parameter zero of the instruction vertex;
write the addressing mode zero-or-discard addressing mode to parameter one of the instruction vertex.
Part "Transfer of Control"
Chapter "Forcing a Breakpoint as an Out-of-World Action"
Forcing a breakpoint is an action out of world applying to nothing.
Understand "force a breakpoint" as forcing a breakpoint.
Carry out forcing a breakpoint:
force a breakpoint named "The out-of-world action 'forcing a breakpoint'".
Part "User Interface" - unindexed
Chapter "Window Wrapping" - unindexed
The debugger wrapping layer is a wrapping layer that varies.
The debugger side window is a wrapped window that varies.
Section "Window Constructors" - unindexed
Include (-
#ifdef ID_RIGHT;
Constant ID_METHOD_INDEX=0;
#ifnot;
#ifdef ID_LEFT;
Constant ID_METHOD_INDEX=1;
#ifnot;
#ifdef ID_BOTTOM;
Constant ID_METHOD_INDEX=2;
#ifnot;
#ifdef ID_TOP;
Constant ID_METHOD_INDEX=3;
#ifnot;
Constant ID_METHOD_INDEX=0;
#endif;
#endif;
#endif;
#endif;
-) after "Definitions.i6t".
Include (-
[ id_method;
switch(ID_METHOD_INDEX){
1:
return winmethod_Right+winmethod_Proportional;
2:
return winmethod_Above+winmethod_Proportional;
3:
return winmethod_Below+winmethod_Proportional;
}
return winmethod_Left+winmethod_Proportional;
];
-).
To decide what wrapped window is a new debugger root window: (- glk_window_open(0,0,0,wintype_TextBuffer,0) -).
To decide what wrapped window is a new frame window split off of the debugger root window: (- glk_window_open(glk_window_get_root(),id_method(),50,wintype_Blank,0) -).
To decide whether (W - a wrapped window) could be a frame window: (- (glk_window_get_type({W})==wintype_Blank) -).
Section "Window Accessors" - unindexed
To decide what wrapped window is the debugger window:
if the multiple windows supported flag is set in the debugger wrapping layer:
decide on the debugger side window;
decide on the sole window according to the Glk layer after the debugger wrapping layer.
Section "Glk Layer" - unindexed
The debugger's emulated timer resolution is a number that varies. The debugger's emulated timer resolution is zero.
The debugger's emulated timer interval is a number that varies. The debugger's emulated timer interval is zero.
The debugger's emulated timer interval remaining is a number that varies. The debugger's emulated timer interval remaining is zero.
To hide the debugger window wrapping (this is hiding the debugger window wrapping):
if the multiple windows supported flag is set in the debugger wrapping layer and the no more than one line input request at a time option is not active:
if the function selector of the current Glk invocation is:
-- 214: [glk_request_timer_events]
now the debugger's emulated timer interval is argument number zero of the current Glk invocation;
now the debugger's emulated timer interval remaining is the debugger's emulated timer interval;
if the debugger's emulated timer interval is less than the ideal emulated timer resolution:
now the debugger's emulated timer resolution is the debugger's emulated timer interval;
otherwise:
now the debugger's emulated timer resolution is the ideal emulated timer resolution;
write the debugger's emulated timer resolution to argument number zero of the current Glk invocation;
if timestamps are supported:
let the discarded value be the number of milliseconds elapsed since the last timestamp;
hide window wrapping with the debugger wrapping layer.
Section "Glk Layer Notification Handler for the Glk Layer" - unindexed
To handle the Glk layer notification (N - a Glk layer notification) for the debugger wrapping layer (this is handling a Glk layer notification for the debugger wrapping layer):
if N is:
-- Glk recovery needed:
recover windows and streams for the debugger wrapping layer;
if the multiple windows supported flag is set in the debugger wrapping layer:
let the root be the root wrapped window;
if the root is null:
now the debugger side window is a new debugger root window;
let the frame be a new frame window split off of the debugger root window;
write the frame window the frame to the debugger wrapping layer;
otherwise:
let the frame be the key of the root;
now the debugger side window is the first child of the root according to the debugger wrapping layer;
let the debugger side window's sibling be the second child of the root according to the debugger wrapping layer;
if the first child of the debugger side window's sibling according to the debugger wrapping layer is null:
if the first child of the debugger side window according to the debugger wrapping layer is null:
if the debugger side window could be a frame window:
let the swap variable be the debugger side window's sibling;
now the debugger side window's sibling is the debugger side window;
now the debugger side window is the swap variable;
otherwise:
always check that the debugger side window's sibling could be a frame window or else fail at recovering the debugger windows;
otherwise:
let the swap variable be the debugger side window's sibling;
now the debugger side window's sibling is the debugger side window;
now the debugger side window is the swap variable;
delete the root from the debugger wrapping layer;
delete the debugger side window from the debugger wrapping layer;
unless the debugger side window's sibling is the frame:
delete the debugger side window's sibling from the debugger wrapping layer;
delete the frame from the debugger wrapping layer;
write the frame window the frame to the debugger wrapping layer;
otherwise:
now the debugger side window is a null wrapped window;
write the frame window a null wrapped window to the debugger wrapping layer;
while within the debugger window via the debugger wrapping layer:
say "[the debugger banner text]";
cancel any request for a debug input line;
-- story yielding:
if the multiple windows supported flag is set in the debugger wrapping layer and the no more than one line input request at a time option is not active:
prepare a spontaneous Glk invocation;
write the function selector 214 [glk_request_timer_events] to the current Glk invocation;
write the argument count one to the current Glk invocation;
write one to argument number zero of the current Glk invocation;
delegate the current Glk invocation to the Glk layer after the debugger wrapping layer;
now the current debugger coexecution state is story unpaused;
now the debugger input event flushing flag is true;
wait for the next foreign event using the debugger wrapping layer;
now the current debugger coexecution state is story waiting for input;
now the debugger input event flushing flag is false;
prepare a spontaneous Glk invocation;
write the function selector 214 [glk_request_timer_events] to the current Glk invocation;
write the argument count one to the current Glk invocation;
write the debugger's emulated timer resolution to argument number zero of the current Glk invocation;
delegate the current Glk invocation to the Glk layer after the debugger wrapping layer.
Section "Event Handler for the Glk Layer" - unindexed
Include (-
Array id_command -> ID_MAX_COMMAND_LENGTH ;
-) after "Definitions.i6t".
To decide what number is the address of the debug command buffer: (- id_command -).
To decide what number is the maximum length of the debug command buffer: (- ID_MAX_COMMAND_LENGTH -).
The debugger's line input handler is a phrase text -> nothing that varies.
Include (-
#ifndef gestalt_DateTime;
Constant gestalt_DateTime 20;
#endif;
#ifndef glk_current_time;
[ glk_current_time _vararg_count ret;
! glk_current_time (time)
! And now the @glk call
@glk $160 _vararg_count ret;
return ret;
];
#endif;
-) after "Definitions.i6t".
Include (-
Array id_previousTimestamp --> 3;
Array id_timestamp --> 3;
[ id_timestampSupport;
return glk_gestalt(gestalt_DateTime,0);
];
[ id_getMsTimestampDifference
highDifference lowDifference microDifference test;
llo_copy(12,id_timestamp,id_previousTimestamp);
glk_current_time(id_timestamp);
highDifference=(id_timestamp-->0)-(id_previousTimestamp-->0);
lowDifference=(id_timestamp-->1)-(id_previousTimestamp-->1);
microDifference=(id_timestamp-->2)-(id_previousTimestamp-->2);
if(microDifference<0){
microDifference=microDifference+1000000;
lowDifference=lowDifference-1;
}
@jgtu lowDifference 2147482 ?overflow;
if(((id_timestamp-->1)>0)&&((id_previousTimestamp-->1)<0)){
highDifference=highDifference-1;
}
if(highDifference){
.overflow;
return 2147483647;
}
return lowDifference*1000+microDifference/1000;
];
-).
To decide what number is the address of the timestamp-support-checking function: (- id_timestampSupport -).
To decide what number is the address of the timestamp differencing function: (- id_getMsTimestampDifference -).
A GRIF shielding rule (this is the shield timestamp functions for timer emulation rule):
shield the address of the timestamp-support-checking function against instrumentation;
shield the address of the timestamp differencing function against instrumentation.
To decide whether timestamps are supported: (- id_timestampSupport() -).
To decide what number is the number of milliseconds elapsed since the last timestamp: (- id_getMsTimestampDifference() -).
To decide what event routing decision is the event routing decision after handling (E - a wrapped event) for the debugger wrapping layer (this is handling a wrapped event for the debugger wrapping layer):
if the event type of E is the timer event type and the multiple windows supported flag is set in the debugger wrapping layer and the no more than one line input request at a time option is not active:
if the debugger input event flushing flag is false:
if timestamps are supported:
decrease the debugger's emulated timer interval remaining by the number of milliseconds elapsed since the last timestamp;
otherwise:
decrease the debugger's emulated timer interval remaining by the debugger's emulated timer resolution;
if the debugger's emulated timer interval remaining is at most zero:
now the debugger's emulated timer interval remaining is the debugger's emulated timer interval;
decide on routing the event normally;
decide on routing the event no further;
if the event type of E is the line input event type:
while within the debugger window via the debugger wrapping layer:
let the remembered handler be the debugger's line input handler;
now the debugger's line input handler is the default value of phrase text -> nothing;
let the length be the first associated value of E;
let the command be a new synthetic text extracted from the length bytes at address the address of the debug command buffer;
apply the remembered handler to the command;
delete the synthetic text the command;
decide on routing the event normally.
Section "Input Requests" - unindexed
To cancel any request for a debug input line (this is canceling any request for a debug input line):
if the debugger's line input handler is the default value of phrase text -> nothing:
stop;
prepare a spontaneous Glk invocation;
write the function selector 209 [glk_cancel_line_event] to the current Glk invocation;
write the argument count two to the current Glk invocation;
write the debugger window to argument number zero of the current Glk invocation;
write zero to argument number one of the current Glk invocation;
delegate the current Glk invocation to the Glk layer after the debugger wrapping layer;
now the debugger's line input handler is the default value of phrase text -> nothing;
while within the debugger window via the debugger wrapping layer:
say "(input interrupted)[line break]".
To request a debug input line to be handled by (H - a phrase text -> nothing):
always check that the debugger's line input handler is the default value of phrase text -> nothing or else fail at requesting multiple debug commands;
now the debugger's line input handler is H;
prepare a spontaneous Glk invocation;
write the function selector 208 [glk_request_line_event] to the current Glk invocation;
write the argument count four to the current Glk invocation;
write the debugger window to argument number zero of the current Glk invocation;
write the address of the debug command buffer to argument number one of the current Glk invocation;
write the maximum length of the debug command buffer to argument number two of the current Glk invocation;
write zero to argument number three of the current Glk invocation;
delegate the current Glk invocation to the Glk layer after the debugger wrapping layer.
Section "The Layering Rule" - unindexed
A Glk layering rule (this is the debugger window wrapper rule):
install hiding the debugger window wrapping as the debugger wrapping layer whose Glk layer notifications are handled by handling a Glk layer notification for the debugger wrapping layer and whose foreign events are handled by handling a wrapped event for the debugger wrapping layer.
Book "Debugger State"
Chapter "Debug Modes"
A debug mode is a kind of value. The debug modes are debugging at the I7 level, debugging at the I6 level, and debugging at the Glulx assembly level.
The specification of a debug mode is "Debug modes represent a preferred language for debugging: I7, I6, or Glulx assembly."
Section "Preferred Debug Modes" - unindexed
The currently preferred debug mode is a debug mode that varies. The currently preferred debug mode is debugging at the I7 level.
To decide what debug mode is the preferred debug mode for (R - a routine record):
if R is an invalid routine record or the function at address the function address of R is a default veneer routine:
decide on debugging at the Glulx assembly level;
if the source version of R is less than seven:
decide on debugging at the I6 level;
decide on debugging at the I7 level.
Chapter "Preferences"
[GRIF defines:]
[The GRIF allows saves flag is a truth state that varies.]
[Call Stack Tracking defines:]
[The original arguments flag is a truth state that varies.
The temporary named values flag is a truth state that varies.
The catch tokens flag is a truth state that varies.
The call stack simplification flag is a truth state that varies.
The call frame numbering flag is a truth state that varies.
The call stack addresses flag is a truth state that varies.]
Section "Warnings"
The showme warnings flag is a truth state that varies.
The lengthly listing warnings flag is a truth state that varies.
Section "Default Preferences"
A GRIF setup rule (this is the default debugger preferences rule):
now the original arguments flag is true;
now the temporary named values flag is true;
now the catch tokens flag is false;
now the call stack simplification flag is true;
now the call frame numbering flag is true;
now the showme warnings flag is true;
now the lengthly listing warnings flag is true;
now the GRIF allows saves flag is false.
Chapter "Current Call Frame" - unindexed
The debugger's current call frame number is a number that varies.
The debugger's current call frame is a call frame that varies.
Section "Sequence Point to Highlight" - unindexed
To decide what number is the sequence point to highlight:
decide on the last-seen sequence point of the debugger's current call frame or the last-seen sequence point before the last-seen breakpoint if it is innermost.
Chapter "Control Flow Manipulation" - unindexed
A debugger control flow state is a kind of value. The debugger control flow states are responding after a continue, responding after a sequence point step, responding after a sequence point next, responding after a step, responding after a next, and responding after a finish. The specification of a debugger control flow state is "Debugger control flow states are used by the debugger to remember what it was doing when it receives a breakpoint notification. Generally they record the last command executed."
A debugger control flow attitude is a kind of value. The debugger control flow attitude are responding after a cautious advance and responding after an assured advance. The specification of a debugger control flow attitude is "Debugger control flow attitudes are used by the debugger to remember how it was proceeding when it receives a breakpoint notification. Cautious advances, those that check on the story state at every opportunity, are used until the debugger is free from at least one previously seen breakpoint. Assured advances are used thereafter, and pause only as needed for the command they carry out."
[This is the control flow state, as described above.]
The debugger's control flow state is a debugger control flow state that varies.
[This is the control flow attitude, as described above.]
The debugger's control flow attitude is a debugger control flow attitude that varies.
[We remember what the call stack looked like by keeping a copy here. More specifically, we store the *outermost* call frame, since that makes life easier in the main debugger routine. Be careful: not all call frame phrases work if we've changed the call stack in the meantime.]
The last-seen call stack root is a call frame that varies.
[We also keep track of the frame that was selected.]
The last-seen call stack divider is a call frame that varies.
[And on top of that, the sequence point last seen.]
The last-seen sequence point for the last-seen call stack is a number that varies.
[If we were stopped by one or more breakpoints last time we talked with the author we don't want to report those breakpoints again unless the set has changed. So we keep the old set here.]
The last-seen compound breakpoint list is a linked list that varies.
Chapter "User Breakpoints" - unindexed
[Maps breakpoint numbers to compound breakpoints]
The user breakpoint hash table is a hash table that varies.
Chapter "Active Stream Logs" - unindexed
[Maps stream numbers to stream logs]
The stream log hash table is a hash table that varies.
Chapter "User Breaktexts" - unindexed
The length of the longest breaktext is a number that varies. The length of the longest breaktext is zero.
To decide what number is the capacity corresponding to the longest breaktext:
let the result be four [overestimation to reduce churn] times four [conversion to bytes] times the length of the longest breaktext;
if the result is less than the minimum stream log capacity:
decide on the minimum stream log capacity;
decide on the result.
[Maps breaktext numbers to breaktexts]
The user breaktext hash table is a hash table that varies.
The breaktext encountered flag is a truth state that varies. The breaktext encountered flag is false.
Chapter "Debugger Initialization" - unindexed
A GRIF setup rule (this is the initialize the debugger state rule):
now the debugger's control flow state is responding after a continue;
now the debugger's control flow attitude is responding after an assured advance;
now the debugger's current call frame is a null call frame;
now the last-seen call stack root is a null call frame;
now the last-seen call stack divider is a null call frame;
now the last-seen compound breakpoint list is an empty linked list;
now the user breakpoint hash table is a new hash table with the user breakpoint hash table size buckets;
now the stream log hash table is a new hash table with the stream log hash table size buckets;
now the user breaktext hash table is a new hash table with the user breaktext hash table size buckets.
Chapter "Debugger State Serialization" - unindexed
To serialize (A - a punctuated word array):
let the length be the word count of A;
serialize the length;
repeat with the index running over the half-open interval from zero to the length:
serialize the synthetic text word index of A.
To serialize (V - parse tree vertex):
let the vertex index hash table be a new hash table with the debug command parse tree vertex hash table size buckets;
let the index be zero;
let the vertex be V;
while the vertex is not null:
insert the key the vertex and the value the index into the vertex index hash table;
increment the index;
now the vertex is the parse tree vertex to visit after the vertex;
serialize the index;
let the parser be the owner of the parseme of V;
let the parseme index hash table be a new hash table with the debug command parseme hash table size buckets;
now the index is zero;
repeat with the parseme running through the parseme keys of the parseme linked list of the parser:
insert the key the parseme and the value the index into the parseme index hash table;
increment the index;
now the vertex is V;
while the vertex is not null:
let the parseme be the parseme of the vertex;
serialize the first number value matching the key the parseme in the parseme index hash table or -1 if there are no matches;
if the parseme is a nonterminal:
let production serialized be false;
let the vertex's production be the production of the vertex;
now the index is zero;
repeat with the indexed production running through the production keys of the production linked list of the parseme:
if the vertex's production is the indexed production:
serialize the index;
now production serialized is true;
break;
increment the index;
always check that production serialized is true or else fail at serializing the debugger's parse of a command;
serialize the first number value matching the key the first child of the vertex in the vertex index hash table or -1 if there are no matches;
serialize the first number value matching the key the last child of the vertex in the vertex index hash table or -1 if there are no matches;
serialize the first number value matching the key the left sibling of the vertex in the vertex index hash table or -1 if there are no matches;
serialize the first number value matching the key the right sibling of the vertex in the vertex index hash table or -1 if there are no matches;
serialize the beginning lexeme index of the vertex;
serialize the end lexeme index of the vertex;
now the vertex is the parse tree vertex to visit after the vertex;
delete the vertex index hash table;
delete the parseme index hash table.
To serialize (C - a compound breakpoint):
serialize the numeric identifier of C;
serialize the synthetic text the human-friendly name of C; [////]
let the simple breakpoint list be the simple breakpoint list of C;
serialize the length of the simple breakpoint list;
repeat with the simple breakpoint running through the simple breakpoint keys of the simple breakpoint list:
serialize the sequence point of the simple breakpoint;
serialize whether or not C is enabled.
To serialize (B - a breaktext):
serialize the numeric identifier of B;
serialize the synthetic text the human-friendly name of B; [////]
let the codepoint count be the codepoint count of B;
serialize the codepoint count;
serialize the codepoint count times four bytes at address the codepoint array address of B;
serialize whether or not B is enabled;
serialize whether or not B is triggered.
To serialize (L - a stream log):
serialize the log capacity of L;
serialize the log length of L;
serialize the log length of L times four bytes at address the log address of L.
Chapter "Debugger Deserialization" - unindexed
To decide what punctuated word array is a deserialized punctuated word array:
let the word count be a deserialized number;
let the size be the size in memory of a punctuated word array for the word count punctuated words;
let the result be a memory allocation of size bytes converted to a punctuated word array;
write the word count the word count to the result;
repeat with the index running over the half-open interval from zero to the word count:
write a deserialized synthetic text to word index of the result;
decide on the result.
To decide what parse tree vertex is a deserialized parse tree vertex for (A - a context-free parser):
let the parseme hash table be a new hash table with the debug command parseme hash table size buckets;
let the index be zero;
repeat with the parseme running through the parseme keys of the parseme linked list of A:
insert the key the index and the value the parseme into the parseme hash table;
increment the index;
let the vertex count be a deserialized number;
let the vertex hash table be a new hash table with the debug command parse tree vertex hash table size buckets;
repeat with the second index running over the half-open interval from zero to the vertex count:
let the vertex be a new parse tree root for an invalid parseme;
insert the key the second index and the value the vertex into the vertex hash table;
repeat with the second index running over the half-open interval from zero to the vertex count:
let the vertex be the first parse tree vertex value matching the key the second index in the vertex hash table or an invalid parse tree vertex if there are no matches;
always check that the vertex is not an invalid parse tree vertex or else fail at deserializing the debugger's parse of a command;
let the parseme be the first parseme value matching the key a deserialized number in the parseme hash table or an invalid parseme if there are no matches;
write the parseme the parseme to the vertex;
if the parseme is a nonterminal:
let the production index be a deserialized number;
if the production index is at least zero:
repeat with the production running through the production keys of the production linked list of the parseme:
decrement the production index;
if the production index is zero:
write the production the production to the vertex;
write the first child the first parse tree vertex value matching the key a deserialized number in the vertex hash table or a null parse tree vertex if there are no matches to the vertex;
write the last child the first parse tree vertex value matching the key a deserialized number in the vertex hash table or a null parse tree vertex if there are no matches to the vertex;
write the left sibling the first parse tree vertex value matching the key a deserialized number in the vertex hash table or a null parse tree vertex if there are no matches to the vertex;
write the right sibling the first parse tree vertex value matching the key a deserialized number in the vertex hash table or a null parse tree vertex if there are no matches to the vertex;
write the beginning lexeme index a deserialized number to the vertex;
write the end lexeme index a deserialized number to the vertex;
let the result be the first parse tree vertex value matching the key zero in the vertex hash table or an invalid parse tree vertex if there are no matches;
always check that the result is not an invalid parse tree vertex or else fail at deserializing the debugger's parse of a command;
decide on the result.
To decide what compound breakpoint is a deserialized compound breakpoint:
let the saved breakpoint counter be the breakpoint counter;
now the breakpoint counter is a deserialized number;
let the human-friendly name be a deserialized synthetic text;
let the result be a new compound breakpoint with human-friendly name the human-friendly name;
now the breakpoint counter is the saved breakpoint counter;
delete the synthetic text the human-friendly name;
let the sequence point count be a deserialized number;
repeat with a counter running from one to the sequence point count:
let the sequence point be a deserialized number;
attach the sequence point the sequence point to the result;
if a deserialized truth state is true:
enable the result;
decide on the result.
To decide what breaktext is a deserialized breaktext:
let the saved breakpoint counter be the breakpoint counter;
now the breakpoint counter is a deserialized number;
let the human-friendly name be a deserialized synthetic text;
let the codepoint count be a deserialized number;
let the codepoint array address be a possibly zero-length memory allocation of the codepoint count times four bytes;
deserialize the codepoint count times four bytes to address the codepoint array address;
let the result be a new breaktext for the codepoint count codepoints at address the codepoint array address named the human-friendly name;
now the breakpoint counter is the saved breakpoint counter;
delete the synthetic text the human-friendly name;
if a deserialized truth state is true:
enable the result;
if a deserialized truth state is true:
trigger the result;
decide on the result.
To decide what stream log is a deserialized stream log:
let the result be a new stream log with capacity of at least a deserialized number bytes;
let the length be a deserialized number;
write the log length the length to the result;
deserialize the length bytes to address the log address of the result;
decide on the result.
Chapter "Debugger State Serialization and Deserialization"
Section "Magic Numbers" - unindexed
To decide what number is the debugger state magic number: (- 1765239140 -). [ASCII for "i7id"]
To decide what number is the debugger state file format version number: (- 0 -).
Section "Serialization/Deserialization Rule"
A protected state serialization/deserialization rule (this is the serializing and deserializing the debugger state rule):
if serializing rather than deserializing:
serialize the debugger state magic number;
serialize the debugger state file format version number;
serialize the call stack simplification flag;
serialize the showme warnings flag;
serialize the lengthly listing warnings flag;
serialize the last-seen debug command punctuated words;
serialize the last-seen debug command vertex;
serialize the breakpoint counter;
serialize the number of entries in the user breakpoint hash table;
repeat with the compound breakpoint running through the compound breakpoint values of the user breakpoint hash table:
serialize the compound breakpoint;
serialize the number of entries in the user breaktext hash table;
repeat with the breaktext running through the breaktext values of the user breaktext hash table:
serialize the breaktext;
serialize the number of entries in the stream log hash table;
repeat with linked list vertex running through the stream log hash table:
serialize the number key of the linked list vertex;
serialize the stream log value of the linked list vertex;
otherwise if there is data to deserialize:
always check that a deserialized number is the debugger state magic number or else fail at recognizing a debugger serialization format;
always check that a deserialized number is the debugger state file format version number or else fail at recognizing a debugger serialization format;
now the call stack simplification flag is whether or not a deserialized truth state is true;
now the showme warnings flag is whether or not a deserialized truth state is true;
now the lengthly listing warnings flag is whether or not a deserialized truth state is true;
now the last-seen debug command punctuated words are a deserialized punctuated word array;
now the last-seen debug command vertex is a deserialized parse tree vertex for the debug command parser;
now the breakpoint counter is a deserialized number;
let the user breakpoint count be a deserialized number;
repeat with a counter running from one to the user breakpoint count:
let the compound breakpoint be a deserialized compound breakpoint;
insert the key the numeric identifier of the compound breakpoint and the value the compound breakpoint into the user breakpoint hash table;
let the user breaktext count be a deserialized number;
repeat with a counter running from one to the user breaktext count:
let the breaktext be a deserialized breaktext;
insert the key the numeric identifier of the breaktext and the value the breaktext into the user breaktext hash table;
let the stream log count be a deserialized number;
repeat with a counter running from one to the stream log count:
let the stream be a deserialized number;
let the stream log be a deserialized stream log;
insert the key the stream and the value the stream log into the stream log hash table;
now the debugger's story-restarted flag is true;
now the banner printed flag is true.
Book "Debugger Instrumentation" - unindexed
Chapter "Finish Detection in Follow-on Calls" - unindexed
Section "Frame-Local Flag for Tripwires" - unindexed
The follow-on call tripwire flag index is a number that varies.
A GRIF setup rule (this is the allocate the follow-on call tripwire flag rule):
now the follow-on call tripwire flag index is the index of a newly reserved call frame field.
Section "Tripwire Insertion" - unindexed
[ @jz <frame-local-tripwire-flag> <constant>; ]
To decide what instruction vertex is a new tripwire instruction vertex:
let the result be a new artificial instruction vertex;
write the operation code op-jz to the result;
write the addressing mode zero-based-dereference addressing mode to parameter zero of the result;
write extra field address follow-on call tripwire flag index of call frames for the chunk being instrumented as seen by that chunk to parameter zero of the result;
write the addressing mode constant addressing mode to parameter one of the result;
decide on the result.
A GRIF instrumentation rule (this is the insert tripwires to detect follow-on calls when the debugger is executing its finish command rule):
repeat with the instruction vertex running through occurrences of function call in the scratch space:
unless the instruction vertex is artificial or the source address of the instruction vertex is a sequence point:
let the pre-call tripwire instruction vertex be a new tripwire instruction vertex;
let the pre-call breakpoint-enabling instruction vertex be a new artificial instruction vertex for a zero-argument call to the function at address the function address of enabling the universal breakpoint with return mode the zero-or-discard addressing mode;
let the post-call tripwire instruction vertex be a new tripwire instruction vertex;
let the post-call breakpoint-disabling instruction vertex be a new artificial instruction vertex for a zero-argument call to the function at address the function address of disabling the universal breakpoint with return mode the zero-or-discard addressing mode;
insert the pre-call tripwire instruction vertex before the instruction vertex;
insert the pre-call breakpoint-enabling instruction vertex before the instruction vertex;
insert the post-call breakpoint-disabling instruction vertex after the instruction vertex;
insert the post-call tripwire instruction vertex after the instruction vertex;
establish a jump link from the pre-call tripwire instruction vertex to the instruction vertex;
establish a jump link from the post-call tripwire instruction vertex to the next link of the post-call breakpoint-disabling instruction vertex.
Book "Output Interception"
Chapter "Stream Logs" - unindexed
Section "The Stream Log Kind" - unindexed
A stream log is a kind of value.
A stream log is an invalid stream log. [See the note in the book "Extension Information."]
The specification of a stream log is "A stream log stores characters recently printed to a stream, which Interactive Debugger monitors for the appearance of breaktexts."
Section "The Stream Log Structure" - unindexed
[Layout:
4 bytes for the log capacity (in bytes, which we call N)
4 bytes for the log length (in bytes)
N bytes for the log]
To decide what number is the size in memory of a stream log with capacity (N - a number) bytes: (- (8+{N}) -).
Section "Stream Log Construction and Destruction" - unindexed
To decide what stream log is a new stream log with capacity of at least (N - a number) bytes:
let the capacity be N;
if the capacity is less than the minimum stream log capacity:
now the capacity is the minimum stream log capacity;
let the size be the size in memory of a stream log with capacity the capacity bytes;
let the result be a memory allocation of the size bytes converted to a stream log;
write the log capacity the capacity to the result;
write the log length zero to the result;
decide on the result.
To delete (A - a stream log):
free the memory allocation at address A converted to a number.
Section "Stream Log Accessors and Mutators" - unindexed
To decide what number is the log capacity of (A - a stream log): (- llo_getInt({A}) -).
To write the log capacity (X - a number) to (A - a stream log): (- llo_setInt({A},{X}); -).
To decide what number is the log length of (A - a stream log): (- llo_getField({A},1) -).
To write the log length (X - a number) to (A - a stream log): (- llo_setField({A},1,{X}); -).
To clear (A - a stream log): (- llo_setField({A},1,0); -).
To decide what number is the log address of (A - a stream log): (- ({A}+8) -).
To decide what number is the log end address of (A - a stream log): (- ({A}+8+llo_getField({A},1)) -).
Section "Stream Log Appending" - unindexed
To decide what number is the written byte count after appending up to (N - a number) bytes from address (B - a number) to (A - a stream log):
let the length be the log length of A;
let the appendable byte count be the log capacity of A minus the length;
if N is less than the appendable byte count:
now the appendable byte count is N;
copy the appendable byte count bytes from address B to address the log end address of A;
increase the length by the appendable byte count;
write the log length the length to A;
decide on the appendable byte count.
Section "Stream Log Scrolling" - unindexed
To scroll (A - a stream log) as far as possible without losing the last (N - a number) byte/bytes:
let the scroll distance be the log length of A minus N;
if the scroll distance is at most zero:
stop;
let the destination address be the log address of A;
let the source address be the destination address plus the scroll distance;
copy the N bytes from address the source address to address the destination address;
write the log length N to A.
Section "Stream Log Searching" - unindexed