Script represents a state transition of an agent in coordination
protocols. It is based on an extended finite state machine. Each state
machine is defined using the macro define-script
, and each state
in the state machine (or script) is defined using the
define-script-state
macro. State transition rules are associated
with a state, and they are defined using define-script-state
when
a state is defined. In addition, a named state transition rule can be
defined using the define-script-rule
macro. This type of rule is
associated with a script, and can be used by including the name of a
rule in :rules
option of the script-state definition.
A script is executed by dynamically changing active message patterns. In other words, a state in a script is implemented as a set of message patterns to be active when the transition to that state occurs. Thus, a script definition is basically a set of message patterns and their associated message handlers.
In order to use a script facility, the class of an agent should be
script-agent
or its subclass.
Macro: define-script script-name lambda-list { script-options }*
script-name ::= symbol script-options ::=:initial-state
initial-state-name |:script-vars
( { script-var | ( script-var initial-value) }*) |:inherits-from
script-name |:initial-active-states
state-name-list |:on-entry
rule-lisp-form |:documentation
doc-string
The script named script-name is defined. lambda-list
specifies the arguments for run-script
function. lambda-list has the same syntax as the lambda list of
Common Lisp (i.e. &optional
, &key
, &rest
are
allowed.) Variables appeared in lambda-list are treated as
script-vars, and bound to the arguments passed to the
run-script
function.
:script-vars
defines additional script variables. When
initial-value is specified, initial-value is evaluated when
a script is invoked. In initial-value, script variables appeared
in lambda-list can be used using script variable access macro
$
. Otherwise the initial value of a script variable is
nil
. :inherits-from
specifies the script from which
script definitions such as script states, script variables,
script-functions are inherited. If on-entry is specified,
on-entry is executed before the state transition to the initial
state occurs. Inside on-entry, call-super
can be used to
call the on-entry function of a super script.
:initial-state
option specifies the initial state. Note that
initial-state-name is evaluated.
As an experimental feature, multiple states can be activated
simultaneously. The state transition rules in active states are also
checked during the script execution. :initial-active-states
option specifies the states which are to be made active initially.
Example:
(define-script cnet-manager (task) :initial-state 'start :script-vars (bid-queue contract-id))
Note:
nil
is not allowed as a script name.
Macro: define-script-rule (rule-name script-name) &key script-vars-used rule documentation
This macro defines a state transition rule named rule-name which
is local to script script-name. Script variables declared in
:script-vars-used
option can be accessed inside rule
without using $
macro.
rule ::= (:when
condition:do
action) condition ::= [ msg-condition | timeout-condition ] script-var-condition | msg-condition | timeout-condition msg-condition ::= (msg
rule-message-pattern) timeout-condition ::= (timeout
timeout) script-var-condition ::= (test
rule-lisp-form) rule-message-pattern ::= message-class [ sender ] { slot-name rule-pattern-value }* slot-name ::= keyword timeout ::= rule-lisp-form action ::= { rule-action-lisp-form }*
The syntax of rule-message-pattern is same as that of the
message-pattern used in define-message-pattern
macro except
the followings.
"*"
is specified.
Timeout should be evaluated to a number, and the timeout condition
is satisfied after timeout seconds elapsed after the state
transition to this state occurs. rule-lisp-form is same as
lisp form except that the two rule macros ($
for accessing
script variables and !
for invoking script/agent functions) are
available. Similarly in rule-lisp-action-form, in addition to
$
and !
macros, goto-state
, invoke-script
and exit-script
macros are also available.
Macro: define-script-state (state-name script-name) { script-state-options }*
script-state-options ::=:script-vars-used
({ script-var }*) |:on-entry
rule-lisp-form |:rules
({ rule-spec }*) |:priority
number |:documentation
doc-string
This macro defines a state named state-name of a script named
script-name. Script variables declared in :script-vars-used
option can be accessed inside :on-entry
as well as inside
rule-spec. When :on-entry
is defined, :on-entry
rule-lisp-form is called when the state transition to this state
occurs. :rules
options defines transition rules at this
state.
rule-spec ::= rule | (:named
rule-name [:here
])
A state transition rule can be defined as rule, which is local to
this state. In addition, a state transition rule defined using
define-script-rule
can be specified using :name
designation. :here
specifies how an inheritance of named rule is
handled. Suppose that Script SubScript
which inherits Script
SuperScript
is defined. Suppose also that both scripts defines a
rule named Rule1
, and Script SuperScript
defines State
State1
, which is inherited in Script SubScript
. In Script
SubScript
, a rule designated as (:name Rule1)
defined in
State State1
refers to the rule named Rule1
defined in
Script SubScript
. However, a rule designated as (:name
Rule1 : here)
defined in State State1
refers to the rule named
Rule1
defined in Script SuperScript
, not SubScript
.
Note that the definition of State State1
is inherited from
SuperScript
.
:priority
specifies the priority of this state. This value is
used to choose a rule to be fired when multiple states are active at the
same time. The rule in the state with a higher priority has precedence.
Note:
nil
is not allowed as a state name.
Examples:
(define-script-state (start cnet-manager) :script-vars-used (task contract-id) :on-entry (progn (setf contract-id (! announce-task task)) (goto-state 'announced))) (define-script-state (announced cnet-manager) :script-vars-used (task bid-queue contract-id) :rules ((:when (msg bid :contract-id !contract-id) :do (if (! send-award-immediately-if-possible msg bid-queue) (goto-state 'success) (push msg bid-queue))) (:when (timeout (task-expiration task)) :do (if (! send-award-if-possible bid-queue) (goto-state 'success) (goto-state 'failure))))) (define-script-state (success cnet-manager) :on-entry (exit-script t)) (define-script-state (failure cnet-manager) :on-entry (exit-script nil))
Function: remove-script-state script-name state-name
This function removes a state state-name from a script script-name. Note that state transition rules associated with this state are also removed.
Generic Function: run-script agent script-name &rest args
Primary Method: run-script (agent script-agent
) script-name &rest args
This function invokes the script script-name. The arguments should match the lambda-list of the script script-name. The function returns a newly created context (see section Script Execution Context).
Note: This function can only invoke a toplevel script (i.e. no parent context exists). When a script is to be invoked inside a transition rule, use
invoke-script
instead.
When a script is invoked, a context is created. The context holds the various information regarding a script execution. The following macros are defined to access the context information. The default value of context is a current context.
Macro: current-state &optional context
current-state
returns a name of a current state. If the script
is exited, nil
is returned.
Macro: exited-state &optional context
exited-state
returns a name of the state when the script is
exited. If the script is not exited, nil
is returned.
Macro: parent-context &optional context
parent-context
returns a parent context. If context is
toplevel, nil
is returned.
Macro: child-contexts &optional context
child-contexts
returns a list of child contexts.
The following macros can be used inside a rule definition.
Rule Macro: $ script-var-name &optional context
This macro is used to access a script variable script-var-name.
setf
can be used with this $
macro.
Rule Macro: ! function-name &rest args
The agent function function-name is invoked with arguments specified by args. When such an agent function does not exist, a script function with the same name is searched for. If it is found, that script function is invoked instead. If there are no agent function nor script function is defined, an error is signaled.
The following macros can be used only inside rule-action-lisp-form.
Rule Action: goto-state state-name &optional context
This macro causes the state transition to the state state-name to occur.
Rule Action: invoke-script script-name &rest args
The script script-name is invoked with arguments given by args. The newly created context of an invoked script is considered as a child context of the current context. This action returns a newly created context.
Rule Action: call-script script-name &rest args
The script script-name is invoked with arguments given by
args. Whereas invoke-script
does not suspend the execution
of a caller script, call-script
does not return until the invoked
script executes the exit-script
rule action. The return value of
call-script
is the value of result argument given to
exit-script
.
Rule Action: exit-script &optional result context
The execution of a current script is exited. Internally, the script
execution context is deleted if there is no child context of
context. If there is a child context still executing, the context
is deleted only after all the child contexts are deleted (by exiting
each child script). The default value of result is nil
.
The agent function interface is provided to customize the script
behavior for a particular agent. When an agent/script function is
called (by a rule macro !
), an agent function (function local to
an agent which invoked the script) with the same name is searched for
first. If it is found, this agent function is called. If not, the
script function is called. Thus, the script function defines a default
behavior of a script.
You can change the behavior of a script either by defining a new script inheriting the original script and defining script functions, or by defining an agent function for a particular agent.
Macro: define-agent-function (function-name agent-name) lambda-list { rule-form }*
The agent function function-name is defined for the agent agent-name.
Macro: define-script-function (function-name script-name) lambda-list { rule-form }*
The script function function-name is defined for the script script-name.
Macro: with-script-vars ({ script-var }*) { rule-form }+
Script variable script-var can be accessed without $
macro
in rule-form. The with-script-vars
macro can be used in
define-agent-function
, define-script-function
, and
transition rule definitions.
Function: call-super &rest args
This function can be used inside the definition of
define-script-function
to call the script function defined in the
super script. If args is not given, the original arguments are
passed to the super script function as the case with
call-next-method
in CLOS.
Generic Function: remove-agent-function agent-or-name function-name
Primary Method: remove-agent-function (agent script-agent
) function-name
Primary Method: remove-agent-function (agent-name symbol
) function-name
This method removes the agent function function-name defined in agent or defined in the agent agent-name.
Function: remove-script-function script-name function-name
This function removes the script function function-name from the script script-name.