The I6 stack

Am I misunderstanding something about the I6 stack? Am I doing something stupid? I just can’t see it.

[code]
To clear the match list: (- ClearMatchList(); -)

To restore the match list: (- RestoreMatchList(); -)

To report (item - an object) (this is reporting):
say “Matched [the item].”;

Every turn:
clear the match list;
if the player’s command matches “[any thing]”:
iterate over the match list with reporting;
restore the match list;

To iterate over the match list with (func - phrase thing -> nothing ): (- LoopOverMatchList({func}); -)

Include (-
[ ClearMatchList;
SaveMatchGlobals();
print "ClearMatchList: saving parsetoken_nesting value of ", parsetoken_nesting, “.^”;
@push parsetoken_nesting;
parsetoken_nesting = 0;
];

[ RestoreMatchList;
print "RestoreMatchList: parsetoken_nesting is ", parsetoken_nesting, “.^”;
@pull parsetoken_nesting;
print "RestoreMatchList: parsetoken_nesting restored to ", parsetoken_nesting, “.^”;
RestoreMatchGlobals();
];

[ LoopOverMatchList func i;
for (i=0: i<number_matched: i++) {
indirect(func, match_list–>i);
}
];

[ SaveMatchGlobals i t;
@push match_from; @push token_filter; @push match_length;
@push number_of_classes; @push oops_from;
for (i=0: i<number_matched: i++) {
t = match_list–>i; @push t;
t = match_classes–>i; @push t;
t = match_scores–>i; @push t;
}
@push number_matched;
parsetoken_nesting++;
print "SaveMatchGlobals: parsetoken_nesting incremented to “, parsetoken_nesting, " - number_matched = “, number_matched,”.^”;
];

[ RestoreMatchGlobals i t;
parsetoken_nesting–;
print "RestoreMatchGlobals: parsetoken_nesting decremented to ", parsetoken_nesting, “.^”;
@pull number_matched;
for (i=0: i<number_matched: i++) {
@pull t; match_scores–>i = t;
@pull t; match_classes–>i = t;
@pull t; match_list–>i = t;
}
@pull oops_from; @pull number_of_classes;
@pull match_length; @pull token_filter; @pull match_from;
];

-)

Test is a room.

There is a blue ball in test. There is a green ball in test.

There is a container called a red bucket in test. There is a container called an orange bucket in test.

Test me with “get blue”[/code]

This code gives a stack underflow the first time it tries to pull something. Where did the stack go?

The value stack is function-local. (Part of the function’s stack frame.) When you return from the function, it’s gone.

Ahh. That explains why there’s so much clutter in I6 functions. Dang. No closures in I6, right?

Is there an alternative, or do I need to express this operation within a single I6 function? I guess if I’m going to use a topic, I can pass the topic as an argument to the function.

There’s no good alternative, if you want to do this nestably. (I7 maintains some arrays as hand-managed global stacks, for various reasons, but it’s an awful pain – you’re either wasting memory or risking overflow, or more probably both.)

I think I have something that does what I want:

[spoiler][code]The parse token nesting is a number that varies.
The number of matched objects is a number that varies.
The word number to match from is a number that varies.
The match length is a number that varies.

The parse token nesting variable translates into I6 as “parsetoken_nesting”.
The number of matched objects variable translates into I6 as “number_matched”.
The word number to match from variable translates into I6 as “match_from”.
The match length variable translates into I6 as “match_length”.

To decide what number is the start of (S - a snippet): (- {S} / 100 -);
To decide what number is the length of (S - a snippet): (- {S} % 100 -);

Instead of asking someone about:
Repeat with item running through things:
if item matches the topic understood, say “matched [the item].”;

To match text against (O - an object): (- MatchTextAgainstObject({O}); -)

To decide whether (O - an object) matches (S - a snippet):
[save match globals]
Let the old depth be the parse token nesting;
Let the old count be the number of matched objects;
Let the old start be the word number to match from;
[force items to be added to the match list]
Now the parse token nesting is 0;
Now the word number to match from is the start of S;
Match text against O;
Let the difference be the number of matched objects minus the old count;
[restore match globals]
now the parse token nesting is the old depth;
Now the word number to match from is the old start;
Now the parse token nesting is the old depth;
[if there’s no match, we’re done]
if the difference is 0, no;
[restore the match list]
Now the number of matched objects is the old count;
Decide on whether or not the match length is the length of S;

Test is a room.

Bob is a man in Test.

There is a blue ball in test. There is a green ball in test.

There is a container called a red bucket in test. There is a container called an orange bucket in test.

Test me with “ask Bob about ball/ask bob about blue/ask bob about ball and socket joints”[/code][/spoiler]

I think it might be possible to do away with the manipulation of the match list completely, but I seem to remember there were complications involved.

Well, there’s the I7 heap. You can use the LIST_OF_TY_* functions from I6 code to work with lists, so you could make a stack out of a global list of numbers. Or you could even have arbitrarily swappable match lists by copying the match globals to a list:

[code]To save match globals into (L - list of numbers): (- SaveMatchGlobals({-pointer-to:L}); -).
To restore match globals from (L - list of numbers): (- RestoreMatchGlobals({-pointer-to:L}); -).

Include (-
[ SaveMatchGlobals list i j;
LIST_OF_TY_SetLength(list, 3 * number_matched + 5, 0);
LIST_OF_TY_PutItem(list, 1, match_from);
LIST_OF_TY_PutItem(list, 2, token_filter);
LIST_OF_TY_PutItem(list, 3, match_length);
LIST_OF_TY_PutItem(list, 4, number_of_classes);
LIST_OF_TY_PutItem(list, 5, oops_from);
for ( i=0, j=6: i<number_matched: i++ ) {
LIST_OF_TY_PutItem(list, j++, match_list–>i);
LIST_OF_TY_PutItem(list, j++, match_classes–>i);
LIST_OF_TY_PutItem(list, j++, match_scores–>i);
}
];

[ RestoreMatchGlobals list i j;
number_matched = (LIST_OF_TY_GetLength(list) - 5) / 3;
match_from = LIST_OF_TY_GetItem(list, 1);
token_filter = LIST_OF_TY_GetItem(list, 2);
match_length = LIST_OF_TY_GetItem(list, 3);
number_of_classes = LIST_OF_TY_GetItem(list, 4);
oops_from = LIST_OF_TY_GetItem(list, 5);
for ( i=0, j=6: i<number_matched: i++ ) {
match_list–>i = LIST_OF_TY_GetItem(list, j++);
match_classes–>i = LIST_OF_TY_GetItem(list, j++);
match_scores–>i = LIST_OF_TY_GetItem(list, j++);
}
]; -).[/code]

I’ve been thinking about creating a “preserve match globals and (func - a phrase …)” phrase to do this, pretty much the way ParseToken sandwiches the call to ParseToken__ between saving and restoring values.