rules.html

`rules.grm`

    // FILE. . . . . /home/hak/hlt/src/hlt/language/jaccapps/aql/sources/rules.grm
    // EDIT BY . . . Hassan Ait-Kaci
    // ON MACHINE. . Hp-Dv7
    // STARTED ON. . Thu Oct 18 00:33:22 2012

This file contains the grammar rules the AQL language and the semantic actions associated to them.
Author: |  | Hassan Aït-Kaci
Copyright: |  | © by the author
Version: |  | Last modified on Thu Oct 18 00:40:42 2012 by hak

    /* ************************************************************************************* */
    /* ********************************  GRAMMAR  RULES  *********************************** */
    /* ************************************************************************************* */

    %%

This is the start symbol. It denotes an AQL program; i.e., a possibly empty sequence of $Statement$s.

    Statements_opt
            :

Empty programs are ok.

            |

A sequence of statements makes up an AQL Program.

              Statements_opt Statement
            ;

This is the main compilation unit, an element of the sequence of statements that make up an AQL program. It consists of one of: Pragma statement: ($Pragma$) Extra-language commands for user interaction conveniences such as tracing etc... Definition statement: ($DefinitionStatement$) To define various kinds of terms, types and values. Typing statement: ('$?$') To type an $Expression$ (and display all its most general types). Expression evaluation statement: ($Expression$) To type and evaluate an expression (with possible side effects). Error statement: (error) To enable error recovery à la yacc. Empty statement: ('$;$') Has no effect; simply skipped.

    Statement
    	:

This statement means to en/disable some built-in meta-programming pragmas defining various modes of user interaction (see $Pragma$).

    	  '#' Pragma PragmaArgument_opt
              {
                processPragma($2.svalue().intern(),$3.svalue());
              } EOS
    	|

This statement is used to define shorthands for types, expressions, and values...

    	  DefinitionStatement
    	|

This statement is used to find out all the principal legal types of an expression...

    	  '?' Expression
    	  {
    	    displayAllTypes($2.expression);
    	  } EOS
    	|

This statement first infers/verifies a unique principal type for the given expression, and if such a unique type exists, compiles and evaluates it. Then, AQL prints the result of each expression it evaluates in the form `value : type` (suppressing this result display may be done using the `mute` pragma - see $Pragma$).

    	  Expression
    	  { //hlt.language.tools.Debug.step($1.expression);
    	    if (showTree) currentNode().display();
    	    processExpression($1.expression);
    	  } EOS
    	|

This rule is needed to enable error recovery à la yacc. This is what makes $Statement$ a unit of parsing for AQL: in case of syntax error, AQL's parser ignores everything past the last successfully parsed $Statement$ and up to the next end of statement character: a semicolon ('$;$'- also known as the nonterminal $EOS$, which is used instead of '$;$' in certain rules in order to enable a user prompt action when in interactive mode).

    	  error
    	    {
    	      errorManager().reportErrors(true);
    	    } EOS
    	|

This is the empty statement; it is a no-op in AQL.

    	  ';'
    	;

This non-terminal denotes statements used to define various kinds of terms, types and values. It may be either one of: Explicit definition: ($DefinitionKind$) To define several kinds of shorthands for types, expressions, and values. Implicit type definition: ($StructureOrClassDeclaration$) For declaring structure or class types - both of which amount to a few (type and function value) definitions.

    DefinitionStatement
            : 'define' DefinitionKind EOS
            | StructureOrClassDeclaration
            ;

This non-terminal denotes statements used to declare or define various AQL language concepts: Operator definition: ('$operator$') To define a new, or redefine an existing, operator symbol. Signature definition: ('$signature$') To declare the type of a yet to be defined symbol (an $Operator$).

    DefinitionKind
            :

This defines a new, or redefines an existing, operator symbol. The $SPECIFIER$ is à la Prolog. Indeed, as in Prolog, AQL operators may be declared at runtime using the built-in $operator$ keyword followed by an $Operator$ (the one being [re]defined), a fixity/associativity $SPECIFIER$, and a precedence level: a natural number in the range [1..1200]. For example,
    	             operator + yfx 500;
