Oho! Now this is a fascinating one! It seems to be a library bug, not a compiler bug.
The way Dialog('s standard library) parser works, it first tries to parse the words into an action, gathering up all the possibilities into a list. If that doesn’t work, it sets a flag called (allowing parse errors) and runs the parser again, this time taking only the first result. When this flag is set, routines like “look for a noun” are also allowed to return special values like [] to mean “I’m looking for a noun but not finding one”, [1] to mean “I’m looking for an animate noun but not finding one”, [,] to mean “I’m looking for one object but found a list instead”, or [all] to mean “I’m looking for one object but found ALL instead”.
Keep this in mind for later.
When it’s looking for a noun, it calls the predicate (parse object name $Words as $Result $All $Policy). $All is set to 1 if ALL is allowed, and $Policy indicates which objects should be preferred. This can either be a closure like { (item $_) } (to prefer items), or an object (to prefer children of that object). It’s enforced like this:
(interface (verify object policy $Policy $<Obj))
(verify object policy (object $Policy) $Obj)
($Obj has parent $Policy)
(verify object policy (nonempty $Policy) $Obj)
(query $Policy $Obj)
Why (nonempty $Policy)? Because closures are internally represented by lists. Something like { ($_ has parent $Obj) } is compiled into something like [43 $Obj], and a rule like this is added at the top of the program:
(query [43 $Obj] $_) ($_ has parent $Obj)
This means there’s no way to tell for sure if something is a closure. You just have to check whether it’s a nonempty list.
So far so good, right?
Now, here’s how ASK X FOR Y is parsed.
(understand [ask | $Words] as [tell $Actor to give $Obj to $Player])
*(split $Words by [for] into $Left and $Right)
*(understand $Left as single object $Actor preferably animate)
*(understand $Right as object $Obj preferably child of $Actor)
(current player $Player)
What happens if you ASK FOR SOMETHING with no first object?
$Words is set to [for something].
- Splitting this by
for produces [] and [something].
[] doesn’t match any object. Parsing fails.
- Let’s try again with
(allowing parse errors) set!
$Words is set to [for something].
- Splitting this by
for produces [] and [something].
[] doesn’t match any object. Since we’re looking for an animate object, and allowing parse errors, return [1] (which means to print “someone” in the error message).
- Now, try to parse
[something] as an object, preferably a child of [1].
- If we find a matching object, compare it against the policy
[1].
- Since
[1] is a nonempty list, we check the policy by calling (query [1] $Obj).
Uh oh! [1] was supposed to be an object placeholder here, not a closure! But it’s a nonempty list, so now we’re calling the second closure compiled, whatever that might be. (The first one is [0 | $Whatever].)