Parser ignores parts

Why can’t I get the parser to consider a part of something when there’s ambiguity in the player’s command?

[code]Quarry is a room.

The gravel is a thing in Quarry. Understand “rock” as gravel. A rock is a part of gravel.

Does the player mean doing something with something that is part of gravel: It is very likely.

Does the player mean doing something with gravel: It is very unlikely.

test me with “get rock”[/code]

If there’s no conflict between the names, the parser is happy to tell me “that seems to be a part of gravel.” But as soon as I let the gravel be understood by the same word, it doesn’t even let me know the rock exists.

I feel the solution involves Understand “rock” as gravel when… but I can’t imagine what the condition would be, since the rock is part of the gravel and hence, always, always there.

Having said this, I’m not sure why this problem you’re having is a problem.

ScopeCeiling applied to the gravel is the Quarry, the same as ScopeCeiling applied to the player. ScopeCeiling applied to the rock, on the other hand, is the rock. If you look at the I6 routine Adjudicate (>TRACE 4 is your friend), you’ll see that MULTI_TOKEN verbs (those where you can use the word all'') prefer objects whose scope ceiling matches the actor's, a preference that takes priority over does-the-player-mean rulings. That's whyx rock’’ works while ``get rock’’ does not.

How about this then, guys?

[code]Quarry is a room

The gravel is a thing in Quarry. A rock is a part of gravel. Understand “gravel” as a rock when not examining.

Does the player mean doing something with a rock: It is very likely.

Does the player mean doing something with gravel: It is very unlikely.

test me with “get gravel/drop gravel/get rock”[/code]

The altered Understand line here matches the actual situation in my extension better - does that help you understand what I’m trying to do?

The “get rock” test demonstrates that the rock is in scope for taking, just not when it shares an Understand token with the gravel. I still want to know why.

Is

the intended output?

Yes, that’s the intended output.

Maybe the best way to explain it is that multitoken verbs like TAKE try to avoid applying to parts of things when they can, to prevent output like

rather than

One way to get that behavior you want is to modify Inform’s notion of the scope ceiling, so that parts aren’t treated as a special case. For instance, replacing ScopeCeiling with [ ScopeCeiling pos c; if (pos == player && location == thedark) return thedark; c = VisibilityParent(pos); if (c == 0) return pos; while (VisibilityParent(c)) c = VisibilityParent(c); return c; ]; in Light.i6t will do the trick. But the comment immediately above it would suggest that ScopeCeiling wasn’t written this way on purpose:

(Aside: we’re getting into areas of the template layer that are more nebulous to me, but I don’t think ``this makes a difference if |pos| is inside a container which is itself part of something else’’ is correct—I think that the difference only matters when |pos| is directly part of something.)

If you make this change, you ought to compensate with at least a to-decide-whether-all-includes rule. And then there are still cases like when a plural is defined and the player enters > TAKE TWO ROCKS. I guess it depends on how much you’re willing to alter the current parser behavior.

Forgive me if I’m being thick-headed, but are you saying that ScopeCeiling is being called when the command includes “gravel” and it’s not being called when the command includes “rock?” And from where is ScopeCeiling called? I’m a little vague on what the “pos” parameter represents and what the “core” of an object is.

I’m reading through the Adjudicate routine in Parser.i6t, and I have a pet peeve. I like every function in code to fit on one screen. It’s not that hard to do, it helps modularity, and it increases readability exponentially. Unfortunately, most parser-related functions in i6 and the templates fill 5 or 6 screens. That’s actually a big selfish reason I’d like to do a parser-rewrite extension.

But I think I’m getting a picture of what’s going on. Parts of things are always last-choice options for the parser, and if anything else matches, they’re considered unimportant. Is that the basic philosophy? Is it any different in Disambiguation Control?

In terms of performance, please don’t use extra functions. For web interpreters they are a major source of slowness. The fewer functions the better! If that’s a problem… get a bigger screen?

I do not actually believe this. Even if it is true, the functions in the code that will be called often enough to hurt performance are a tiny fraction of the total. This is true even in the parser.

From my tests usually around 30% of the processing time is spent building new functions, which won’t be a problem for commonly run code like the parser.

BUT, another 25% of processing code is spent in the two functions which implement @call and @ret. (Sometimes up to 60%!) It’s that infrastructure which is slow, and sometimes far outweighs the code itself. I’d love to be able to improve the situation, but I think I’ve optimised those functions as much as I can. Sometimes there’s 100k function calls a turn or more, but if they could be reduced to 20k or so then the whole time would take 20% less. The only strategy I’ve yet to try is to inline all of the function calling/return code in the JIT code itself.

The situation could be different for Quixe… have you done much testing to determine how much time is spent for enter_function() and leave_function()?

I’ve always been curious what, if any, optimizations the I6 code generator does. Will it inline very short functions? Will it inline functions that are only called from one spot? Does it eliminate dead code? Does it use at least a peephole optimizer? Etc.

I used to program action videogames in assembly, sometimes mixing in some C, so I’ve always had a love for making programs go faster.

(Step one: add racing stripes!)

Okay then, if I get around to working on this idea, I’m asking Ron to help optimize it!

I assume you’re excellent at painting racing stripes, Ron… :wink:

Tell me if I’m understanding this correctly - the Adjudicate routine runs before ChooseObjects, which calls the Does the Player Mean Rules. Adjudicate can eliminate some choices on its own (at least if the verb can take multiple objects), so the DPMR never gets to some things. Am I starting to understand the limitations of the DPMR?

I think in a sense it’s reasonable to do things this way, because determining what the player meant will probably always rely on some sort of score calculation. Since a rulebook stops running rules when it returns a value, it doesn’t make sense to have DPMR make the decision all on its own - it can only get a decision from a single rule.

To achieve my goal of exposing more of the parser to I7, I think there would need to be an activity similar to choosing notable locale objects, where we set or adjust a match score as opposed to making a single decision and exiting. Would it be possible to express all the existing parser logic with such a thing?

Also, even if a verb can take multiple objects, can’t the parser tell when there’s only one object listed in a command? Why can’t it treat that as a non-MULTI object?

No to all of those, I think. Which is fine in my opinion, it’s more of an assembler than a compiler. We can get much better performance through the I7 compiler than the I6 compiler.

Right. Sorry that I failed to write clearly. As you probably saw if you trudged through Adjudicate, the parser identifies both the gravel and the rock as possible interpretations, and then divides that set into two categories: the good ones and the bad ones. When there are any good ones, the bad ones aren’t considered. And for a MULTI_TOKEN verb like TAKE, the gravel qualilfies as a good one because ScopeCeiling returns the same thing when pos is the player as it does when pos is the gravel. Because of a funny quirk in ScopeCeiling, the rock doesn’t enjoy the same luxury. (But things contained by the rock would.)

It can tell. But why it’s testing what the verb is looking for (the MULTI_TOKEN) rather than what it was given, I do not know. Maybe someone else can explain?

I haven’t tested with Disambiguation Control, but reading its override of Adjudicate, it seems to make the same special case for MUTI_TOKEN verbs.

Also, belated: An object’s core is whatever it is ultimately a part of. So if the tine is part of the fork, the fork is part of the place setting, the tine’s core is the setting.