Rule for clarifying the parser's choice not firing when no noun was in the command

When the parser chooses a noun automatically when there was none in the command, the rules for clarifying the parser’s choice do not fire. It fires when the parser chooses between multiple objets when the noun was ambiguous in the command.

I’d like to know if it’s a bug or the intended behavior. In the latter case, is there an easy way to change the clarification message?

If what I mean is not clear, here an example.

Talking to is an action applying to one visible thing.
Understand "talking to [something]" as talking to.

Check talking to:
	if the noun is not a person, say "You can't." instead.

Report talking to:
	say "You talk with [the noun].".

For clarifying the parser's choice of something while talking to:
	say "(MY CUSTOM CLARIFICATION)".

[So that the parser chooses a person in priority.]
Does the player mean talking to a person:
	it is very likely.

The red guard is a man in example room.
The red cube is a thing in example room.

If the player types TALK TO RED, the custom message will be displayed. But if the player types TALK TO with no noun, the default message “(to the red guard)” is printed. (In both case, the parser chooses the person because of the “does the player mean”.)

The example you gave didn’t quite compile. I rewrote it slightly to this:

Talking to is an action applying to one visible thing.
Understand "talk to [something]" as talking to.

Check talking to:
	if the noun is not a person, say "You can't." instead.

Report talking to:
	say "You talk with [the noun].".

For clarifying the parser's choice of something while talking to:
	say "(MY CUSTOM CLARIFICATION)".

[So that the parser chooses a person in priority.]
Does the player mean talking to a person:
	it is very likely.

Example room is a room.
The red guard is a man in example room.
The red cube is a thing in example room.
Test me with "talk to/talk to red".

Compilation yields this transcript:

Welcome An Interactive Fiction Release 1 / Serial number 190522 / Inform 7 build 6M62 (I6/v6.33 lib 6/12N) SD

Example room
You can see a red guard and a red cube here.

test me
(Testing.)

[1] talk to
(MY CUSTOM CLARIFICATION)You talk with the red guard.

[2] talk to red
(MY CUSTOM CLARIFICATION)You talk with the red guard.

I don’t know why I’m getting a different result. If you run my code and we still have divergent behavior, you might be using an older version of I7.

What was missing from my code? Ah, it was the room? I’ll be more careful next time.

I tested and in fact you are right. But I realise I made a small mistake in my post: the problem arise when the player types TALK, without the preposition. Then Inform does’t follow the clarifying the parser’s choice rule and instead just displays “(to the red guard)”.

I need this because if multiple prepositions are specified (as in Understand "talk to/with" as...), Inform will choose the first preposition when clarifying. But in French, the needed preposition changes according to the grammatical gender and number (it can be “à”, “au” or “aux”); so I don’t want Inform to choose systematically the first one when clarifying.

(And yes, in case it matters, I’m using 6L38. But I looked into 6M62’s changelog to see if something changed regarding this, and I found nothing.)

I think the magic template code in question here is this part of Parser.i6t. (I think this is 6M62, but I bet it’s not much different in 6L38.)

[ PrintInferredCommand from singleton_noun;
	singleton_noun = FALSE;
	if ((from ~= 0) && (from == pcount-1) &&
		(pattern-->from > 1) && (pattern-->from < REPARSE_CODE))
			singleton_noun = TRUE;

	if (singleton_noun) {
		BeginActivity(CLARIFYING_PARSERS_CHOICE_ACT, pattern-->from);
		if (ForActivity(CLARIFYING_PARSERS_CHOICE_ACT, pattern-->from) == 0) {
			print "("; PrintCommand(from); print ")^";
		}
		EndActivity(CLARIFYING_PARSERS_CHOICE_ACT, pattern-->from);
	} else {
		print "("; PrintCommand(from); print ")^";
	}
];

