[I7] Odd responses from parser

Here’s the debug trace:

>trace
[Trace on.]

>drop nails
[Parsing for the verb 'drop' (4 lines)]
[line 0 * multiheld -> Drop]
[line 1 * held 'at' / 'against' noun -> ThrowAt]
[line 2 * multiexcept 'in' / 'into' / 'down' noun -> Insert]
What do you want to drop those things in?

>take nails
[Parsing for the verb 'take' (6 lines)]
[line 0 * 'inventory' -> Inv]
[line 1 * multi -> Take]
[line 2 * 'off' noun -> Disrobe]
[line 3 * noun 'off' -> Disrobe]
[line 4 * multiinside 'from' noun -> Remove]
[line 5 * multiinside 'off' noun -> Remove]
He seems to belong to the hamster.

In both cases, it seems quite clear that I6 should not – indeed, cannot – match those grammar lines. The use of “He” is a separate, and even more peculiar – issue.

I don’t get the ‘he’ issue, though it could still somehow stem from what I’m guessing is the first (nails) issue.

A subsequent poster will probably be able to elaborate more technically, but I know that basically the presence of types of things and incidences of those things that use the default name of the type (e.g. type is nail) – or other objects sharing the name – is a circumstance that can change the behaviour of get, drop and related verbs, sending them down slightly unexpected (or undesired) roads. Inform is trying to distinguish between counting up objects of a type and multiple objects with the same name of any type, and gets more finicky about bundling these things together, and/or what it will let the player do with them.

You see all those ‘multi(X)’ comments in the trace; I think that’s it telling you that it is going down the multi road where it’s interpreting ‘nails’ this way. Them being part of another object may be an additional parsing complication.

I’ve rarely used multiple incidences of a type myself (e.g. three marbles) so another thing worth checking perhaps is that the three nails are what you think they are… three objects of type nail, each called nail. And not, say, an object called ‘three nails’. Glancing at it, I expect they’re what you think, but it is worth checking.

-Wade

1 Like

Yes, they’re separate objects. The index confirms that.

In the second command, line 1 (* multi) should have been matched. In the first command, none of the lines should have been matched. Specifically, multiexcept has nothing to do with the input, so Insert is clearly the wrong choice of Action.

