prev | toc | next

3.1 Overview: MPI

MPI is an interpretted language with a LISP-like syntax available to all players. Because it is universally available, MPI includes some security features that restrict its power. In general, MPI can only read props on the triggering object and on objects controlled by the controller of the object on which the MPI string is stored, and can only set props on the latter... on objects controlled by the owner of the MPI object. Other than setting props as mentioned, it is difficult (but not impossible) to significantly modify the database with MPI, but is ideally suited for message-handling. And because it is interpretted, it is well-suited for one-off programming tasks: no separate compiling and linking operations are needed, nor is a separate program object for holding the code.

MPI's syntax consists of nested functions enlcosed in curly braces that are evaluated left-to-right and `from the inside out', much like mathematical expressions are evaluated outward from the innermost set of parentheses. For example...

    {if:{eq:{ref:me},#1},Hey it's God!,Hello world!}

The MPI parser will first evaluate the innermost function, {ref:me}. The {ref} function returns the dbref of its single argument — which in this case is `me' — so, {ref:me} returns the user's dbref. The returned expression `replaces', as it were, the function. So, if the user's dbref were #123, the MPI string would in effect and at this moment be...

    {if:{eq:#123,#1},Hey it's God!,Hello world!.}

Then the next-innermost expression, effectively {eq:#123,#1}, would be evaluated. The {equals} function returns true if the two arguments supplied are the same; otherwise it returns false. In this case, the two arguments are not the same, so {equals} will return false. At this point, the MPI value for false — the string "0" — will replace the function. (A "" null string is also false in MPI. Any value other than "" or "0" is considered true.) So, at this point the string would in effect be...

    {if:"0",Hey it's God!,Hello world!}

Finally, this, the outermost function will be evaluated. The {if} function takes three arguments. If the first argument is true, it returns the second argument. If the first argument is false, it returns the third argument. In this example, the first argument is false, so the the third argument will be returned: MPI will return the string "Hello world!" to player #123. If God had triggered the string, the {if} test would have been true, and the string "Hey it's God!" would have been returned instead.

The {debug} function displays the progress of the parser. Enclosing the whole of our example in a {debug} function will show the process described above.

> @succ testmpi = {debug:{if:{eq:{ref:me},#1},Hey it's God!,Hello world!}}
  Message set.
> testmpi
  (@Succ) {IF:"{eq:{ref:me},#1}", "Hey it's God!", "Hello world!"}
    (@Succ) {EQ:"{ref:me}", "#1"}
      (@Succ) {REF:"me"}
        (@Succ) "me"
      (@Succ) {REF:"me"} = "#123"
      (@Succ) "#1"
    (@Succ) {EQ:"#123", "#1"} = "0"
    (@Succ) "Hello world!"
  (@Succ) {IF:"{eq:{ref:me},#1}", "Hey it's God!", "Hello world!"} = "Hello world!"
  Hello world!

In the lines from the first half of the debugging output — where indentation is moving to the right — the parser is essentially finding the innermost, left-most function to be evaluated. The remaining portion, with lines ending in ` = <value> ' and indentation moving back to the left, depicts the series of returned expressions described above.

The keywords `me' and `here' can be used as normal. In addition, MPI supports the keyword `this', which will be replaced by the dbref of the object on which the MPI is stored.

The variable functions {&cmd}, {&arg}, and {&how} may be used to retrive information about how MPI was triggered. {&cmd} stores the command name typed to trigger the MPI. {&arg} stores any arguments typed along with the command. {&how} stores the method by which MPI was triggered, and will have values such as (@desc), (@succ), (@osucc), (@lock), etc.

Functions can be nested up to 26 levels deep. Loops may iterate a maximum of 256 times, at which point the automatically exit. Lists may have a maximum of 256 lines, or 4096 characters, whichever is less.

An MPI string that appears in a _/ prop (a @succ message, a @desc, and so forth) will be parsed automatically. For other triggering props, the parser must be called by an & ambersand at the beginning of the prop string.

> @set me=_oarrive/aaa:&{null:{otell:pads in quietly.}}
  Property set.

The arguments of functions are separated by commas. Commas appearing in argument strings will confuse the parser: functions will seem — to it — to have too many arguments. So, commas in argument strings must be `escaped'... i.e., preceded with a \ backslash escape character, which tells the parser to treat the next character literally, rather than as an MPI instruction. For example, if we wanted our first example to say "Hey, it's God!" or "Hello, world!", the commas would need to be escaped with a backslash character.

    {if:{eq:{ref:me},#1},Hey\, it's God!,Hello\, world!}

Complex or very long MPI instructions are often better stored in a list, where whitespace can be used to make the code more readable, rather than in a single prop where all will run together in an opaque mass of characters. A simple pointing string using the {lexec} (`execute list') function can then be placed in the triggering prop.

> lsedit harley = bikecode
  <    Welcome to the list editor. You can get help by entering `.h'     >
  < `.end' will exit and save the list. `.abort' will abort any changes. >
  <    To save changes to the list, and continue editing, use `.save'    >

> {null:
>    {if:
>        {
>        (lots of complicated really cool
            motorcycle code goes here)
>         }
>     }
> }
> .end
  < Editor exited. >
  < list saved. >

> @succ ride harley;ride motorcycle;ride cycle = {lexec:bikecode}
  Message set.

> ride harley
  (The Harley does something amazing.)

The {lexec} function executes MPI in a list. The {exec} function executes MPI in a property, and thus provides another way to break code up into managable pieces. MUSH coders especially might find this method more intuitive.

prev | toc | top | next