redefines the symbol `'+'` to be an infix binary left-associative operator with binding looseness 500 (binding looseness is the opposite of precedence - anti-precedence, so to speak).

      	  'operator' Operator SPECIFIER INT
    	  {
    	    processOperator($2.svalue(),$3.svalue(),(int)$4.nvalue());
    	  }
            | 'signature' Operator Typing
    	  {
    	    processType($2.svalue(),$3.type);
    	  }
            | 'type'
              {
    	    setLocation(tokenNode);
    	  }
              'alias' ID
              {
    	    pushTypeParameters();
    	  }
              TypeParameters_opt '=' Type
    	  {
    	    processTypeAlias($4.svalue(),$8.type);
    	    popTypeParameters();
    	  }
            | 'type'
              {
    	    setLocation(tokenNode);
    	  }
              'name' ID
              {
    	    pushTypeParameters();
    	  }
              TypeParameters_opt '=' Type
    	  {
    	    processNewType($4.svalue(),$8.type);
    	    popTypeParameters();
    	  }
            | 'value' Definition
    	  {
    	    if (showTree) currentNode().display();
    	    processEvaluatedDefinition($2.symbol,$2.parameters,$2.types,$2.expression);
    	  }
            | Definition
    	  {
    	    if (showTree) currentNode().display();
    	    processDefinition($1.symbol,$1.parameters,$1.types,$1.expression);
    	  }
            ;

    StructureOrClassDeclaration
            : 'structure' { setLocation(tokenNode); } ID  { pushTypeParameters(); }
              TypeParameters_opt '{' NamedTupleTypeComponents '}'
            {
              processStruct($3.svalue(),$7.fields,$7.types);
              popTypeParameters();
              commitParse();
            }
            | 'class' ID { pushTypeParameters(); } TypeParameters_opt Interface Implementation_opt
            {
              processClass($2.svalue(),$5.symbols,$5.types,$5.expressions,
                           $6.symbols,$6.parameters,$6.types,$6.expressions,
                           new Span($5.getStart(),
                                    $6.symbols == null ? $5.getEnd() : $6.getEnd()));
              popTypeParameters();
              commitParse();
            }
            ;

This node stands for a pragma statement which allows the user to set up some interactive conveniences dynamically using a few built-in extra-language commands of the form `#pragma;` where `pragma` is an identifier. Currently defined pragmas are:
`pragma` | effect
--- | ---
`exit` | exit AQL
`mute` | toggle on/off intermediate displays such as '`value : type`', etc...
`tree` | toggle on/off graphical display of syntax tree
`include` | start reading from the file (name specified as a quoted string)
`time` | toggle on/off execution timing
`gc` | force immediate garbage collection
`syntax` | toggle on/off parser tracing
`typing` | toggle on/off typecheck tracing
`trace` | toggle on/off runtime tracing
`kbd` | toggle on/off compiled code display
`fields` | toggle on/off class fields' code display
`defined` | list all the currently defined symbols
`symbols` | list all the known (built-in and defined) symbols
`types` | list all the registered (declared or not) types
`help` | list this information

    Pragma
            : ID
            ;

    PragmaArgument_opt
            : /* empty */
            | STRING
            ;

This symbol denotes the end of a statement. It recognizes the end of statement character ('$;$') as a statement delimiter and triggers a prompt when AQL is in interactive mode.

    EOS
    	:

