Can't match more than one word

Oh dear, parser fatigue is returning. I thought I had Objects Matching Snippets working pretty well, but there’s a snag.

Here’s the full extension, as it stands at the moment, with some debugging code:

[spoiler][code]Version 2 of Objects Matching Snippets by Mike Ciul begins here.

“Provides phrases and relations for checking whether objects are named in snippets. Also provides a rulebook for disambinguating objects outside of an action context.”

“based on ideas in Original Parser by Ron Newcomb and I6 advice from Andrew Plotkin”

Section - I6 Hooks

The parse token nesting level is a number that varies.
The number of objects in the match list is a number that varies.
The next word to parse’s position is a number that varies.
The number of words matched per object is a number that varies.

The parse token nesting level variable translates into I6 as “parsetoken_nesting”.
The number of objects in the match list variable translates into I6 as “number_matched”.
The next word to parse’s position variable translates into I6 as “match_from”.
The number of words matched per object 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 -);

To decide which snippet is the next subsnippet of (S - a snippet): (- {S} + 100 - 1 -);

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

Section - Low-Level Phrases

[TODO: make sure pronouns work]

[TODO: make sure ARTICLES work!]

To decide whether the name of (O - an object) appears in (S - a snippet):
While the length of S is greater than 0:
if O matches S, allowing shorter length:
yes;
Now S is the next subsnippet of S;
no.

To dump parser state: (- DumpParserState(); -)

Include (-
[ DumpParserState i;
print "parse token nesting: ", parsetoken_nesting, " number matched: ", number_matched, " match from: ", match_from, " match length: ", match_length, “^”;
for (i = 0; i < number_matched; i++) {
print "match list item ", i, " = ", (name) match_list–>i, “^”;
}
print "parser_action = ", parser_action, " parser_one = ", parser_one, " parser_two = ", parser_two, “^”;
print "wn = ", wn, " scope_token = ", scope_token, " scope_stage = ", scope_stage, " scope_reason = ", scope_reason, " suppress_scope_loops = ", suppress_scope_loops, “^”;
];
-)

To decide whether (O - an object) matches (snip - a snippet), allowing shorter length:
[save match globals]
Let the old depth be the parse token nesting level;
Let the old count be the number of objects in the match list;
Let the old start be the next word to parse’s position;
[force items to be added to the match list]
Now the parse token nesting level is 0;
Now the next word to parse’s position is the start of snip;
Match text against O;
Let the difference be the number of objects in the match list minus the old count;
[restore match globals]
now the parse token nesting level is the old depth;
Now the next word to parse’s position is the old start;
Now the parse token nesting level 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 objects in the match list is the old count;
If allowing shorter length and the number of words matched per object is not greater than the length of snip, yes;
Decide on whether or not the number of words matched per object is the length of snip;

Section - Relations

Snippet-matching relates an object (called candidate) to a snippet (called S) when candidate matches S. The verb to be identified with implies the snippet-matching relation.

Snippet-inclusion relates an object (called candidate) to a snippet (called S) when the name of candidate appears in S. The verb to be named in implies the snippet-inclusion relation.

Section - Did the Player Choose

did the player choose is an object based rulebook.
The did the player choose rules have outcomes it is very likely, it is likely, it is possible, it is unlikely, it is very unlikely.

To decide which number is the/-- match score for (item - an object):
follow the did the player choose rules for item;
if the outcome of the rulebook is:
– the it is very likely outcome: decide on 4;
– the it is likely outcome: decide on 3;
– the it is possible outcome: decide on 2;
– the it is unlikely outcome: decide on 1;
– the it is very unlikely outcome: decide on 0;
decide on 2;

The best match score is a number that varies.

Definition: A thing is likeliest if the match score for it is the best match score;
Definition: A room is likeliest if the match score for it is the best match score;
Definition: A direction is likeliest if the match score for it is the best match score;
Definition: A region is likeliest if the match score for it is the best match score;

Section - Choosing the Most Likely Object

To decide whether nothing matched:
decide on whether or not the best match score is -1;

To decide whether something matched:
decide on whether or not the best match score is at least 0;

To decide which object is the/-- most likely (O - description of objects):
Let the already matched item be nothing;
Now the best match score is -1;
Repeat with the candidate running through the list of O:
Let the current match score be the match score for the candidate;
If the current match score is less than the best match score, next;
If the current match score is the best match score:
now the already matched item is nothing;
next;
Now the already matched item is the candidate;
Now the best match score is the current match score;
Decide on the already matched item.