TAKE NAILS acts as expected if you first drop the board. DROP NAILS, uh, sort of does in terms of practical outcome, but not at the parsing level (It goes to 'There are none at all available!) So I suspect a conflict between the ‘multi’ behaviour and Inform’s deep-down favouring of things the player is carrying in terms of how the command falls apart when you’re carrying the board.

-Wade

1 Like

And interestingly, that also alters the results of ‘take stamps’. Now the hamster is not mentioned; now we get this:

>take stamps
What do you want to take those things from?

My tentative conclusion would be that the parser is tying itself in knots because the player is carrying TWO things each of which has parts.

Nonetheless, this ought not to happen.

1 Like

Amen!

-Wade

An interesting study! Quite a wrench in the gears for the default code of 6M62.

For >DROP NAILS, the issue seems to stem from:

  1. The parser sees the nails as potentially matching the plural word “NAILS” in the input, but while trying to match the grammar for the dropping action, it is disqualifying all of the actual individual nails, presumably because they (as part of the board) are not directly held, so they don’t match the required multiheld token.
  2. Next, the parser abandons a grammar line for the throwing it at action because that uses a held grammar token. In addition to the fact that the nails aren’t held, this action doesn’t allow multiple objects.
  3. However, then the parser tries the grammar for an inserting it into syntax variant (appropriate to cases like " >DROP COINS INTO WELL"), which uses the multiexcept token. This token does not require that the noun object(s) be held, so the parser is continuing on the assumption that the player only typed half of the command. It assumes that the preposition “in” is applicable and is looking for a definition of the second noun, prompting the question. If the question is answered, it will produce a parser error message for the nothing to do error.

For >TAKE NAILS, the issue seems to stem from:

  1. The nails again appear to be being disqualified as appropriate objects to match “NAILS”, this time due to the “exclude indirect possessions from take all rule”, which is being invoked as the parser tries to process grammar lines using multi or multiinside tokens. As a result, no grammar lines are found to match the verb word 'take', and the parser error type is again determined to be the nothing to do error.
  2. This triggers parser nothing error internal rule response C, with substitution "[regarding the noun][Those] [seem] to belong to [the noun]." per the Standard Rules. (An aside: It seems like at least one of the references to noun should be to some other entity.) By a confluence of factors, the noun is being defined as the hamster via some special case code related to reporting this particular parser error for the removing it from action (which was the action for the last grammar line tried):
    if (etype == NOTHING_PE) {
	    if (parser_results-->ACTION_PRES == ##Remove && ! ** last grammar line tried is for ##Remove
        	parser_results-->INP2_PRES ofclass Object) { ! ** hamster is an object (but why hamster?)
        	noun = parser_results-->INP2_PRES; ! ensure valid for messages ! ** this is how the hamster becomes noun
            if (noun has animate) { PARSER_N_ERROR_INTERNAL_RM('C', noun); new_line; } ! ** hamster is animate

It’s somewhat mysterious how the hamster gets assigned to parser_results-->INP2_PRES in the first place. However, you can see it happening if you turn up the tracing level to 3:

[line 4 * multiinside 'from' noun -> Remove]
 [Trying look-ahead]
 [Look-ahead aborted: prepositions missing]
 [line 4 token 1 word 2 : multiinside]
  [Object list from word 2]
  [Calling NounDomain on location and actor]
Parse_name called
[ ... lots of uninteresting lines clipped here ...]
Pass 1: 0 Pass 2: 0 Pass 3: 0
  [ND appended to the multiple object list:
  List now has size 0]
  [token resulted in success]
 [line 4 token 2 word 3 : 'from']
  [token resulted in success]
 [line 4 token 3 word 3 : noun]
  [Object list from word 3]
  [Calling NounDomain on location and actor]
Parse_name called
Parse_name called
  [ND returned the hamster] ! ** provisional second noun?
  [token resulted in success]
 [line 4 token 4 word 3 : END]

After that assignment the special code block is how it becomes the noun that is referenced in the parser error message. Note that this assignment seems to be related to the fact that the hamster is the only other object in the room, as mentioned by severedhand.

Perhaps in a month or two I will have traced far enough into the parser to figure out where and why the relevant assignment takes place. More likely, someone who has already blazed that trail will come along to explain.

The situation with the stamps is essentially similar, because they are part of the envelope, just like the nails are part of the board.

I would like to congratulate you for crafting such a wonderful bit of sabotage. It’s very impressive!

To your further credit: I’ve been trying to figure out how to do this scenario “right”, but I haven’t come up with anything satisfactory yet.

5 Likes

It was an accident, honest. I do have a vague idea about a puzzle involving a board with some nails driven into it. I don’t remember why it occurred to me to add the stamps or the hamster, except that every good test suite ought to have a hamster in it!

3 Likes

Truer words were never spoken (or written I guess).

1 Like

Interesting thread. Seems that a solution (or is it just a cheap work-around?) is to define a new action instead of hoping that “drop” will work right out-of-the-box:

The Lab is a room. "Bubbling retorts, that sort of thing."

A board is a kind of container. 
The two-by-twelve is a board.
The printed name of two-by-twelve is "two-by-twelve board".
Understand "board" as the two-by-twelve.

The player carries the two-by-twelve.

A nail is a kind of thing.

The rusty nail is a nail.
It is in the two-by-twelve.

The crooked nail is a nail.
It is in the two-by-twelve.

The new nail is a nail.
It is in the two-by-twelve.

Prying is an action applying to one thing.
Understand "pry [things]" as prying.
Understand "drop [things]" as prying.

Check prying:
	if the noun is not held by the two-by-twelve:
		instead say "[The noun] isn't in the [two-by-twelve]."

Carry out prying:
	silently try taking the noun;
	silently try dropping the noun;
	say "You pry [the noun] out of the board, and it tumbles to the floor."

A hamster is in the Lab. 
The hamster is an animal. 
The description of the hamster is "Small and cute." 
Understand "critter" and "rodent" as the hamster.

Test me with "i / x board / pry crooked nail / l / i / x board / drop nails / l / i / pry rusty nail / l / i / x board".

This produces this output:

Lab
Bubbling retorts, that sort of thing.

You can see a hamster here.

>test me
(Testing.)

>[1] i
You are carrying:
  a two-by-twelve board
    a rusty nail
    a crooked nail
    a new nail

>[2] x board
In the two-by-twelve board are a rusty nail, a crooked nail and a new nail.

>[3] pry crooked nail
You pry the crooked nail out of the board, and it tumbles to the floor.

>[4] l
Lab
Bubbling retorts, that sort of thing.

You can see a crooked nail and a hamster here.

>[5] i
You are carrying:
  a two-by-twelve board
    a rusty nail
    a new nail

>[6] x board
In the two-by-twelve board are a rusty nail and a new nail.

>[7] drop nails
crooked nail: The crooked nail isn't in the two-by-twelve board.
rusty nail: You pry the rusty nail out of the board, and it tumbles to the floor.
new nail: You pry the new nail out of the board, and it tumbles to the floor.

>[8] l
Lab
Bubbling retorts, that sort of thing.

You can see a new nail, a rusty nail, a crooked nail and a hamster here.

>[9] i
You are carrying:
  a two-by-twelve board

>[10] pry rusty nail
The rusty nail isn't in the two-by-twelve board.

>[11] l
Lab
Bubbling retorts, that sort of thing.

You can see a new nail, a rusty nail, a crooked nail and a hamster here.

>[12] i
You are carrying:
  a two-by-twelve board

>[13] x board
The two-by-twelve board is empty.

>

Seems to produce what was intended, eh? The stamp-detaching would work exactly the same way.

Or is there something much more profoundly disturbing in all of this? Just trying to grok I7 in its many-splendored beauty!

The main problem with defining it as a container is that now it’s possible to put a nail back inside the board – and also possible to put the hamster in the board, which is even more silly.

The original part of method avoided that because there aren’t any default actions that can make or remove that relation, so it’s entirely at the author’s control.

It’s possible via various means to disable the standard actions for this case, but it’s probably better to avoid getting into this situation in the first place.


Incidentally, I believe in the end the underlying problem was eventually solved in this thread.

1 Like

Personally I would think that nails – which can be driven into a board and removed and driven in again – would be more appropriately be modeled in something other than a part-of relation. But your point is well-taken that to use a container would require a bunch of checks to ensure that something like a hamster can’t be pounded into the wood as well.

I’m also glad to read in the other thread that it is procedurally possible to remove a part that has been added to an object. I believe that there is no example code in Writing with Inform that shows how to do that, but now that I know it’s possible, I’ll continue the search. Seems like an important technique to know how to do. Thanks!

For future reference: removing a part turns out to be effortless and is demonstrated in example 36 “Brown” in Writing with Inform. Or to simplify:

Lab is a room.

Baz is a thing in Lab. "A Baz. I declare."
The description of Baz is "[if fu is part of baz]It has a Fu, too[otherwise]A fu-less Baz[end if]!"

Fu is a part of Baz.

Instead of taking fu when fu is a part of baz:
	now the player carries the fu;
	say "You yank out the fu."

Instead of pushing fu when fu is not a part of baz:
	now fu is part of baz;
	say "You squeeze the fu back in."
	
Test me with "x baz / showme baz / take fu / x baz / showme baz / push fu / x baz / showme baz".

Which produces:

Lab
A Baz. I declare.

>test me
(Testing.)

>[1] x baz
It has a Fu, too!

>[2] showme baz
Baz - thing
    Fu (part of Baz)
location: in Lab
singular-named, proper-named; unlit, inedible, portable
list grouping key: none
printed name: "Baz"
printed plural name: none
indefinite article: none
description: "It has a Fu, too!"
initial appearance: "A Baz. I declare."

>[3] take fu
You yank out the fu.

>[4] x baz
A fu-less Baz!

>[5] showme baz
Baz - thing
location: in Lab
singular-named, proper-named; unlit, inedible, portable
list grouping key: none
printed name: "Baz"
printed plural name: none
indefinite article: none
description: "A fu-less Baz!"
initial appearance: "A Baz. I declare."

>[6] push fu
You squeeze the fu back in.

>[7] x baz
It has a Fu, too!

>[8] showme baz
Baz - thing
    Fu (part of Baz)
location: in Lab
singular-named, proper-named; unlit, inedible, portable
list grouping key: none
printed name: "Baz"
printed plural name: none
indefinite article: none
description: "It has a Fu, too!"
initial appearance: "A Baz. I declare."

>

So: it’s gone and back again. I wouldn’t have been able to guess the syntax “now the player carries [the part]” as being what’s needed to remove the part. But there it is.

Any statement that changes the part’s location should work.

now the part is in the Kitchen;
now the part is off-stage;
1 Like

Good to know! Thank you!

If you have a look at Index -> Phrasebook -> Relations, you can see that containment (inside), support (on top of), and incorporation (part of), among a few others, are all “spatial” relations.

This means that Inform knows that when you change one of these, all the others change as well. (This is also a side-effect of how Inform models all of these relations in the underlying I6 code – they all share the same storage.)

I don’t think it’s possible to define a new kind of spatial relationship; they’re implemented with internal compiler magic. But the existing ones are broad enough to serve most purposes, and you can tweak the related behaviour to suit as well.

Incorporation (part of) is a particularly good one to use for things that are physically stuck together in some way (such that a simple “take” or “remove” command should not be sufficient), since there aren’t any default actions that are permitted to change this relationship (there’s already check rules that refuse to do so, although you’re likely to want to customise the failure message), and yet it’s still easy to write a rule that will do so under the right circumstances.

The Rules of Attraction example is an interesting demonstration of this – it models a magnet that things can be stuck to, although it does allow “take” to easily remove them again.

1 Like

Specifically, the thing-to-thing spatial relationships you’re likely to use in a game are containment,

The ball is in the box.

supporting,

The box is on the table.

incorporation,

A shipping label is part of the box.

carrying,

The player carries a black magic marker.

and wearing.

The player wears a woolen scarf.

As @mirality mentioned, these five relations are all mutually exclusive, because for efficiency reasons Inform internally keeps track of everything as a strict tree hierarchy, with a room at the top of each tree (or a thing, if it is nowhere); then under that, all the things which are out in the open in that room (or contained in/supported by/carried by/worn by/part of that nowhere thing); then under each of those things, their individual contents; and so on down into deeply nested things.

Possession (If the player has the star sunglasses:) is a superset of wearing and carrying together, so authors don’t need to worry about how a player (or other person) is using something wearable, just that they have it. And concealment is strange because you can’t just declare Now Bob conceals the dynamite.; you have to define it indirectly, via a Rule for deciding the concealed possessions of Bob:, instead.

The rest are mostly esoteric terms only used in the Standard Rules, although holder of might be useful if you want to know exactly where a thing is located (openly in a room, or in/on/part of/held by some other thing), and encloses is roughly that relation in reverse.

You can play around with that tree hierarchy directly by using the testing command abstract:

>abstract redwood to me

makes the player carry the redwood tree,

>abstract lilypad to wardrobe

makes the wardrobe contain the lilypad,

>abstract Janet to mantelpiece

moves Janet on top of the mantel, and so on.

Technically, you could create a new spatial relation; but you’d need to explicitly unset all of the above five to set it, and then you’d need to explicitly move it around to whatever thing it was supposed to be attached to. Probably best to hijack one of the existing relations, and just write special-case rules for setting or unsetting it and displaying it to the player, as necessary. So handcuffs and manacles could be worn items that just can’t removed in the normal way, and probably so should permanent features on the player like tattoos (things being part of the player was a bit buggy a couple versions ago, and even if that’s apparently been fixed, worn items appear automatically in the inventory listing, while parts don’t), while new spatial relations between other things might best be modeled as incorporation.

I don’t know the code details, but Eric Eve’s Underside extension certainly defines a new kind of spatial relationship.

Specifically, that extension defines

An underside is a kind of container.

and instructs the author to make an underside thing which is part of the thing to be hidden under. Which is usually going to be good enough.

I’m aware; I extended it a while back :wink:

I don’t really count that as a new spatial relationship; it’s a manipulation of the containment relation and you can’t directly assert it (i.e. now the key is under the table doesn’t work; you need to use the custom phrase move the key under the table). But yes, within certain constraints you can fake a new relationship well enough for most purposes.

1 Like