DOCUMENTATION TUTORIALS DOWNLOAD NEWS CONTRIBUTE

Developing Statements

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.

Defining the class

A new statement must be a Java class that:

In addition the 4 following optional annotations can be added:

Note: GAMA annotations are classes defined into the msi.gama.precompiler.GamlAnnotations class.

Examples

The write statement

The 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 {

The aspect statement

The 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 {

The action statement

The 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 {

Implementation

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:

Define a SINGLE_STATEMENT statement

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:

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 “”; } ```

Annotations

@symbol

This 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:

@inside

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:

@facets

This annotation describes a list of facets used by a statement in GAML.

This annotation contains:

@facet

This facet describes a facet in a list of facets.

This annotation contains:

@doc

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.

@serializer

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.

@validator

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.