Section - Testing Commands - Not for Release

match-checking is an action out of world applying to one topic. Understand “objmatch [text]” as match-checking.

Report match-checking:
showme the list of things identified with the topic understood;
showme the list of rooms identified with the topic understood;
showme the list of directions identified with the topic understood;
showme the list of regions identified with the topic understood;

[Tracing object matches is a truth state that varies.

activating match-tracing is an action out of world. Understand “oms-trace” as activating match-tracing.

Carry out activating match-tracing:
now tracing object matches is true.

Report activating match-tracing:
say “Trace on for Objects Matching Snippets.”;

deactivating match-tracing is an action out of world. Understand “oms-trace off” as deactivating match-tracing.

Carry out deactivating match-tracing:
now tracing object matches is false.

Report deactivating match-tracing:
say “Trace off for Objects Matching Snippets.”;]

[TODO: check match scores?]

Objects Matching Snippets ends here.

---- DOCUMENTATION ----

Objects Matching Snippets is a very simple extension that provides a convenient way to search for names of objects within a snippet such as the player’s command or the topic understood.

There are two relations that can be used for this: snippet-matching (“O is identified with S”) and snippet-inclusion (“O is named in S”). These correspond to the built-in phrases “S matches O” and “S includes O.”

Snippet-matching tests whether the name of object O matches the snippet S:

say "[The list of things identified with the topic understood] all match the phrase '[the topic understood]' in your command.";

Snippet-inclusion tests whether the name of object O appears in the snippet S:

say "The rooms [list of rooms named in the player's command] are all mentioned in your command."

Note that these are both object-to-snippet relations, so you can test them on rooms, directions, and regions as well as things.

If you just want to pick an object, you can use the phrase “the most likely O”:

say "You probably meant [the most likely thing identified with the topic understood]."

This phrase will return an object if there is exactly one match, otherwise it will return nothing, even if there were multiple matches.

To control what objects match, you can use a scoring system similar to the Does the Player Mean rules. This is managed using the “Did the Player Choose” rulebook. The difference is that the Did the Player Choose rules are object based, so you need to pass a description of the object you’re testing:

Did the player choose an exclamation when answering someone that: It is very likely.

The “most likely” phrase will reject any objects that score lower than the best choice. But if there are two or more objects that score equally high, it will still return nothing. To find out whether the phrase failed because nothing match or because of multiple matches, you can test “if nothing matched,” “if something matched,” and which objects were “likeliest” immediately after calling the phrase:

Let the choice be the most likely thing named in the player's command;
if the choice is nothing:
	if nothing matched, say "You didn't mention any things I recognize.";
	if something matched, say "You mentioned [the list of likeliest things named in the player's command] in your command.";

Remember that the “likeliest” adjective merely runs the “did the player choose” rulebook on the item described - it doesn’t test whether that object was part of the “most likely” test just performed, so you must reiterate any other conditions used to invoke the phrase.

To test what objects match any snippet, you can use the “objmatch” testing command:

>objmatch me
"list of things identified with the topic understood" = list of things: {yourself}
"list of rooms identified with the topic understood" = list of rooms: {}
"list of directions identified with the topic understood" = list of directions: {}
"list of regions identified with the topic understood" = list of regions: {}

Example: * Exclamations - Creates a new action that can be parsed from the command “[someone], [something]”

*: "Exclamations"

Include Objects Matching Snippets by Mike Ciul.

Exclaiming it to is an action applying to two visible things.
Report exclaiming it to: say "You say '[noun]' to [the second noun]."

An exclamation is a kind of thing. Hello is an exclamation.

Check answering someone that:
	Let item be the most likely thing identified with the topic understood;
	If item is a thing:
		instead try exclaiming item to the noun;
	Let item be the most likely thing named in the topic understood;
	if something matched:
		say "Your command did not exactly match anything you can say, but [the list of likeliest things named in the topic understood] matched part[if item is nothing]s[end if] of it.";
		stop the action.

Test is a room. Bob is a man in Test.

Test me with "say hello to bob/bob, hello how are you Bob"[/code][/spoiler]

And here’s a test:

[code]include objects matching snippets by mike ciul.

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

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 thing called nameless. Understand “unnamed” as nameless.

