Scoping Verbs & Syntaxes
I’m again struggling with some Alan language syntax constructs which I can’t work out how to scope; namely, the VERB
and SYNTAX
constructs. These are used to create verbs that the player can type in the adventure game, and which do something in the game world, and to define their syntax.
The VERB
BNF is:
verb = ['META'] 'VERB' id {',' id}
verb_body
'END' 'VERB' [id] '.'
The SYNTAX
BNF:
syntaxes = 'SYNTAX' {syntax}
syntax = id '=' {element} syntax_end
element = id
| '(' id ')' [indicator]
Are these functions?
To me, verbs look like functions, but they don’t follow the usual syntax of functions or procedures in other languages. For one thing, verbs can be defined globally (only if they are intransitive), or inside classes and instances; they can even be added to existing instances via the ADD TO EVERY
construct. An example of SYNTAX
and VERB
, where the verb is added to every instance at initialization time:
SYNTAX paint = paint (obj)
WHERE obj ISA OBJECT
ELSE "That's not something you can paint."
ADD TO EVERY OBJECT
VERB paint
DOES "You paint" SAY THE obj. "."
-- (MAKE obj painted.)
-- (DECREASE amount_left OF red_paint BY 2.)
END VERB.
END ADD TO.
And here an example how to implement an instance-specific variant of an already existing verb (overriding/overloading it):
THE street ISA OBJECT AT town
-- [... some definitions ...]
VERB cross
DOES "There's too much traffic."
END VERB.
END THE street.
Maybe Function calls or Forward declarations?
But what perplexes me most is the SYNTAX
construct, which defines its parameters and how the verb is constructed, allowing different phrasings of the same VERB
— ie, syntaxes point to verbs, so they look like actual function calls, or maybe forward declarations?
Why not interfaces?
Syntaxes have strictly tied to how player’s input is linked to a specific verb (a verb’s identifier is usually also available to the player as a command, but not always: the presence of an _
in the verb ID will hide it from the the parsable player commands). From this angle, they resemble interfaces.
The problem is that parameters are defined in SYNTAX
constructs, while in VERB
blocks you can only hanlde them, but not define them. For example:
SYNTAX
take = 'take' (obj)*.
talk_about = 'talk' 'to' (act) 'about' (subj)!.
… defined the parameters (their number and names) which will be passed on to the VERB
by the commands parser. So if the player types take bottle
, then the verb take
will be invoked, and bottle
will be passed to it as parameter obj
. It looks like both a function call and and interface to me.
Moreover, syntax statements can also have restriction to them:
SYNTAX
take = 'take' (obj)
WHERE obj IsA object
ELSE "You can't take that."
So it looks like they are both part of the same function/procedure construct, whose definition is scattered in different places. I find it a bit puzzling when it comes to decide how to scope these.
Could they be function pointers?
Also, different syntaxes can point to the same verb, which is intended to allow the player to impart commands in different word ordering. Example to allow both give the pen to Bob
and give Bob the pen
:
SYNTAX
give = 'give' (obj) 'to' (recip)
WHERE obj ISA OBJECT
-- [...more checks/restrictions...]
give = give (recip) (obj).
… in this last example, the checks and restrictions can only be written for the first give
syntax definition, and they’ll will also apply to all give
variants/synonims. Which reminds me of function pointers!
The point here is that I’d definitely like verbs to be indexed, and possibly also to use the Goto Definition functionality with them, allowing to jump to the block that defines a verb. I haven’t actually worked out how ST handles Goto Definition, but I had the impression that this is a special built-in fucntionality that only applies to functions (ie: elements scoped as functions), is that correct?
When The Duck Test Isn’t Enough…
Again, the question of how to scope these syntax constructs boils down to be able to make use of them somehow (autocompletion, indexing, plugins, color schemes, etc.). Finding parallels with other languages is not easy for me, as they seem to overlap different constructs, and I have no idea how strict the criteria are when it comes to fitting common scopes.
I try to follow the Duck test here, assuming that:
If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.
… except that to me these constructs seem to walk like a function, swim like a procedure call, and quack like an interface!
… I’m really lost in semantic translation here!!!