This rule must use the same end of statement character as the error handling rule to be consistent with error recovery.

    	  { commitParse(); } ';'
            ;

    Operator
            : ID
            ;

    Typing_opt
            : /* empty */
            { $$.type = new TypeParameter(); }
            | Typing
            { $$.type = $1.type; }
            ;

    Typing
            : ':' Type
            { $$.type = $2.type; }
            ;

    Type_opt
            : /* empty */
            | Type
            { $$.type = $1.type; }
            ;

    Type
            : TypeConstant
            { $$.type = $1.type; }
            | FunctionType
            { $$.type = $1.type; }
            | TupleType
            { $$.type = $1.type; }
            | ArrayType
            { $$.type = $1.type; }
            | CollectionType
            { $$.type = $1.type; }
            | IntRangeType
            { $$.type = $1.type; }
            | RealRangeType
            { $$.type = $1.type; }
            | TypeTerm
            { $$.type = $1.type; }
            | '(' Type_opt ')'
            { $$.type = $2.type == null ? Type.VOID : $2.type; }
            | '[' PrimitiveType ']'
            { $$.type = $2.type.setBoxed(true); }
            | 'forall' { pushTypeParameters(); } TypeParameters '.' Type
            { $$.type = $5.type; popTypeParameters();
            /* Type.resetNames();hlt.language.tools.Debug.step($$.type.toQuantifiedString()); */ }
            ;

    TypeConstant
            : PrimitiveType
            { $$.type = $1.type; }
            | 'string'
            { $$.type = Type.STRING; }
            ;

    PrimitiveType
            : 'void'
            { $$.type = Type.VOID; }
            | 'int'
            { $$.type = Type.INT(); }
            | 'boolean'
            { $$.type = Type.BOOLEAN(); }
            | 'char'
            { $$.type = Type.CHAR(); }
            | 'real'
            { $$.type = Type.REAL(); }
            ;

    FunctionType
            : Type '->' Type
            { $$.type = new FunctionType($1.type,$3.type); }
            | '(' Types_opt ')' '->' Type
    	{ $$.type = new FunctionType($2.types,$5.type); }
            ;

    TupleType
            : '<' TupleTypeComponents '>'
            { $$.type = $2.type; }
            ;

    TupleTypeComponents
            : Types_opt
            { $$.type = TupleType.newTupleType($1.types); }
            | NamedTupleTypeComponents
            { $$.type = new NamedTupleType($1.types,$1.fields); }
            ;

    NamedTupleTypeComponents
            : NamedTupleTypeComponent
            { ($$.types = new ArrayList()).add($1.type); ($$.fields = new ArrayList()).add($1.svalue()); }
            | NamedTupleTypeComponents ',' NamedTupleTypeComponent
            { ($$.types = $1.types).add($3.type); ($$.fields = $1.fields).add($3.svalue()); }
            ;

    NamedTupleTypeComponent
            : ID Typing
            { $$.setSvalue($1.svalue()); $$.type = $2.type; }
            ;

    ArrayType
            : Type '[' IndexType ']'
            { try
                {
                  $$.type = new ArrayType($1.type,$3.type);
                }
              catch (StaticSemanticsErrorException e)
                {
                  errors.add(staticSemanticsError(e.msg(),$$));
                }
            }
            ;

    IndexType
            : IntType_opt
            { $$.type = Type.INT(); }
            | MapIndexType
            { $$.type = $1.type; }
            ;

    IntType_opt
            : /* empty */
            | 'int'
            ;

    MapIndexType
            : SetType
            { $$.type = $1.type; }
            | IntRangeType
            { $$.type = $1.type; }
            ;

    CollectionType
            : SetType
            { $$.type = $1.type; }
            | NonSetKind '{' Type_opt '}'
            { try
                {
    	      switch ($1.kind)
    		{
    		  case Type.BAG:
    		    $$.type = new BagType($3.type == null ? new TypeParameter() : $3.type);
    		    break;
    		  case Type.LIST:
    		    $$.type = new ListType($3.type == null ? new TypeParameter() : $3.type);
    		}
                }
              catch (StaticSemanticsErrorException e)
                {
                  errors.add(staticSemanticsError(e.msg(),$$));
                }
            }
            ;

    CollectionKind
    	: SetKind
            | NonSetKind
    	{ $$.kind = $1.kind; }
    	;

    SetKind
            : 'set'
            ;

    NonSetKind
    	: 'bag'
    	{ $$.kind = Type.BAG; }
    	| 'list'
    	{ $$.kind = Type.LIST; }
    	;

    SetKind_opt
            : /* empty */
            | SetKind
            ;

