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 Fri Oct 19 10:29:59 PDT 2012 from file rules.grm
by the hlt.language.tools.Hilite Java tool written by Hassan Aït-Kaci