Test me with “ask Bob about ball/ask bob about bob/ask bob about blue/ask bob about blue ball/ask bob about it/ask bob about him/ask bob about ball and socket joints/ask bob about the disco ball lights/ask bob about unnamed”
[/code]

Bob doesn’t match, but I think I’ve figured out the reason for that: he’s already in the match list. But I can’t figure out why “blue ball” doesn’t match the blue ball. In fact, it seems like no multiple word topic ever matches anything. Any ideas?

Thanks!

I think the problem may be located in the MakeMatch routine. Appendix B § 37 says:

“blue ball” matches with quality 2, and therefore erases all other entries in the match list; whereas “blue” only matches with quality 1, and therefore just adds the blue ball to the match list.

(EDIT:)
This behaviour of MakeMatch will mess up the logic in your extension’s to decide phrase:

The difference will be 0, if either there was no match, or there was one best quality match.

Thanks, Felix! I guess I can’t take any shortcuts with the match list then.

The difficulty of saving the match list is making me think I should return to using topics as scope filters instead of manually looping over objects. But now I have a glk runtime error: “Local variable wasn’t 4 bytes wide.”

What does that mean? How do I trace it?

[spoiler][code]An thing can be snippet-matched.
A room can be snippet-matched.
A direction can be snippet-matched.
A region can be snippet-matched.

To match (snip - a snippet) against (the candidate set - a topic):
Execute exact snippet matching with snip and the candidate set while preserving the match list.

To execute (func - phrase (snippet, topic) -> nothing) with (S - a snippet) and (T - a topic) while preserving the match list: (- PreserveMatchListAndExec({func}, {S}, {T}); -)

To unstably match (snip - a snippet) against (the candidate set - a topic) (this is exact snippet matching):
say “exact snippet matching.”;
Now every thing is not snippet-matched;
Now every room is not snippet-matched;
Now every direction is not snippet-matched;
Now every region is not snippet-matched;
if snip matches the candidate set, loop over the match list with marking snippet matches.

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

To mark (item - an object) as snippet-matched (this is marking snippet matches):
Now item is snippet-matched.

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

[ PreserveMatchListAndExec func snip topic i t;
if (parsetoken_nesting > 0) {
! save match globals
@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;
}
@push parsetoken_nesting;
parsetoken_nesting = 0;
number_matched = 0;
number_of_classes = 0;
match_from = snip % 100;
print "func = ", func, " snip = ", snip, " topic = ", topic, “^”;
indirect(func, snip, topic);
@pull parsetoken_nesting;
if (parsetoken_nesting > 0) {
! restore match globals
@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;
}
];
-)

Instead of asking someone about:
[Repeat with item running through things:
say “checking if [the item] matches [the topic understood].”;
if item matches the topic understood, say “MATCHED [the item].”;]
Match the topic understood against “[any thing]”;
showme the list of snippet-matched things;

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 thing called nameless. Understand “unnamed” as nameless.

Test me with “ask Bob about ball/ask bob about bob/ask bob about blue/ask bob about blue ball/ask bob about it/ask bob about him/ask bob about ball and socket joints/ask bob about the disco ball lights/ask bob about unnamed”
[/code][/spoiler]

I think it means you made an I6 function call to an invalid address.

Phrase values are arrays not functions. So replace {func} with {func}–>1

Oh, right. I knew that before, but I forgot.

Interesting… it sort of works now, except when there are multiple matches, it triggers the “asking which do you mean” activity. Which is sort of cool, but not at all what I wanted…

It should be easy to hijack it to do what I really want, though. Maybe.

So I’ve still got a bit of a mystery. Originally I thought that the global variable parsetoken_nesting was the thing that stopped “(snippet) matches (topic)” from building the match list (and subsequently asking which do you mean), but that can’t be true, because parsetoken_nesting is already 0 before all my convoluted steps to save the match list. Perhaps that was just a big waste of time. On the other hand, something different is happening here, I just don’t know what it is. Any hints?

Maybe I’m going insane. Even this simple example triggers the asking which do you mean activity. I swear it wasn’t like that before. What’s going on?

[code]Instead of asking someone about:
If the topic understood matches “[any thing]”:
say “match.”;

Test is a room.

Bob is a man in Test.

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

Test me with “ask Bob about ball”[/code]