[ PrintCommand from i k spacing_flag;
    if (from == 0) {
        i = verb_word;
        if (LanguageVerb(i) == 0)
            if (PrintVerb(i) == 0) print (address) i;
        from++; spacing_flag = true;
    }
    for (k=from : k<pcount : k++) {
        i = pattern-->k;
        if (i == PATTERN_NULL) continue;
        if (spacing_flag) print (char) ' ';
        if (i == 0) { PARSER_CLARIF_INTERNAL_RM('F'); jump TokenPrinted; }
        if (i == 1) { PARSER_CLARIF_INTERNAL_RM('G'); jump TokenPrinted; }
        if (i >= REPARSE_CODE)
            print (address) VM_NumberToDictionaryAddress(i-REPARSE_CODE);
        else
            if (i ofclass K3_direction)
                print (LanguageDirection) i; ! the direction name as adverb
            else
                print (the) i;
      .TokenPrinted;
        spacing_flag = true;
    }
];

Looking at PrintInferredCommand, “from” is a parameter (it gets passed as the global “inferfrom” when PrintInferredCommand gets called from within Parser Letter G). “singleton_noun” is a local variable.

So the logic here seems to be, when singleton_noun gets set to TRUE, the clarifying the parser’s choice activity gets a chance to run, and if there are no rules for it then the normal message gets printed (with PrintCommand). If singleton_noun doesn’t get set to TRUE, then it just goes straight to calling PrintCommand.

I’d say that maybe the thing to do would be to write an activity that you could hook in at the appropriate spot, but I’m having trouble figuring out how the call to the clarifying the parser’s choice works in a way that might be emulated. Is pattern–>from somehow guaranteed to be an object whenever this gets called, that is, when pattern–>from is greater than 1 and less than REPARSE_CODE? This seems like it might be a particularly thorny bit of the parser, at least for me?

(From a comment in the annotated i6 template Appendix B, the way I6 calls activities is kind of astonishing–activities get assigned ID numbers in order of creation, so the I6 templates define constants for the activities and use BeginActivity with those constants. Which means CLARIFYING_PARSERS_CHOICE_ACT as referred to above is just a constant that stands for the number that this activity gets assigned when the Standard Rules get compiled into I6.)

I checked again and noticed this important note from Appendix B:

(Recall that pattern entries are 0 for “multiple object”, 1 for “special word”, 2 to REPARSE_CODE-1 are object numbers and REPARSE_CODE+n means the preposition n.)

So it looks like for your case, the prepositions, we’re looking at some cases under (i >= REPARSE_CODE). This looks like it might be pretty challenging to hook something into–if you could figure out what number the relevant prepositions were, then you could probably write special cases in there to make sure you had the proper form of the preposition, but I’m not sure how to figure out the number of the relevant preposition. I fear it may be set somewhere in the ni compilation process where we can’t see it even in principle.

Very late reply, but well…

Yeah, it really seems complicated just for that!

I’ll live with it for the moment, using workarounds (putting as first preposition in an understand line one that does not depend on the gender, or even an arrow -> instead.

I’ll investigate later, when I’ll have more time and nothing more important to do regarding the French extension.

The processing of incomplete sentences is also a problem for the translation of Inform 6 libraries.This is partially resolved for the French 6.12.
But if you want a radical and very effective answer to all these problems, add to your grammar, for all verbs that are waiting for a complement, a redirecting to a default message of the type: “Your sentence is incomplete.” or “This verb is waiting for a complement.” or whatever.

Here is an example with the grammar of Inform 6 and the verb Tell. I just added, in the first line of the grammar, a call to a default message if the verb is entered without complement:

[ IncompletSentenceSub;
   "This verb is waiting for a complement.";   
];

Verb 'parler'
   * -> IncompletSentence
   * 'à'/'au'/'aux'/'avec' creature                  -> Tell
   * 'à'/'au'/'aux'/'avec' creature 
                          'de'/'d^'/'du'/'des' topic -> Tell
   * 'de'/'d^'/'du'/'des' topic
                     'à'/'au'/'aux'/'avec' creature  -> Tell reverse
;

But this breaks Inform’s beautiful and complex mechanics (which sometimes does too much!)