This denotes a set type of base type $Type_opt$. If the base type is missing, it is set to a type parameter. (NB: the collection kind keyword '$set$' is optional for set types).

    SetType
            : SetKind_opt '{' Type_opt '}'
            { try
                {
    	      $$.type = new SetType($3.type == null ? new TypeParameter() : $3.type);
                }
              catch (StaticSemanticsErrorException e)
                {
                  errors.add(staticSemanticsError(e.msg(),$$));
                }
            }
    	;

    IntRangeType
            : 'int' '..' 'int'
            { $$.type = Type.INT_RANGE; }
            ;

    RealRangeType
            : 'real' '..' 'real'
            { $$.type = Type.REAL_RANGE; }
            ;

    TypeTerm
            : ID
            {
              $$.type = getTypeParameter($1.svalue());
              if ($$.type == null)
                $$.type = tables.getType($1.svalue());
            }
            | ID '(' Types ')'
            {
              try
                {
                  $$.type = tables.getType($1.svalue(),$3.types);
                }
              catch (StaticSemanticsErrorException e)
                {
                  errors.add(staticSemanticsError(e.msg(),$$));
                }
            }
            ;

    Types_opt
            : /* empty */
            { $$.types = new ArrayList(); }
            | Types
            { $$.types = $1.types; }
            ;

    Types
            : Type
            { ($$.types = new ArrayList()).add($1.type); }
            | Types ',' Type
            { ($$.types = $1.types).add($3.type); }
            { $$.undo(); }
            ;

    TypeParameters_opt
            : // empty
            | '(' TypeParameters ')'
            ;

    TypeParameters
            : ID
            { registerTypeParameter($1.svalue()); }
            | TypeParameters ',' ID
            { registerTypeParameter($3.svalue()); }
            ;

    Interface
            : '{' MemberDeclarations_opt '}'
            {
              $$.symbols = $2.symbols;
              $$.types = $2.types;
              $$.expressions = $2.expressions;
            }
            ;

    MemberDeclarations_opt
            : /* empty */
            {
              $$.symbols = new ArrayList();
              $$.types = new ArrayList();
              $$.expressions = new ArrayList();
            }
            | MemberDeclarations_opt MemberDeclaration
            {
              ($$.symbols = $1.symbols).add($2.symbol);
              ($$.types = $1.types).add($2.type);
              ($$.expressions = $1.expressions).add($2.expression);
            }
            { $$.undo(); }
            ;

    MemberDeclaration
            : ID Typing Initialization_opt ';'
            {
              setLocation();
              $$.symbol = $1.svalue();
              $$.type = $2.type;
              $$.expression = $3.expression;
            }
            | 'method' Operator Typing ';'
            {
              setLocation();
              $$.symbol = $2.svalue();
              $$.type = $3.type;
            }
            ;

    Initialization_opt
            : /* empty */
            { $$.expression = Constant.NULL(); }
            | '=' Expression
            { $$.expression = $2.expression; }
            ;

    Implementation_opt
            : /* empty */
            | '{' Definitions_opt '}'
            {
              $$.symbols = $2.symbols;
              $$.parameters = $2.parameters;
              $$.types = $2.types;
              $$.expressions = $2.expressions;
            }
            ;

    Definitions_opt
            : /* empty */
            {
              $$.symbols = new ArrayList();
              $$.parameters = new ArrayList();
              $$.types = new ArrayList();
              $$.expressions = new ArrayList();
            }
            | Definitions_opt Definition ';'
            {
              setLocation();
              ($$.symbols = $1.symbols).add($2.symbol);
              ($$.parameters = $1.parameters).add($2.parameters);
              ($$.types = $1.types).add($2.types);
              ($$.expressions = $1.expressions).add($2.expression);
            }
            { $$.undo(); }
            ;

    Definition
            : Operator FunctionParameters_opt Typing_opt '=' Expression
            {
              $$.symbol = $1.svalue();
              $$.parameters = $2.parameters;
              $$.types = $2.types;
              $$.expression = $5.expression.addType($3.type);
            }
            ;

    FunctionParameters_opt
            : /* empty */
            | FunctionParameters
            {
              $$.parameters = $1.parameters;
              $$.types = $1.types;
            }
            ;

    FunctionParameters
            : '(' Parameters_opt ')'
            {
              $$.parameters = $2.parameters;
              $$.types = $2.types;
            }
            ;

    Parameters_opt
            : /* empty */
            {
              $$.parameters = new ArrayList();
              $$.types = new ArrayList();
            }
            | Parameters
            {
              $$.parameters = $1.parameters;
              $$.types = $1.types;
            }
            ;

    Parameters
            : Parameter
            {
              ($$.parameters = new ArrayList()).add($1.name);
              ($$.types = new ArrayList()).add($1.type);
            }
            | Parameters ',' Parameter
            {
              ($$.parameters = $1.parameters).add($3.name);
              ($$.types = $1.types).add($3.type);
            }
            ;

    Parameter
            : ID Typing_opt
            { $$.name = $1.svalue(); $$.type = $2.type; }
            ;

    Expression_opt
            : /* empty */
            { $$.expression = Constant.VOID; $$.setSvalue("void"); }
            | Expression
            { $$.expression =  $1.expression; }
            ;

