Statements are a fundamental part of GAML, as they represent both commands (imperative programming style) or declarations (declarative programming style). Developing a new statement allows, then, to add a new instruction to GAML.
A new statement must be a Java class that:
IStatement
or extends an existing implementation of this interface (like AbstractStatement
or AbstractSequenceStatement
).In addition the 4 following optional annotations can be added:
@serializer(CustomSerializer.class)
, with a class extending SymbolSerializer
.@validator(CustomValidator.class)
with a class implementing IDescriptionValidator
as value. This class will receive the IDescription
of the statement and be able to execute further validations on the type of expressions, etc. or even to change the IDescription
(by adding new information, changing the value of facets, etc.).Note: GAMA annotations are classes defined into the msi.gama.precompiler.GamlAnnotations
class.
write
statementThe write
statement is an example of a SINGLE_STATEMENT (i.e. statement that does not embed a sequence of statements).
It can used inside a BEHAVIOR statement (i.e. reflex
, init
…), a SEQUENCE_STATEMENT (e.g. loop
, ask
, if
…) or a LAYER statement.
It defines a single facet (“message”) mandatory and omissible.
@symbol(name = IKeyword.WRITE, kind = ISymbolKind.SINGLE_STATEMENT, with_sequence = false)
@inside(kinds = { ISymbolKind.BEHAVIOR, ISymbolKind.SEQUENCE_STATEMENT, ISymbolKind.LAYER })
@facets(value = {
@facet(name = IKeyword.MESSAGE, type = IType.NONE, optional = false)
}, omissible = IKeyword.MESSAGE)
public class WriteStatement extends AbstractStatement {
aspect
statementThe aspect
statement defines an example of BEHAVIOR statement (i.e. a statement that can written at the same level as init
, reflex
…), containing a sequence of embedded statements. It can only be used inside a species
statement (i.e. the definition of a new species) and the global
block. It defines a single facet name
mandatory and omissible.
@symbol(name = { IKeyword.ASPECT }, kind = ISymbolKind.BEHAVIOR, with_sequence = true, unique_name = true)
@inside(kinds = { ISymbolKind.SPECIES, ISymbolKind.MODEL })
@facets(value = { @facet(name = IKeyword.NAME, type = IType.ID, optional = true)
}, omissible = IKeyword.NAME)
public class AspectStatement extends AbstractStatementSequence {
action
statementThe action
statement defines an example of ACTION statement containing a sequence of embedded statements and that can have arguments.
It can be used (to define an action) in any species, experiment or global statement. It defines several facets and uses a custom validator and a custom serializer.
@symbol(name = IKeyword.ACTION, kind = ISymbolKind.ACTION, with_sequence = true, with_args = true, unique_name = true)
@inside(kinds = { ISymbolKind.SPECIES, ISymbolKind.EXPERIMENT, ISymbolKind.MODEL })
@facets(value = {
@facet(name = IKeyword.NAME, type = IType.ID, optional = false),
@facet(name = IKeyword.TYPE, type = IType.TYPE_ID, optional = true, internal = true),
@facet(name = IKeyword.OF, type = IType.TYPE_ID, optional = true, internal = true),
@facet(name = IKeyword.INDEX, type = IType.TYPE_ID, optional = true, internal = true),
@facet(name = IKeyword.VIRTUAL, type = IType.BOOL, optional = true)
}, omissible = IKeyword.NAME)
@validator(ActionValidator.class)
@serializer(ActionSerializer.class)
public class ActionStatement extends AbstractStatementSequenceWithArgs {
All the statements inherits from the abstract class AbstractStatement
. Statements with a sequence of embedded statements inherit from the class AbstractStatementSequence
(which extends AbstractStatement
).
The main methods of a statement class are:
executeOn(final IScope scope)
, it executes the statement on a given scope. This method is executed at each call of the statement in the model,privateExecuteIn(IScope scope)
: the executeOn(final IScope scope)
method implemented in AbstractStatement
does some verification and call the privateExecuteIn(IScope scope)
method to perform the statement. The execution of any statement should be redefined in this method.To define a SINGLE_STATEMENT statement that can be executed in any behavior and sequence of statements and with 2 facets, we first define a new Java class that extends AbstractStatement
such as:
@symbol(name = "testStatement", kind = ISymbolKind.SINGLE_STATEMENT, with_sequence = false)
@inside(kinds = { ISymbolKind.BEHAVIOR, ISymbolKind.SEQUENCE_STATEMENT})
@facets(value = {
@facet(name = IKeyword.NAME, type = IType.NONE, optional = false),
@facet(name = "test_facet", type = IType.NONE, optional = true)
}, omissible = IKeyword.NAME)
public class SingleStatementExample extends AbstractStatement {
The class should at least implement:
getFacet(String)
method) and to store it into an attribute of the class.
```
final IExpression name;public SingleStatementExample(final IDescription desc) { super(desc); name = getFacet(IKeyword.NAME); }
* the **method privateExecuteIn**: this method is executed each time the statement is called in the model.
protected Object privateExecuteIn(IScope scope) throws GamaRuntimeException { IAgent agent = stack.getAgentScope(); String nameStr = null; if ( agent != null && !agent.dead() ) { nameStr = Cast.asString(stack, name.value(stack)); if ( nameStr == null ) { nameStr = “nil”; } GuiUtils.informConsole(nameStr); } return nameStr; }
The variable `scope` of type `IScope` can be used to:
* get the current agent with: `scope.getAgentScope()`
* evaluate an expression in the current scope: `Cast.asString(scope, message.value(scope))`
### Define a statement with sequence
This kind of statements includes SEQUENCE\_STATEMENT (e.g. `if`, `loop`,...), BEHAVIOR (e.g. `reflex`,...)...
Such a statement is defined in a class extending the `AbstractStatementSequence` class, e.g.:
@symbol(name = { IKeyword.REFLEX, IKeyword.INIT }, kind = ISymbolKind.BEHAVIOR, with_sequence = true, unique_name = true) @inside(kinds = { ISymbolKind.SPECIES, ISymbolKind.EXPERIMENT, ISymbolKind.MODEL }) @facets(value = { @facet(name = IKeyword.WHEN, type = IType.BOOL, optional = true), @facet(name = IKeyword.NAME, type = IType.ID, optional = true) }, omissible = IKeyword.NAME) @validator(ValidNameValidator.class)
public class ReflexStatement extends AbstractStatementSequence {
This class should only implement a constructor. The class `AbstractStatementSequence` provides a generic implementation for:
* `privateExecuteIn(IScope scope)`: it executes each embedded statement with the scope.
* `executeOn(final IScope scope)`: it executes the statement with a given scope.
### Additional methods that can implemented
The following methods have a default implementation, but can be overridden if necessary:
* the **`String getTrace(final IScope scope)` method** is called to trace the execution of statements using [trace statement](Statements#trace).
public String getTrace(final IScope scope) { // We dont trace write statements return “”; } ```
setChildren(final List<? extends ISymbol> commands)
is used to define which are the statement children to the sequence statement. By default, all the embedded statements are taken as childrenThis annotation represents a “statement” in GAML, and is used to define its name(s) as well as some meta-data that will be used during the validation process.
This annotation contains:
This annotation is used in conjunction with symbol. Provides a way to tell where this symbol should be located in a model (i.e. what its parents should be). Either direct symbol names (in symbols) or generic symbol kinds can be used.
This annotation contains:
This annotation describes a list of facets used by a statement in GAML.
This annotation contains:
This facet describes a facet in a list of facets.
This annotation contains:
It provides a unified way of attaching documentation to the various GAML elements tagged by the other annotations. The documentation is automatically assembled at compile time and also used at runtime in GAML editors.
It allows to declare a custom serializer for Symbols (statements, var declarations, species ,experiments, etc.). This serializer will be called instead of the standard serializer, superseding this last one. Serializers must be sublasses of the SymbolSerializer class.
It allows to declare a custom validator for Symbols (statements, var declarations, species ,experiments, etc.). This validator, if declared on subclasses of Symbol, will be called after the standard validation is done. The validator must be subclass of IDescriptionValidator.
All these annotations are defined in the GamlAnnotations.java
file of the msi.gama.processor
plug-in.