Command Execution

Command Execution javelin Sat, 2002-11-30 18:21

When a player types a command, or when a command is dequeued from the queue to be run, it is passed to the command parser, process_command(). In the command parser, the first word of the input is mangled a bit -- spaces are squished, a outer layer of curly braces may be stripped, and %-substitutions are evaluated (the expression parser is used to do these things - it's not just for functions!) To see this behavior at work, type: {say } foo

The command parser now attempts to match the input in the following order, and stops as soon as one of these works:

  1. The complete input to a local exit
  2. The first word (or token in the case of several special symbols like double-quote, colon, etc.) of the input to a standard mushcode command. If this doesn't match, the command parser evaluates the rest of the input (as above, squishing spaces, stripping braces, and evaluating %-substitutions but not functions) and continues.
  3. The complete input to an enter alias of an object in the room
  4. The complete input to a leave alias of the current container
  5. The complete input to $commands on objects in the player's location (including the player)
  6. The complete input to $commands on the current container
  7. The complete input to $commands on objects in the player's inventory
  8. The complete input to exits in the zone master room, if any
  9. The complete input to $commands on objects in the zone master room, if any
  10. The complete input to $commands on the zone master (non-room) object, if any
  11. The complete input to $commands on the player's personal zone, if any
  12. The complete input to exits in the master room, if any
  13. The complete input to $commands on objects in the master room, if any

Then, usually, the commands' arguments are passed to the function parser to be evaluated. The command itself is then run with the evaluated arguments. There are two exceptions to this behavior: commands that get the /noeval switch receive their arguments without this evaluation step, and the &attrib <obj>=<value> style of attribute setting does not evaluate the <value> when run directly by a player descriptor.

Functions aren't commands

Functions aren't commands javelin Sat, 2002-11-30 18:22

This model explains why typing the following results in a Huh? and nothing else:

  if(1,pemit(num(me),test))

The command parser calls the expression parser, but without telling it to evaluate functions, so the above is treated as a single command, fails to match, and gets you a Huh?. On the other hand, this:

  [if(1,pemit(num(me),test))] pose

may result in both 'test' being pemitted and a Huh?, because the []'s force the expression parser to recurse and parse what's inside them with mandatory function checking. However, the expression still returns a null string, which is not a valid command, yielding Huh?

In PennMUSH 1.8 and later, however, most admins have enabled the WARN_ON_MISSING internal command, which generates an error message whenever any command starting with "[" is attempted.

Finally:

  [if(1,say[pemit(num(me),test)])] pose

can result in both 'test' being pemitted, and the player saying "pose", because the expression now evaluates to "say", which is a valid command, and pose is taken to be the argument to the say command.

$commands

$commands javelin Sat, 2002-11-30 18:24

Consider the following attribute, FOOCMD, set on an object:

        $foo *: @pemit %#=%0

What happens when a player (let's say #10) types 'foo A%rB'?

The player's command ('foo A%rB') is passed to process_command. The input doesn't match a local exit, and 'foo' isn't a standard command. Now the rest of the input is evaluated, resulting in the total input being transformed to 'foo A<newline>B'. This isn't an enter or leave alias, so the command parser now checks to see if the input matches a $command, and it does. The resulting action (@pemit %#=%0) is now queued, along with some information about the context in which it was queued (for example, that the enactor was #10, and the first wildcard matched 'A<newline>B').

Eventually, the queued entry is dequeued, and '@pemit %#=%0' is passed to process_command (with the context at which the command was run restored). The input doesn't match a local exit, but @pemit is a standard command. Its arguments are evaluated (and in this context, %# evaluates to #10, and %0 evaluates to A<newline>B), and the command is run, which results in the appropriate @pemit.

Notice that the parsing insures that when the @pemit is queued, %0 in the queue entry's context will be set to the %-substituted input. This is why you can not generally get access to the raw input in your $command (except via %c) -- by the time the actions are dequeued, %-substitions have already happened. Function evaluation has not, which is why a player typing 'foo add(1,1)' will see 'add(1,1)' pemitted back to them. In this situation, a player must type 'foo \\%r' if they want to have '%r' pemitted to them.