PlexiLisp Tutorial¶
See the Programming in Plexilisp chapter
for an introduction to Plexilisp. Before we continue, it’s assumed you
are using Emacs on a Unix-like system, and that you have checked out the
latest plexil_exec
module from SVN.
Emacs Setup¶
In order to have Plexilisp automatically compiled (when needed) and
loaded every time you start Emacs, the file
plexil/src/plexilisp/emacs.el
should be automatically loaded. This
file depends on the Unix environment variable PLEXIL_HOME
to find
things, so it must be set prior to loading the file. The easiest way to
make all this happen is to insert the following two lines into your
.emacs
file. (If you don’t have a .emacs
file, create one in
your home directory):
(setenv "PLEXIL_HOME" "/home/fred/plexil")
(load (concat (getenv "PLEXIL_HOME") "/src/plexilisp/emacs.el"))
Of course, please edit the pathname /home/fred/plexil
as needed.
Using the full pathname of your plexil
directory, and not the ~/
shortcut for your home directory, may be necessary, as the tilde
character is not always handled correctly in this context.
First Example¶
We’re now ready to get our feet wet. Open the file
plexilisp/examples/simple-assignment.pli
, which looks like this:
(plexil-plan
(assignment-node "SimpleAssignment"
(variables (integer "foo" 0))
(assignment (intvar "foo") 3)))
This is a trivial single-node PLEXIL plan that is just an assignment
node. It declares an integer variable named foo
and assigns 3 to it.
You might notice that this looks like Lisp. However, it is not Lisp, and
it is impossible to invoke any Lisp though Plexilisp. If you prefer, you
may use the Capitalized and “CamelCase
” variants of all the
Plexilisp constructs. Look at the file SimpleAssignment.pli
:
(PlexilPlan
(AssignmentNode "SimpleAssignment"
(Variables (Integer "foo" 0))
(Assignment (IntegerVariable "foo") 3)))
It differs only in the typecase of the Plexilisp identifiers, and is functionally equivalent to the first plan.
Compiling Plexilisp¶
Now, let’s generate some PLEXIL XML. Put your cursor in either of the
buffers you created above, and either type ‘’’M-x plexil
’’’ or
‘’’Control-C Control-C’’’ (the latter is a shortcut for the former).
Plexilisp goes through a two-step “compilation” process. The first
generates an Extended PLEXIL file, which has a
file extension of .epx
. The second step compiles the Extended PLEXIL
into Core PLEXIL, creating a .plx
file. Buffers for both these files
will be appear in your Emacs.
In this case a new buffer named simple-assignment.plx
(or
SimpleAssignment.plx
) should appear, after a brief delay. Directly
“underneath” this buffer will be one for the .epx
file. The Core
PLEXIL buffer should contain XML code that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by PlexiLisp -->
<PlexilPlan>
<Node NodeType="Assignment">
<NodeId>SimpleAssignment</NodeId>
<VariableDeclarations>
<DeclareInteger>
<IntegerVariable>foo</IntegerVariable>
<IntegerValue>0</IntegerValue>
</DeclareInteger>
</VariableDeclarations>
<NodeBody>
<Assignment>
<IntegerVariable>foo</IntegerVariable>
<NumericRHS>
<IntegerValue>3</IntegerValue>
</NumericRHS>
</Assignment>
</NodeBody>
</Node>
</PlexilPlan>
Simulation Script¶
If you’d like to run this plan with the PLEXIL Test Executive, you’ll
need a simulation script. Since this plan does not interact with an
external world, an empty script will do. We can create scripts with
Plexilisp as well. There’s an empty script in your examples
directory. Open one of empty-script.pli
or EmptyScript.pli
,
whichever looks prettier to you.
(plexil-script
(script))
Type M-x plexil
(or type ‘’’Control-C Control-C’’’) again, which
should give you the .plx
version of the file:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by PlexiLisp -->
<PLEXILScript>
<Script></Script>
</PLEXILScript>
More Examples¶
We’ll look at one more example plan, the “simple drive” plan that has
two equivalent versions in the examples
directory:
(PlexilPlan
(ListNode "SimpleDrive"
(EndCondition (NodeFinished "TakeSample"))
(PostCondition (NodeSuccessful "TakeSample"))
(List
(CommandNode "Drive"
(Precondition (= (LookupNow "At" "Rock") false))
(RepeatCondition (= false (LookupOnChange "At" "Rock")))
(Command "drive" 1.0))
(CommandNode "TakeSample"
(StartCondition (NodeFinished "Drive"))
(InvariantCondition (= true (LookupOnChange "At" "Rock")))
(Command "takeSample")))))
(plexil-plan
(list-node "SimpleDrive"
(end-condition (node-finished "TakeSample"))
(postcondition (node-successful "TakeSample"))
(list
(command-node "Drive"
(precondition (= (lookup-now "At" "Rock") false))
(repeat-condition (= false (lookup-on-change "At" "Rock")))
(command "drive" 1.0))
(command-node "TakeSample"
(start-condition (node-finished "Drive"))
(invariant-condition (= true (lookup-on-change "At" "Rock")))
(command "takeSample")))))
This plan translates into about 100 lines of PLEXIL XML, so we won’t
show that here. But try it yourself! The corresponding simulation script
is found in simple-drive-script.pli
/SimpleDriveScript.pli
:
(PlexilScript
(InitialState
(State "At" "bool" 0 (Param "Rock")))
(Script
(State "At" "bool" 1 (Param "Rock"))
(CommandAck "drive" "bool" 1 (Param 1.0 "real"))
(CommandAck "takeSample" "bool" 1)))
Its translation is:
<?xml version="1.0" encoding="utf-8"?>
<!-- Generated by PlexiLisp -->
<PLEXILScript>
<InitialState>
<State name="At" type="bool">
<Param>Rock</Param>
<Value>0</Value>
</State>
</InitialState>
<Script>
<State name="At" type="bool">
<Param>Rock</Param>
<Value>1</Value>
</State>
<CommandAck name="drive" type="bool">
<Param type="real">1.0</Param>
<Result>1</Result>
</CommandAck>
<CommandAck name="takeSample" type="bool">
<Result>1</Result>
</CommandAck>
</Script>
</PLEXILScript>
A substantial Plexilisp plan example is found in examples/3209.pli
.
This is the actual ISS Procedure 3.209 that runs with the
ISS-In-A-Box
simulator.
For a comprehensive look at Plexilisp, see the Plexilisp Reference Manual.