Plastic is a pluggable, flexible, extensible MOOcode parser/compiler. Plastic currently implements all of LambdaMOO's existing language features, with a few slight deviations from and/or extensions to the original syntax.
Plastic is a Top Down Operator Precedence, or TDOP parser, also known as a "Pratt Parser" after Vaughan Pratt, who first described this class of parsers. If you want to learn more about TDOP parsers in general, I recommend Pratt's original paper and all of the following:
The Plastic parser generates a syntax tree from source conforming to the supported grammar. The grammar is a near superset of the LambdaMOO language grammar. Plastic comes with a compiler that translates the syntax tree into plain-old-MOOcode (minus the language enhancements, of course). See the Rationale, below, for the justification for this approach. The examples in the section below illustrate how this works in practice.
Installing Plastic via Composed, the package manager, automatically makes the MOOcode parser/compiler available.
If you invoke the compile()
method on $plastic.compiler
and pass in a list of lines of source, it will transform the Plastic syntax into plain-old-MOOcode. Notice that the missing semicolons are added and end
becomes endif
in the output:
; $plastic.compiler:compile({"if (player.wizard)", "notify(player, 'you are a wizard')", "end"}) => {"if (player.wizard)", "notify(player, \"you are a wizard\");", "endif"}
The compiler is automatically added to the map of external compilers. When programming a verb, the source type is still "application/x-moocode" but the version must be set to the correct version of Plastic syntax (current "1.0.0").
Assuming there is a verb on player
named "test", the following compiles:
@program me:test as application/x-moocode;version=1.0.0 if (player.wizard) player:tell('wizard') end if (player.programmer) player:tell('programmer') end if (player.name != "Bob") player:tell('Your name is not "Bob".') else player:tell('Your name is "Bob".') end .
And runs!
; me:test() wizard programmer Your name is not "Bob".
The original source is available for editing.
@list me:test if (player.wizard) player:tell('wizard') end if (player.programmer) player:tell('programmer') end if (player.name != "Bob") player:tell('Your name is not "Bob".') else player:tell('Your name is "Bob".') end
The in-MOO, MOOcode-to-MOOcode strategy may seem questionable. Why not build it into the server? The Plastic approach has several advantages over in-server parsers:
TDOP is not as widely used or understood as alternative approaches. However, in an experimental, dynamic environment like Stunt/LambdaMOO, a TDOP parser has several advantages:
I will be writing about extending Plastic in the near future.