E_MOO Programmer's Manual
November 1997 -- ThwartedEfforts <e_moo@thwartedefforts.org>
This document was recovered out of the archive. It has not been updated, and since E_MOO is down, all of the external links are broken.
E_CORE version 1
Document version 0.0.1
Introduction
to be written
Package Creation and Distribution
to be written
The In-Database Parser
One of E_MOO's nicest features is the command parser. Implemented
entirely in the database, it adds new dimensions to programming and using
command line interfaces in a manner that is more natural for both the programmer
and the user. The motivation for designing and writing the parser
were:
-
Many verbs include code to parse the value of argstr themselves
in order to support an argument style that doesn't fit in the direct
object, preposition, indirect object specification. By allowing
for an unlimited number of arguments and an expandable list of argument
types, the parsing of these kinds of commands could be standardized, and
duplicate code in the database could be reduced.
-
Every verb has it's own method of telling the user that the command they
entered may be invalid. This is because many of the commands have
any any any as arguments, and must do parsing themselves internally.
Using the parser, we can customize the printing of help for the commands
entered, and offer useful help messages for all commands, not just those
which have internal support for providing help.
-
Support a more free-form specification of arguments, to support other languages
which do not fit well into the server's use of hard coded english prepositions
Unlike in-server parsing, the parser makes a distinction between the name
and arguments of a command, and the code which is executed when a match
is found. The name and arguments are called the command, and
the code is called the method. The server treats the command
and method as one unit, called a verb. The parser treats each separately,
and while they are dependent on each other, there does not have to be a
one-to-one relationship. E_CORE has commands which allow manipulation
of both independently, and the method which is called upon successful parsing
of a command can be changed at any time.
Technically, a method is a verb, but it's a verb that can not be called
from the command line because it has the arguments none none this.
Any verb which has none none this arguments is a command method,
and any verb with this none this as arguments is a utility method.
This is not strictly enforced, but is a convention used to distinguish
between the different types of methods and verbs.
Also similar to the server's verb handling, both command names and methods
can have aliases. A command's name is a string of space separated
words, each word being an alias for the command. The names can have
asterisks in them to signify that the part after the asterisk is optional.
If the asterisk comes at the end of the word, then anything that starts
with the part before the asterisk is acceptable as an alias.
Once the parser finds a command and argument match for the entered string,
it will call that command's associated command method, but only
if all the arguments are successfully match. The first completely
successful match will be be taken, and partial argument matches (unless
otherwise noted) will not be successful command matches. For example,
<obj> only matches valid objects, if $nothing is entered,
it is a failed match.
Arguments
The parser supports a number of different kinds of command arguments, and
an unlimited number of arguments can be specified per command. The
different kinds of arguments are
static arguments
match static strings. These replace the prepositions which are
needed under server parsing.
variable arguments
match a specific kind of strings, such as the name of an object, or
property reference.
regular expressions arguments
use the MOO built-in function match()
to find complex strings in the input string.
optional arguments
a cross between a regular expression and a static string, these are
converted to regular expressions that match the empty string
modifier arguments
can change how the arguments around them are parsed.
Static arguments are just regular MOO literal strings, and replace
the meaning of the prepositions which are used in server parsing.
They can not (in general) start or end with < and >,
%( and %), or [ and ].
Variable arguments are surrounded by < and >.
Each one will match a specific kind of string or condition. E_CORE
comes with 30 different variable arguments.
<any>
Matches any string, except the empty string
<none>
Matches only the empty string. This is necessary when you have
a command that takes no arguments
<verbref>
<methodref>
Matches an object reference followed by a colon, followed by a string.
<propref>
Matches an object reference followed by a period, followed by a string.
<num>
Matches a literal number.
<range>
Matches a range of numbers, such as 1-4, or "from 4 to
8"
<str>
Matches a quote enclosed string.
<this>
Matches an object reference that is the object that defines the command.
Similar to the server verb argument this.
<player>
Matches the name of a player.
<coreref>
Matches core and local core objects; objects that are the values of
properties on $sys or $local, prefixed with $
or &.
<obj>
Matches an object reference.
<objnum>
Matches a literal object number.
<keyexp>
Matches a key expression used to lock objects (see help
locking).
<any|none>
Matches any string or the empty string. Similar to the server
verb argument any.
<player|me>
Matches a player if a string is entered, but defaults to the player
who entered the command if the empty string is found.
<obj|player>
Matches an object reference, if that fails to find a match, then will
match against player names.
<list>
Matches a comma separated list of strings.
<mailrecip>
Matches a mail recipient, words that are prefixed by an asterisk.
<mailrecip|none>
Matches like <mailrecip>, but will default to the user's
current mail folder if the empty string is entered.
<value>
<prep>
<duration>
<word>
Matches a single word. Unlike <any>, will not match
a series of words delimited by whitespace.
<emailaddr>
Matches an Internet email address, such as abakun@scinc.com.
<unmatchable>
Will always return a failed match. This can be useful in conjunction
with the * command flag.
<trymatch>
Will attempt to match a string to an object, but a failed object match
is a valid argument match.
<obj:contents>
Will only match object references which are directly contained within
the player
<obj:visible>
Will only match object references which are in sight of the player
<eval>
<eval> can be used to evaluate arbitrary code to determine
dynamicly if a command matches.
<$generic>
<&generic>
Match only object references which are descendants of the named generic.
For example, <$container> will only match objects which have
$container as one of their ancestors.
Regular expression arguments use the match()
built-in function. Any regular
expression is acceptable. This is most commonly used where a
choice of possible static arguments would be a possibility.
For example, the @create
command could be used both as:
@create $note named love letter
@create $note called love letter
The third argument to the @create command could be the regular
expression:
You can specify a static string as optional using optional arguments.
These are static strings enclosed in square brackets. These can be
used in commands like walk, which might have the following arguments:
The string to is optional, both the following commands are acceptable
matches, assuming that "living room" names a valid room:
walk to living room
walk living room
The last kind of arguments are modifier arguments. These arguments
change or limit the way the other arguments around them are matched.
Currently, the only modifier argument is ..., the continuation
argument. This argument means to keep trying to match the argument
that comes before it. For example
Will match one or more objects in series without separators, such as:
$sys $room $thing
~tef ~eru here
satchel tale of two cities boots
Each one lists three objects. The continuation argument can follow any
of the variable arguments or a regular expression argument.
It can not follow a static argument or be at the start of the arguments.
Here are some examples of commands and their arguments:
@recreate <obj> as <obj> %(named%|called%) <any>
ha*nd <this> to <player>
@lock <obj> with <keyexp>
@gethelp <any> from <$help> ...
p*ut <obj> %(inside%|into%|in%) <this>
@kill %(%%[0-9]+%)
@method <methodref> [command|utility|cmd|util] <player|me>
Note that you can have multiple commands named the same that, when successfully
parsed, can invoke different command methods. You can also have multiple
commands with different arguments that invoke the same method.
Nothing is perfect, including the in-db parser. As such, there
are a number of techniques that can be used to assist the parser, so it
will produce reliable results. For example, because the continuation
argument continues eating up words, you can give a hint where to stop
by putting a static argument right after it. For example,
the arguments:
most likely will always match the empty string as the last argument
(returning the object number of the player who typed the command), and
if a player is entered, it will be consumed by the continuation argument
and be grouped with the other matches for <obj>. While
this is an allowed series of arguments, it will not produce the required
or expected result.
Another thing to remember is that MOO regular expressions match the
longest possible substring, and may match more of the input string than
you want. It is acceptable (and can result in a speed increase) to
define multiple commands using static arguments, rather than one command
with a regular expression argument. Remember that multiple commands
can point to the same method. It may be wise to use:
<obj> named <any>
<obj> called <any>
rather than
<obj> %(named%|called%) <any>
The reason for this is because the parser uses the static arguments as
pivots to divide the input string to sections. More static arguments
means fewer ambiguities in how arguments should be matched. The former
two argument lists divide the input into two sections, with one argument
per section. The latter tries to match three arguments to one section.
Command Flags
Just like verbs and methods, commands can have flags which change their
behavior or their permissions. There are two kinds of flags, permission
flags and execution flags. Permission flags determine
what kind of objects and users should have the command in their scope of
commands to search. Execution flags change the way a command is matched
or how it's associated method is called.
The @chmod
command is used to alter the flags of a command, the same way it would
be done for methods or properties.
The permission flags that the parser supports are:
o
only the owner(s) of the object on which the command is defined may
use this command
w
only players who have their .wizard bit set can use this command
p
only programmers can use this command
t
this command is not passed onto descendants, only usable on the defining
object
d
only the defining object and its descendants can use this command
The two execution flags are:
f
the call the to the command's method will be forked off in order to
give it the full count of ticks and seconds
*
ignore bad argument matches and call the command's method anyway; is
only considered if no good matches for the entered arguments were found
These flags can be extended at any time, depending on the needs of your
database. For example, say there were a series of commands which
were only allowed to be executed, using a MUD example, while the user's
experience was above 20. In that case, you'd define a new command
flag and code it so it would check the experience level of the user, and
reject the command if the condition was not met. (There are other
ways to do this also; a cleaner method would be to use command
packages).
User Interface
Commands exist on $prog to manlipulate commands and methods
A LambdaCore compatible @verb command exists for adding
command and utility methods, along with server parsed verbs, to objects
using a method that LambdaCore programmers are familar with.
E_MOO also has a @method
command which follows the command and utility method convention.
Since methods are verbs, but the verb arguments don't matter to us, the
@method command allows you to specify which of the two types of
methods you want to add to an object. The arguments to the @method
command are:
@method <methodref> [command|utility|cmd|util] <player|me>
Where the <methodref> is an object and a method name seperated
by a colon. Using the second argument, you can specify if you want
the new method to be a command or a utility method. Remember that
command methods have the server verb arguments none none this, and
utility methods have the server verb arguments this none this.
If left off, it defaults to adding a command method. The last argument
specifies who should own the new method. Only wizards can specify
a user other than themselves.
To add a command to an object, you use the @command
command. It takes a <cmdref> and a series of arguments
to assign to the command. A commmand reference is an object and a
command name seperated by a vertical bar or pipe (|). If
a method reference appears in parenthesis right after the command reference,
then that assigns the method that will be called when this command is successfully
parsed. Note that this does not add the method to the object, it
just disignates it. If left off, it defaults to the command name
prefixed by the string "do_".
@command me|dance with <player>
Adds a command named dance to the user's object, which will
call :do_dance on the user's object.
@command here|smash (:figgle) <obj>
Adds a command named smash to the user's current location
with one argument, <obj>. Will call :figgle
on the location if matched.
@command $thing|take <this>
Adds a take command to $thing, which will call :do_take.
The @chmethod command is used to change which method is associated
with a command.
@chmethod <cmdref> [to] <methodref>
@chmethod me|dance to :do_lambada
Note that wizards (and other programmer's, depending on the security level
implemented in the parser) can specify objects other than ones they own
or the command's defining object to call a method on. When an object
is left out before the colon in the above method references, that means
call it on the object that the command was matched on.
The @args
command is used to change the arguments for a command. This will
most likely also require a change to the method code to honor the change
in arguments. It works just like the LambdaCore @args works
on methods, except you could also specify
a command reference to change the arguments of.
Using the Parser
The parser makes it easier to write and handle commands which take arguments
that are more complex than the normal direct object, preposition, indirect
object style.
In the same way the server provides information about the parsed command
through the use of the built-in variables dobj, dobjstr,
iobj, iobjstr etc, the parser makes information avaiable
via the object $env.
You can get this information through calling methods on $env.
-
$env:args()
-
Returns the values of the resolved arguments for the command
-
$env:verb()
-
Returns the first word on the command line. This is the word that invoked
the command.
-
$env:argstr()
-
Returns the value of argstr, that is, without the verb. Thus tostr($env:verb(),
" ", $env:argstr()) returns the entire string the user entered.
-
$env:argmatch()
-
Returns a list of strings, where each string matched it's associated argument.
-
$env:arglist()
-
Returns the list of arguments that were used to match.
-
$env:start_time()
-
Returns an integer representing the time when the parser started parsing
the command line.
-
$env:this()
-
Returns the object that the command that was matched to was found on.
-
$env:method()
-
Returns a two element list, the object and the name of the method that
was called after the command was matched.
-
$env:perms()
-
Returns the flags/permissions of the command that was matched.
-
$env:player()
-
The object number of the user who typed the command.
Lists of these values can also be requested at once using $env:get,
which takes a list of strings as its arguments and returns a list.
That is:
{argstr, argmatch, method} = $env:get("argstr", "argmatch", "method");
would assign to the variables argstr, argmatch, and method,
just like:
argstr = $env:argstr();
argmatch = $env:argmatch();
method = $env:method();
Note that the value of args contains the resolved arguments. If the
matched command was:
dance with <player>
dance with ThwartedEfforts
And the command was on the room, #1234, then here would be the
result of some of the values returned from $env:
-
:args
-
{"with", #2}
-
:verb
-
{"with", "ThwartedEfforts"}
-
:argstr
-
"with ThwartedEfforts"
-
:argmatch
-
{"with", "ThwartedEfforts"}
-
:arglist
-
{"with", "<player>"}
Programming Interface
to be written
Command Packages
to be written
Coding Style
to be written
$object
to be written
Multiple Ownership
to be written
Object Matching
to be written
Blocked Methods
to be written
Datatypes, Frobs
to be written
The Trust/Distrust System
to be written
HTML Rendering
to be written
E_WEB
to be written
Events and Event Dispatching
to be written
Compatiblity with Other Cores
to be written
Required Server Changes
to be written
History of E_MOO
to be written
E_CORE Contributors
to be written