This nonterminal node rules express the several possible syntactic forms of an AQL expression: a (possibly typed) untyped expression [see $UntypedExpression$]; an allocation expression [see $Allocation$]; an expression seen as value of a defined opaque type (whose defining type is that of the expression) [see $as$]; an expression of opaque type being seen as a value of its underlying defining type [see %$%] (N.B.: this has the same as using the prefix operator '`strip`'); a parenthesized expression.

    Expression
            : UntypedExpression Typing_opt
            { ($$.expression = $1.expression).addType($2.type); }
            | Allocation
            { $$.expression = $1.expression; }
            | Expression 'as' Type
            { $$.expression = new HideType($1.expression,$3.type); }
            |

The %$% constructs strips the following expression's opaque type into its defining type. This operator associates to the right and may be repeated as long as the defining type is itself opaque.

    	  '$' Expression
            { $$.expression = new OpenType($2.expression); }
            | '(' Expression_opt ')'
            { $$.expression = $2.expression; }
            ;

    Allocation
            : 'new' Type Dimensions_opt
            {
              setLocation($$);
              $$.expression = allocation($2.type,$3.expressions);
            }
            | 'new' Type Dimensions '=' Expression
            {
              setLocation($$);
              $$.expression = ArrayInitializer.construct($2.type,$3.expressions,$5.expression);
            }
            ;

    Dimensions_opt
            : /* empty */
            | Dimensions
            { $$.expressions = $1.expressions; }
            ;

    Dimensions
            : Dimension
            { ($$.expressions = new ArrayList()).add($1.expression);  }
            | Dimensions Dimension
            { ($$.expressions = $1.expressions).add($2.expression);  }
            { $$.undo(); }
            ;

    Dimension
            : '[' UntypedExpression ']'
            { $$.expression = $2.expression; }
            ;

    UntypedExpression
            : Literal
            { $$.expression = $1.expression; }
            | CollectionKind '{' Expressions_opt '}'
    	{ switch ($1.kind)
    		{
    		  case Type.BAG:
    		    $$.expression = makeBag($3.expressions);
    		    break;
    		  case Type.LIST:
    		    $$.expression = makeList($3.expressions);
    		    break;
    		  case Type.SET:
    		  default:
    		    $$.expression = makeSet($3.expressions);
    		}
    	}
            | TupleExpression
            { $$.expression = $1.expression; }
            | Expression '!' Expression
            { $$.expression = new ArrayToMap($1.expression,$3.expression); }
            | '#[' ArrayExtension ']#'
            { $$.expression = new ArrayExtension($2.elements,$2.indices); }
            | ArraySlotExpression
            { $$.expression = $1.expression; }
            | OperatorExpression
            { $$.expression = $1.expression; }
            | 'function' FunctionParameters Expression
            { $$.expression = abs($2.parameters,$2.types,$3.expression); }
            | Expression Arguments
            { $$.expression = app($1.expression,$2.expressions); }
            | 'return' Expression_opt
            { $$.expression = new ExitWithValue($2.svalue() == "void"?Constant.NULL():$2.expression); }
            | 'if' UntypedExpression 'then' Expression 'else' Expression
            { $$.expression = new IfThenElse($2.expression,$4.expression,$6.expression); }
            | 'while' UntypedExpression 'do' Expression
            { $$.expression = new Loop($2.expression,$4.expression); }
            | 'let' Locals 'in' Expression
            { $$.expression = new Let($2.parameters,$2.types,$2.expressions,$4.expression); }
            | Location '=' Expression
            { $$.expression = assignment($1.expression,$1.name,$3.expression); }
            | Expression '.' Member
            { $$.expression = memberapp($1.expression,$3.name,$3.arguments); }
            | Sequence
            { $$.expression = $1.expression; }
            | '(' UntypedExpression ')'
            { $$.expression = $2.expression; }
            | Comprehension
            { $$.expression = $1.expression; }
            | 'foreach' '(' Qualifiers_opt ')' Expression_opt
            { $$.expression = new Comprehension(tables,symbol("noop2"),Constant.VOID,
                                                new Sequence($5.expression,Constant.VOID),
                                                $3.patterns,$3.expressions,
                                                Homomorphism.ENABLED_IN_PLACE).setNoLetWrapping();
            }
            | 'hom' '(' Expression ',' Expression ',' Expression ',' Expression ')'
            { $$.expression = new Homomorphism($3.expression,$5.expression,
                                               $7.expression,$9.expression).disableInPlace();
            }
            ;

    Literal
            : INT
            { $$.expression = new Int((int)$1.nvalue()); }
            | CHAR // should check that there's exactly one character!
            { $$.expression = new Char($1.svalue().charAt(0)); }
            | REAL
            { $$.expression = new Real($1.nvalue()); }
            | STRING
            { $$.expression = new StringConstant($1.svalue()); }
            | 'true'
            { $$.expression = Constant.TRUE(); }
            | 'false'
            { $$.expression = Constant.FALSE(); }
            | 'null'
            { $$.expression = Constant.NULL(); }
            ;

    TupleExpression
            : '<' TupleComponents '>'
            { $$.expression = $2.expression; }
            | TupleProjection
            { $$.expression = $1.expression; }
            ;

    TupleComponents
            : Expressions_opt
            { $$.expression = Tuple.newTuple($1.expressions); }
            | NamedTupleComponents
            { $$.expression = new NamedTuple($1.expressions,$1.fields); }
            ;

    NamedTupleComponents
            : NamedTupleComponent
            { ($$.expressions = new ArrayList()).add($1.expression); ($$.fields = new ArrayList()).add($1.svalue()); }
            | NamedTupleComponents ',' NamedTupleComponent
            { ($$.expressions = $1.expressions).add($3.expression); ($$.fields = $1.fields).add($3.svalue()); }
            ;

    NamedTupleComponent
            : ID ':=' Expression
            { $$.setSvalue($1.svalue()); $$.expression = $3.expression; }
            ;

    TupleProjection
            : UntypedExpression '@' TupleSelector
            { $$.expression = new TupleProjection($1.expression,$3.selector); }
            ;

    TupleSelector
            : INT
            { $$.selector = new Int((int)$1.nvalue()); }
            | ID
            { $$.selector = new StringConstant($1.svalue()); }
            ;

    ArrayExtension
            : Expressions
            { $$.elements = $1.expressions; }
            | IndexedExpressions
            { $$.elements = $1.elements; $$.indices = $1.indices; }
            ;

    IndexedExpressions
            : IndexedExpression
            { ($$.elements = new ArrayList()).add($1.element); ($$.indices = new ArrayList()).add($1.index); }
            | IndexedExpressions ',' IndexedExpression
            { ($$.elements = $1.elements).add($3.element); ($$.indices = $1.indices).add($3.index);  }
            { $$.undo(); }
            ;

    IndexedExpression
            : UntypedExpression ':' Expression
            { $$.index = $1.expression; $$.element = $3.expression; }
            ;

    ArraySlotExpression
            : Expression '[' Expression ']'
            { $$.expression = new ArraySlot($1.expression,$3.expression); }
            ;

    OperatorExpression
            : Operator
            { $$.expression = symbol($1.svalue()); }
            | OPERATOR_ Expression
    	{ if ($1.svalue().equals("strip"))
    	    $$.expression = new OpenType($2.expression);
    	  else
    	    $$.expression = app(locateSymbol($1),$2.expression);
    	}
            | Expression _OPERATOR
            { $$.expression = app(locateSymbol($2),$1.expression); }
            | Expression _OPERATOR_ Expression
            { $$.expression = app(locateSymbol($2),$1.expression,$3.expression); }
            ;

    Arguments
            : '(' Expressions_opt ')'
            { $$.expressions = $2.expressions; }
            ;

    Expressions_opt
            : /* empty */
            { $$.expressions = new ArrayList(); }
            | Expressions
            { $$.expressions = $1.expressions; }
            ;

    Expressions
            : Expression
            { ($$.expressions = new ArrayList()).add($1.expression); }
            | Expressions ',' Expression
            { ($$.expressions = $1.expressions).add($3.expression); }
            { $$.undo(); }
            ;

    Locals
            : Local ';'
            {
              setLocation();
              ($$.parameters = new ArrayList()).add($1.parameter);
              ($$.expressions = new ArrayList()).add($1.expression);
              ($$.types = new ArrayList()).add($1.type);
            }
            | Locals Local ';'
            {
              ($$.parameters = $1.parameters).add($2.parameter);
              ($$.expressions = $1.expressions).add($2.expression);
              ($$.types = $1.types).add($2.type);
            }
            { $$.undo(); }
            ;

    Local
            : Parameter Initialization_opt
            { $$.parameter = $1.name; $$.type = $1.type; $$.expression = $2.expression; }
            ;

    Location
            : ID
            { $$.name = $1.svalue(); }
            | TupleProjection
            { $$.expression = $1.expression; $$.name = ""; }
            | ArraySlotExpression
            { $$.expression = $1.expression; }
            | Expression '.' ID
            { $$.expression = $1.expression; $$.name = $3.svalue(); }
            ;

    Member
            : ID
            { $$.name = $1.svalue(); }
            | Operator Arguments
            { $$.name = $1.svalue(); $$.arguments = $2.expressions; }
            ;

    Sequence
            : '{' ExpressionSequence_opt '}'
            { $$.expression = seq($2.expressions); }
            ;

    ExpressionSequence_opt
            : /* empty */
            { $$.expressions = new ArrayList(); }
            | Expression ';'
            { ($$.expressions = new ArrayList()).add($1.expression); }
            { $$.undo(); }
            | ExpressionSequence_opt Expression ';'
            { ($$.expressions = $1.expressions).add($2.expression); }
            { $$.undo(); }
            ;

    Comprehension
            :  Monoid '{' Expression '|' Qualifiers_opt '}'
            { $$.expression = new Comprehension(tables,$1.operation,$1.identity,$3.expression,
                                                $5.patterns,$5.expressions,(byte)$1.nvalue());
            }
            ;

    Monoid
            : '[' Expression ',' Expression ']' InPlace_opt
            {
              $$.operation = $2.expression;
              $$.identity = $4.expression;
              $$.setSvalue($6.svalue());
            }
            ;

    InPlace_opt
            : /* empty */
            | '<' { $$.setNvalue(Homomorphism.ENABLED_IN_PLACE); }
            | '>' { $$.setNvalue(Homomorphism.DISABLED_IN_PLACE); }
            ;

    Qualifiers_opt
            : /* empty */
            | Qualifiers
            {
              $$.patterns = $1.patterns;
              $$.expressions = $1.expressions;
            }
            ;

    Qualifiers
            : Qualifier
            {
              ($$.patterns = new ArrayList()).add($1.pattern);
              ($$.expressions = new ArrayList()).add($1.expression);
            }
            | Qualifiers ',' Qualifier
            {
              ($$.patterns = $1.patterns).add($3.pattern);
              ($$.expressions = $1.expressions).add($3.expression);
            }
            { $$.undo(); }
            ;

    Qualifier
            : Expression
            { $$.expression = $1.expression; }
            | Expression '<-' Expression
            { $$.pattern = $1.expression; $$.expression = $3.expression; }
            ;

    %%

    /* ************************************************************************************* */
    /* *****************************   END  OF GRAMMAR  RULES   **************************** */
    /* ************************************************************************************* */

This file was generated on Wed Jan 30 13:24:31 CET 2013 from file `rules.grm`
by the `hlt.language.tools.Hilite` Java tool written by Hassan Aït-Kaci