curiousdannii-testing / inform7-imported-bugs

0 stars 0 forks source link

[I7-1765] [Mantis 1801] Unexpected behavior of if-lines containing tab characters #319

Open curiousdannii-testing opened 2 years ago

curiousdannii-testing commented 2 years ago

Reported by : otistdog

Description :

[Note that this uses similar example code to another report, but it is a separate issue.]

Note that in the "test me" responses for the provided example code, responses #1 and #3 show that both a defined condition and the otherwise condition for the "list recorded specimens" rule's if statement are applying. Since the specified comparison is "is" (should translate to ==, right?), this does not seem like correct behavior, and it is counter to what is described in WWI 11.8, which states:

One alternative is allowed to be "otherwise", which is used only if none of the other cases apply, and which therefore guarantees that in any situation exactly one of the blocks will be followed.

My apologies if there's some subtlety here that I'm missing. If that is the case, please treat this as a request to expand the documentation to illustrate why this doesn't work as might be naively expected.

Steps to reproduce :

"Test"

Place is a room.

Recording relates one thing (called the catalog) to various things. The verb to record means the recording relation.

The player carries a thing called a birdwatcher's guide.

A bird is a kind of animal.

A bird called a magpie is in Place. A bird called a cardinal is in Place.

Check examining a bird (called specimen) recorded by the birdwatcher's guide (this is the catalogued birds are of no interest rule):
    say "You've already recorded [the noun]." instead.

Check examining a bird (called specimen) when the birdwatcher's guide records at least 5 things (this is the done for the day rule):
    say "You don't need any more specimens today."

After examining a bird (this is the record examined things rule):
    now the birdwatcher's guide records the noun.

Carry out examining the birdwatcher's guide (this is the list recorded specimens rule):
    if the number of things recorded by the birdwatcher's guide is:
        -- 0: say "You've recorded nothing.";
        -- 1: say "You have recorded only [the list of birds recorded by the birdwatcher's guide].";
        -- otherwise:   say "You have records of [the list of birds recorded by the birdwatcher's guide].";
    rule succeeds.

Test me with "x guide / x magpie / x guide / x cardinal / x guide / x magpie". 

Additional information :

Turning on rules shows both responses are occurring in the same execution of the rule. The generated I6 looks like:

=======================================

! Carry out examining the birdwatcher's guide ( this is the list recorded specimens rule ):
[ R_780
tmp_0 ! Let/loop value, e.g., '?-1,-1?'(deallocated by end of phrase)
;
if ((( (actor==player) && ((noun == I125_birdwatcher_s_guide) && (true))))) { ! Runs only when pattern matches
self = noun;
if (debug_rules) DB_Rule(R_780, 780);
! [1: if the number of things recorded by the birdwatcher's guide is begin]
switch((Prop_25()))

{ ! [2: -- 0] 0:

! [3: say ~You've recorded nothing.~] say__p=1;ParaContent(); print "You've recorded nothing."; new_line; .L_Say146; .L_SayX146; ! [4: -- 1] ; 1:

! [5: say ~You have recorded only [the list of birds recorded by the birdwatcher's guide].~] say__p=1;ParaContent(); print "You have recorded only ";ParaContent(); objectloop(tmp_0 ofclass Object) if (((tmp_0 ofclass K16_bird) && (I125_birdwatcher_s_guide == (RGuard_f0_2(tmp_0))))) give tmp_0 workflag2; else give tmp_0 ~workflag2; WriteListOfMarkedObjects(ENGLISH_BIT+DEFART_BIT);ParaContent(); print "."; new_line; .L_Say147; .L_SayX147; ! [6: -- otherwise] ; default:

! [7: end if] }

! [8: say You have records of [the list of birds recorded by the birdwatcher's guide].]
say__p=1;ParaContent(); print "You have records of ";ParaContent(); objectloop(tmp_0 ofclass Object)
if (((tmp_0 ofclass K16_bird) && (I125_birdwatcher_s_guide == (RGuard_f0_2(tmp_0)))))
give tmp_0 workflag2;
else
give tmp_0 ~workflag2;
WriteListOfMarkedObjects(ENGLISH_BIT+DEFART_BIT);ParaContent(); print "."; new_line; .L_Say148; .L_SayX148;
! [9: rule succeeds]
RulebookSucceeds(); rtrue;
} else if (debug_rules > 1) DB_Rule(R_780, 780, 'action');
rfalse;
];

=======================================

..and it looks like the "otherwise" condition at the I7 level is being translated as a separate "if" block.

imported from: [Mantis 1801] Unexpected behavior of if-lines containing tab characters
  • status: Reported
  • resolution: Open
  • resolved: 2022-04-07T05:00:50+10:00
  • imported: 2022/01/10
curiousdannii-testing commented 2 years ago

557058:4c095ffd-6d6f-47ce-9e73-77c613347b86:

Comment by zarf :
In your sample code, there is a tab between "-- otherwise:" and "say...". This apparently causes Inform to treat "say..." as a new line beginning with one tab. That matches the behavior you're seeing.

If you change the tab to a space, you get what you want.

I think this counts as a lexing bug. You see the same thing if you write


if 1 is 1: say "One"; [tab after the colon]

The compiler behaves as if the tab were a newline-tab. I suggest that a tab which appears after any non-whitespace characters (on the line) should be treated as a space instead.

(Except in tables, which have their own tab semantics, obviously.)

curiousdannii-testing commented 2 years ago

557058:4c095ffd-6d6f-47ce-9e73-77c613347b86:

Comment by zarf :
Actually, my example in the previous comment is invalid code even with a space. Ignore it.

curiousdannii-testing commented 2 years ago

557058:4c095ffd-6d6f-47ce-9e73-77c613347b86:

Comment by otistdog :
It must have gotten that way while cutting-and-pasting, and I didn't notice because it ended up only one space wide in my window. Perhaps I should have noticed the way it turned out after copy-and-pasting it above... the spacing and line breaks are quite different from how they look on my screen.

At any rate, changing it to a space definitely fixes things. Thanks, and thanks for updating the title.