Command Processing
3 November 1994, email to lily-dev@rpi.edu.
When we left our intrepid adventurer last night she had just discovered the entry point of command processing in lily. We now resume with
#0:do_command..
Once the user has typed something in, the do_command verb takes over. The primary concern of
#0:do_command() is to handle dispatching, prefixing, and suffixing. Dipatching is easy and just involves calling the player objects's
do_command() verb. Prefixing and suffixing allow a client to know when a command's output begins and ends. To accomodate this the player object holds a pair of strings in
player.fixes. fixes[1] is the prefix string, and fixes[2] is the suffix string.
#0:do_command() an excellent spot to install benchmarking, in MOO terms "tick counting", so it is often the source of those annoying
<* "foo" took n ticks *> messages. The command is quickly passed to the player object's
do_command() verb. Each kind of player object, including helper, client, and user, has a different
do_command() verb. We will discuss the user's version of the verb only.
With Core 2.2a1, command leafing was introduced. This concept was first explored by
Prisoner in the
CloverLeaf project. With excellent suggestions by both Prisoner and Whammy, lily's leafing feature was developed. At the start of
$player:do_command a check is made for the client option
leaf. If it exists a client command is sent
%begin (command) [task_id], and the task_id is added to a list in the player object. Whenever output is pushed through
$player:notify(), if the current task_id is found in the list then
%command [task_id] is prepended to the line being sent to the client. At the end of the command's execution
%end [task_id] is transmitted.
$player:do_command() is actually a fairly small routine given that it processes all of the input by 99% of the active
connections on lily. If
argstr begins with a '/', then we know we have a command of some kind. First we look in
$player.aliases, if the command, as typed, matches against a line in the aliases list, then insert the alias information into the existing arguments list and string. Now look up the partial command name with
$sset_c:find_names which returns a list of commands that can match with what he user typed. Then we pass that list to
$list_utils:match() and ask it to match the full command entered by the user against the list of possible matches given by
$sset_c:find_names(). At this point we have a list which is empty if there were no matches or a list containing the
completely evaluated command name (ie
/whe returns
{"/where"}). If the fully resolved name is in the list of cardgame commands *and*i the player is participating in a cardgame call the player's cardgame's
do_command() verb. Otherwise call verb defined by
$command_mode:(command_name)(), for example,
$command_mode:({"/where"}[1])();.
If the command begins with '$' and the player is in $admins, follow the same process detailed above, leaving out the cardgame stuff and the alias expansion.
If the command begins with '@' and the player is a programmer, call the corresponding verb on
$admin. This uses the old MOO style of command processing. For more information on this, check out the
LambdaMOO Programmer's Manual.
If the command begins with '?' and the player is a helper (i.e.
player.helper = 1=), follow the same process detailed
for '@' commands, but call the command name on object $help_mgr.
At this stage we have processed all the known command prefixes,
{"?","@","$","/"}. We then assume it is a message and call the
$command_mode:send() verb.
The send() verb is quite litterally the largest and most complex verb on the entire system, outweighing the sendlist() verb by almost 40 lines. Much of the reason for this complexity is, like sendlist(), send() is an amalgam of every single pidling little request ever for sending. Amazingly enough send() casts into stone bugs that existing in Clover which became later day features. Also, send() makes use of an amazingly large number of properties in the player object, so I'll will do a brief rundown those properties over here.
With all that out of the way lets begin moving through the send() verb:
The verb options with an attempt to regular expression match the argstr, the player's command input as a string. If successful the msg and unprocessed recipients strings are broken off from each other and stored. If unsuccessful the msg is presumed to be the entire argstr and an attempt is made to use the send_recip. If successful lr_save is used to hold onto the
real last_recip value. If unsuccessful the last_msg value is still filled with the attempted
send and the verb returns.
At this point 'msg' and 'recips' are filled with text values corresponding to their names. If 'recips' is blank then an attempt is made to send to...
I'll send another letter covering message processing since I am disgusted by the way I've writen $command_mode:send() and I am substantially rewriting it.
Oh, and if you're programming complicated boolean expressions, you might want to look at an
intro to set theory.
--
TamaraCrowe - 01 Oct 2003
to top