//TODO add ListLiteral
//TODO ExprTyped:  assign default(none) type

#include "ast.h"
#include "ExternLayer.h"
#include "pass/adhocpass.h"
#include <string>
#include <stack>

#define wprintf(format, ...) \
                char __buffer[100];    \
                wcstombs(__buffer, format, 100);   \
                fprintf(stderr, __buffer, __VA_ARGS__)
                
using namespace std;

COMPILER Xreate

 details::inconsistent::AST* root = nullptr;  // current program unit 
 
 void ensureInitalizedAST(){
   if (root == nullptr) root = new details::inconsistent::AST();
 }
 
 struct {
    std::stack<CodeScope*> scopesOld;
    CodeScope* scope = nullptr;
 } context;
 
 void pushContextScope(CodeScope* scope){
    context.scopesOld.push(context.scope);
    context.scope = scope;
 }
 
 void popContextScope(){
        context.scope = context.scopesOld.top();
        context.scopesOld.pop();
 }
     
int nextToken()
{
  scanner->ResetPeek();
  return scanner->Peek()->kind;
}

bool checkTokenAfterIdent(int key){
  if (la->kind != _ident) return false;
  return  nextToken()  == key;
}

bool checkParametersList()
{
    return la->kind == _ident && nextToken() == _lparen;
}

bool checkInfix()
{
  return la->kind == _ident && nextToken() == _ident;
}

bool checkIndex()
{
  return la->kind == _ident && nextToken()  == _lbrack;
}

bool checkFuncDecl()
{
  if (la->kind != _ident) return false;
  
  int token2 = nextToken();
  int token3 = scanner->Peek()->kind;
  
  return  token2  == _assign && (token3 == _function || token3 == _pre);
}



bool checkAssignment()
{
  if (la->kind != _ident) return false;
  
  scanner->ResetPeek();
  int token2 = scanner->Peek()->kind;
  if (token2 == _lcurbrack) {
      scanner->Peek();
      int token3 = scanner->Peek()->kind;
      if (token3 != _rcurbrack) return false;
      
      int token4 = scanner->Peek()->kind;
      return token4 == _assign;
  }
  
  return  token2  == _assign;
}

void recognizeIdentifier(Expression& i){
    if (!context.scope->recognizeIdentifier(i)){       
        root->postponeIdentifier(context.scope, i);
    }
}

enum SwitchKind{SWITCH_NORMAL, SWITCH_META};

CHARACTERS
  letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".
  any = ANY - '"'.
  digit = "0123456789".
  cr  = '\r'.
  lf  = '\n'.
  tab = '\t'.

TOKENS
  ident = (letter | '_') {letter | digit | '_'}.
  number = (digit | '-' digit) {digit}.
  string = '"' { any } '"'.
  function = "function".
  pre =  "pre".  
  lparen = '('. 
  rparen = ')'.
  lbrack = '['.
  rbrack = ']'.
  lcurbrack = '{'.
  rcurbrack = '}'.
  equal = "==".
  assign = '='.
  implic = '-' '>'.
  colon = ':'.
  context = "context".
  tagcolon   = "::".
  lse = "<=".
  lss = "<".
  gte = ">=".
  gtr = ">".
  
  ne1 = "!=".
  ne2= "<>".
  

COMMENTS FROM "/*" TO "*/" NESTED
COMMENTS FROM "//" TO lf

IGNORE cr + lf + tab

PRODUCTIONS

Xreate =    (. Function* function; ensureInitalizedAST(); .)
{(  RuleDecl 
    | InterfaceData | Imprt | ContextSection | GuardSection
    | IF(checkFuncDecl()) FDecl<function>  (. root->add(function); .)
    | TDecl 
    | SkipModulesSection
)}                                         (.  .)
.

Ident<std::wstring& name>
= ident                                     (. name = t->val; .).

VarIdent<Expression& e>
= ident                                     (. e = Expression(Atom<Identifier_t>(t->val)); .)
  [ lcurbrack (                              
        ident                               (. SemErr(coco_string_create("var version as ident is not implemented yet")); .)
      | number                              (. Attachments::put<versions::VariableVersion>(e, Atom<Number_t>(t->val).get()); .)
  ) rcurbrack ]
.
  

FDecl<Function*& f> =       (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .)
Ident<fname> assign 
[pre            (. flagIsPrefunct = true; .)]
function 		(. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .)

['(' Ident<argName> tagcolon ExprAnnotations<binding>  (. f->addBinding(Atom<Identifier_t>(argName), move(binding)); .)
{',' Ident<argName> tagcolon ExprAnnotations<binding>  (. f->addBinding(Atom <Identifier_t>(argName), move(binding));.)
} ')']

[ tagcolon  
( IF(flagIsPrefunct) FnTag<f>
  |  Type<typOut>
)
{';' FnTag<f> }]
BDecl<entry>    (. const_cast<Expression&>(entry->getBody()).bindType(move(typOut));.)
.

ContextSection<>=                       (. Expression context; Function* f; .)
    "case" "context" tagcolon MetaSimpExpr<context>  
    lcurbrack { FDecl<f>                    (. f->guardContext = context; root->add(f); .)
    } rcurbrack.
    
GuardSection<>=                       (. Expression guard; Function* f; .)
    "guard" tagcolon MetaSimpExpr<guard>  
    lcurbrack { FDecl<f>                    (. f->guard = guard; root->add(f); .)
    } rcurbrack.    

  /**
   *                          TYPES  
   * 
   */
TypeTerm<TypePrimitive& typ> =                       (. std::wstring tid; .)
  ("string" (. typ = TypePrimitive::String;.)
  | "num"   (. typ = TypePrimitive::Num;.)
  | "int"   (. typ = TypePrimitive::Int;.)
  | "float" (. typ = TypePrimitive::Float;.)
  | "bool" (. typ = TypePrimitive::Bool; .)
  | "i8"    (. typ = TypePrimitive::I8; .)
  | "i32"   (. typ = TypePrimitive::I32; .)
  | "i64"   (. typ = TypePrimitive::I64; .)
  ).

Type<TypeAnnotation& typ> =  (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .)
( 
  TList<typ>   
| TStruct<typ>
| TVariant<typ>
| TypeTerm<typ3> (. typ = typ3; .) 
| IF (checkIndex()) Ident<tid> lbrack
      Ident<field>      (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); typ.fields.push_back(Atom<Identifier_t>(field).get()); .)
      {',' Ident<field> (.  typ.fields.push_back(Atom<Identifier_t>(field).get());  .)
      } rbrack
      
| Ident<tid>            (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom<Identifier_t>(tid).get(); .)
    ['(' Type<typ2>     (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .)
    {',' Type<typ2>     (. typ.__operands.push_back(typ2); .)
    } ')']
) .

TList<TypeAnnotation& typ> =            (.      TypeAnnotation ty; .)
    '[' Type<ty> ']'                    (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .)
.

TStruct<TypeAnnotation& typ> = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .)
  lcurbrack
    (
        IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon Type<t> 
        | Type<t>       (. key = to_wstring(keyCounter++); .)
        
    )     (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
    {',' (
        IF(checkTokenAfterIdent(_tagcolon)) Ident<key> tagcolon Type<t> 
        | Type<t>       (. key = to_wstring(keyCounter++); .)
        
        ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom<Identifier_t>(key).get()); .)
    } rcurbrack.
  
TVariant<TypeAnnotation& typ>=  (. TypeAnnotation t, typVoid(TypeOperator::STRUCT, {}); std::vector<TypeAnnotation> operands; std::vector<Atom<Identifier_t>> keys; std::wstring variant; .)
    "variant" lcurbrack
    Ident<variant>              (. t=typVoid; .)        
    [tagcolon Type<t>]          (. keys.push_back(Atom<Identifier_t>(variant)); operands.push_back(t); .)
                          
    {',' Ident<variant>         (. t=typVoid; .)        
    [tagcolon Type<t>]          (. keys.push_back(Atom<Identifier_t>(variant)); operands.push_back(t); .)
    }                           
    rcurbrack                   (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands;  typ.addFields(std::move(keys)); .)
.    

 TDecl =  (. TypeAnnotation t; std::wstring tname, arg; std::vector<Atom<Identifier_t>> args; .)
  Ident<tname> assign "type"
  ['('  Ident<arg>        (. args.push_back(Atom<Identifier_t>(arg));   .)
  {',' Ident<arg>         (. args.push_back(Atom<Identifier_t>(arg));   .)
  } ')']
  Type<t>'.'              (. t.addBindings(move(args)); root->add(move(t), Atom<Identifier_t>(tname)); .)
  .
  
ContextDecl<CodeScope * scope> =        (. Expression tag; .)
context tagcolon 
MetaSimpExpr<tag>                     (. scope->tags.push_back(tag); .)
{';' MetaSimpExpr<tag>                (. scope->tags.push_back(tag); .)
}.

VDecl<CodeScope* f> =                       (. std::wstring vname; Expression var, value;.)
    VarIdent<var> assign ExprTyped<value>   (. Symbol identSymbol = f->addDefinition(move(var), move(value)); 
                                                Attachments::put<SymbolAlias>(value, identSymbol);
                                            .)
.

BDecl<CodeScope* scope> =  lcurbrack      (. Expression body; pushContextScope(scope);  .)
    {(IF(checkAssignment()) VDecl<scope> '.'
    | RuleContextDecl<scope>  
    | ContextDecl<scope>'.'
    | ExprTyped<body>                     (. scope->setBody(body); Attachments::put<SymbolAlias>(body, Symbol{ScopedSymbol::RetSymbol, scope});.)
    )}
    rcurbrack                             (. popContextScope(); .) 
. 

IfDecl<Expression& e> =     (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .)
"if" '(' Expr<cond> ')'                         (. e = Expression(Operator::IF, {cond}); .)
tagcolon ExprAnnotations<e> 
BDecl<&*blockTrue> "else" BDecl<&*blockFalse>   (.  e.addBlock(blockTrue); e.addBlock(blockFalse); .)
.

LoopDecl<Expression& e> = 
  (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl;
    ManagedScpPtr block = root->add(new CodeScope(context.scope)); .)
   "loop"
   ("map" '(' Expr<eIn> implic Ident<varEl>     (. e = Expression(Operator::MAP, {eIn}); .)
    tagcolon ExprAnnotations<tagsEl> ')' tagcolon ExprAnnotations<e> 
        (.
            e.addBindings({Atom<Identifier_t>(varEl)});
            block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl)); 
        .)
    BDecl<&*block>
        (. e.addBlock(block);  .)

  |"fold" 
    ("inf" '(' Expr<eAcc> implic Ident<varAcc> ')' 
        (.
                e = Expression(Operator::FOLD_INF, {eAcc});
                e.addBindings({Atom<Identifier_t>(varAcc)});
                block->addBinding(Atom<Identifier_t>(varAcc), Expression());
        .)        
     tagcolon ExprAnnotations<e> BDecl<&*block>
        (.  e.addBlock(block); .)
  
     | '(' Expr<eIn> implic Ident<varEl> tagcolon ExprAnnotations<tagsEl> ['|' Expr<eFilters> ] ',' Expr<eAcc> implic Ident<varAcc>')'
            (.
                e = Expression(Operator::FOLD, {eIn, eAcc});
                e.addBindings({Atom<Identifier_t>(varEl), Atom<Identifier_t>(varAcc)});
            .)
        tagcolon ExprAnnotations<e> 
            (.  
                block->addBinding(Atom<Identifier_t>(varEl), move(tagsEl));
                block->addBinding(Atom<Identifier_t>(varAcc), Expression());
            .)
        BDecl<&*block>
            (.  e.addBlock(block);             .)
    )
  | "context" '(' string                          (. contextClass = t->val; .)
    ')' BDecl<&*block> 
        (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom<String_t>(std::move(contextClass)))});
            e.addBlock(block);
         .)
).
   
//              Switches   
SwitchDecl<Expression& eSwitch, SwitchKind flagSwitchKind> = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.)
"switch" 
    (
        SwitchVariantDecl<eSwitch>
        | lparen ExprTyped<eCondition> rparen tagcolon  ExprAnnotations<eSwitch>  (. eSwitch.operands.push_back(eCondition);.)
          CaseDecl<eSwitch, flagSwitchKind> {CaseDecl<eSwitch, flagSwitchKind>}
    ) 
.
  
CaseDecl<Expression& outer, SwitchKind flagSwitchKind> = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .)
  "case" 
  ( IF(flagSwitchKind == SWITCH_META)
        lparen MetaSimpExpr<condition> rparen BDecl<&*scope>  (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.)
        
    | "default" BDecl<&*scope>                    (. Expression exprCase(Operator::CASE_DEFAULT, {});       
                                                   exprCase.addBlock(scope); 
                                                   outer.operands.insert(++outer.operands.begin(), exprCase); .)
  
    | lparen CaseParams<&*scope> rparen         (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .)
      BDecl<&*scopeBody>                                (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .)
 ).

CaseParams<CodeScope* scope> =           (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .)
 ExprTyped<condition>                  (. guard.addArg(Expression(condition)); .)
   {',' ExprTyped<condition>             (. guard.addArg(Expression(condition)); .)
   }                                     (. scope->setBody(guard); popContextScope(); .)
.

SwitchVariantDecl<Expression& expr> =                                        
            (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .)
                
    "variant" lparen Expr<varTested> [implic Ident<varAlias>
            (. flagAliasFound = true; .) 
            
    ] [tagcolon ExprAnnotations<varTested>] rparen tagcolon ExprAnnotations<expr>  
            (. expr.addArg(std::move(varTested)); 
                if (flagAliasFound) {
                    expr.addBindings({Atom<Identifier_t>(varAlias)}); 
                    
                } else {
                    if(varTested.__state != Expression::IDENT){
                        SemErr(coco_string_create("Switch variant expects identifier"));
                        
                    }
                    
                    expr.addBindings({Atom<Identifier_t>(string(varTested.getValueString()))});
                }
            .)
                
    CaseVariantDecl<expr> {CaseVariantDecl<expr>}
.    

CaseVariantDecl<Expression& expr> =   (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom<Identifier_t>(string(expr.bindings.front())), Expression()); .)
    "case" lparen Ident<key> rparen   (. expr.addArg(root->recognizeVariantConstructor(Atom<Identifier_t>(std::move(key))));  .)
    BDecl<&*scope>                    (. expr.addBlock(scope); .)
.    
    
IntrinsicDecl<Expression& outer>=        (. std::wstring name; .)
"intrinsic" Ident< name>                 (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom<Identifier_t>(name)); .)
lparen [CalleeParams<outer>] rparen .
  
                              /*============================ INTERFACES ===============================*/
Imprt<> =                           
"import" "raw" lparen string      (. root->__rawImports.push_back(Atom<String_t>(t->val).get()); .) 
rparen '.'.

InterfaceData<> = "interface" '('
  (   "dfa" ')'  InterfaceDFA
    | "extern-c" ')' InterfaceExternC
    | "cfa" ')' InterfaceCFA
    | "adhoc" ')' InterfaceAdhoc
    
  ).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

InterfaceAdhoc<> = 
    '{' { PrefunctionSchemeDecl }  '}'.
     
PrefunctionSchemeDecl<> =         (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .)
    pre function Ident<prefName> tagcolon Type<typReturn>
    lcurbrack SwitchDecl<exprCases, SWITCH_META> rcurbrack
                                  (. Expression prefData(Operator::CALL, {Atom<Identifier_t>(prefName), exprCases}); 
                                     prefData.bindType(typReturn); 
                                     root->addInterfaceData(Adhoc, move(prefData));  
                                  .).    


InterfaceExternC<>  =   (. ExternData data; .)
  '{' {IncludeExternDecl<data> | LibExternDecl<data> } '}'
      (. root->addExternData(move(data));  .)
.

LibExternDecl<ExternData& data> =       (. std::wstring pkgname, libname; .)
  Ident<libname> assign "library" tagcolon "pkgconfig" 
  '(' string            (. pkgname = t->val; .)
  ')' '.'               (. data.addLibrary(Atom<Identifier_t>(libname), Atom<String_t>(pkgname)); .)
. 

IncludeExternDecl<ExternData& data> =   (. Expression inc; .)
  "include" StructLiteral<inc> '.'              (. data.addIncludeDecl(move(inc)); .)
.
  
InterfaceDFA<> = '{' { InstructDecl } '}' .

InstructDecl =                        (.Operator op; Expression tag; 
                                  Expression scheme; 
                                  std::vector<Expression>& tags = scheme.operands; 
                                  tags.push_back(Expression()); /* return value */ .)
"operator" InstructAlias<op> tagcolon '('      (.scheme.setOp(op); .)
[
  MetaSimpExpr<tag>             (. tags.push_back(tag); .)
  {
      ',' MetaSimpExpr<tag>     (. tags.push_back(tag); .)
  }
] ')' [ implic MetaSimpExpr<tag>             (. tags[0] = tag; .) 
      ]                                      (. root->addDFAData(move(scheme)); .)
'.'.

InstructAlias<Operator& op> = 
(
   "map"  (. op = Operator::MAP; .)
  | "list_range" (. op = Operator::LIST_RANGE; .)
  | "list"       (. op = Operator::LIST; .)
  | "fold"       (. op = Operator::FOLD; .)
  | "index"      (. op = Operator::INDEX; .) 
). 


InterfaceCFA<> = '{' { InstructCFADecl } '}' .

InstructCFADecl<> =                          (.Operator op; Expression tag; 
                                                Expression scheme; 
                                                std::vector<Expression>& tags = scheme.operands;  .)

"operator" InstructAlias<op> tagcolon     (. scheme.setOp(op); .)
[
  MetaSimpExpr<tag>             (. tags.push_back(tag); .)
  {
      ',' MetaSimpExpr<tag>     (. tags.push_back(tag); .)
  }
] '.'                           (. root->addInterfaceData(CFA, move(scheme)); .).
    
                              /*============================ METAPROGRAMMING ===============================*/
// TagsDecl<CodeScope* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
// ':' { MetaSimpExpr<tag> (. /*f.addTag(std::move(tag), mod); */ .)
// }.


FnTag<Function* f> = (. Expression tag; TagModifier mod = TagModifier::NONE; .)
MetaSimpExpr<tag>
['-' TagMod<mod>] (. f->addTag(std::move(tag), mod); .).

TagMod<TagModifier& mod> = 
(  "assert" (. mod = TagModifier::ASSERT; .)
 | "require" (. mod = TagModifier::REQUIRE; .)
).
 
RuleDecl<> =
"rule" tagcolon         		(. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .)
'(' Ident<arg> tagcolon Domain<typ>  	(. args.add(arg, typ); .)
{',' Ident<arg> tagcolon Domain<typ>  	(. args.add(arg, typ); .)
} ')'
["case" RGuard<guards> {',' RGuard<guards>}]
'{' RBody<args, guards> '}' .    	

/* - TODO use RGuard for guards-*/
RuleContextDecl<CodeScope* scope> =     (.Expression eHead, eGuards, eBody; .)
"rule" "context" tagcolon MetaSimpExpr<eHead>
"case" lparen MetaSimpExpr<eGuards> rparen
'{' MetaSimpExpr<eBody> '}'             (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .).

Domain<DomainAnnotation& dom> = 
(
  "function"  				(. dom = DomainAnnotation::FUNCTION; .)
  | "variable"    			(. dom = DomainAnnotation::VARIABLE; .)
).

RGuard<RuleGuards& guards>=          (. Expression e; .)
MetaExpr<e>                       (. guards.add(std::move(e)); .).

MetaExpr<Expression& e>=            (.Operator op; Expression e2; .)
MetaExpr2<e>
[MetaOp<op> MetaExpr2<e2>           (. e = Expression(op, {e, e2}); .)
].

MetaExpr2<Expression& e>=
(
'(' MetaExpr<e> ')'
| MetaSimpExpr<e>
).

MetaSimpExpr<Expression& e>=      (. std::wstring i1, infix; Expression e2; .)
( '-' MetaSimpExpr<e2>            (. e = Expression(Operator::NEG, {e2}); .)
| IF(checkParametersList()) Ident<i1>   (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(i1))}); .)
'(' [ MetaCalleeParams<e> ] ')'
| IF(checkInfix()) Ident<i1> Ident<infix> MetaSimpExpr<e2>                                       
                                        (. e = Expression(Operator::CALL, {Expression(Atom<Identifier_t>(infix))});
                                           e.addArg(Expression(Atom<Identifier_t>(i1)));
                                           e.addArg(std::move(e2));
                                        .)
| Ident<i1>                             (. e = Expression(Operator::CALL, {Atom<Identifier_t>(i1)}); .)
).

MetaCalleeParams<Expression& e> = (. Expression e2; .)
  MetaSimpExpr<e2>	     	(. e.addArg(Expression(e2)); .)
  {',' MetaSimpExpr<e2>		(. e.addArg(Expression(e2)); .)
  }.

RBody<const RuleArguments& args, const RuleGuards& guards> =
                                  (. Expression e; std::wstring msg; .)
 "warning" MetaExpr<e> ["message" string (. msg = t->val; .)
]                                 (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom<String_t>(msg))); .)
 .

MetaOp< Operator& op> =
 implic                          (. op = Operator::IMPL; .)
.

        /*============================ Expressions ===============================*/
ExprAnnotations<Expression& e> = (. TypeAnnotation typ; std::list<Expression> tags; Expression tag; e.tags.clear();.)
Type<typ>                    (. e.bindType(move(typ)); .)
  {';' MetaSimpExpr<tag>     (. tags.push_back(tag); .)
  }                          (. e.addTags(tags); .)
.
  
ExprTyped<Expression&e> = Expr<e> [tagcolon ExprAnnotations<e>].

Expr< Expression& e>         (. Operator op; Expression e2; .)
= ExprArithmAdd<e>		 
  [ RelOp<op>
    ExprArithmAdd<e2>      (. e = Expression(op, {e, e2});  .)
  ].

ExprArithmAdd< Expression& e>=      (. Operator op; Expression e2; .)
  ExprArithmMul< e>
  [ AddOp< op>
    ExprArithmAdd< e2>         (. e = Expression(op, {e, e2});.)
  ].

ExprArithmMul< Expression& e>         (. Operator op; Expression e2; .)
= ExprPostfix< e>
  [ MulOp< op>
    ExprArithmMul< e2>        (. e = Expression(op, {e, e2}); .)
  ].

ExprPostfix<Expression& e> 
= Term<e> 
  [                                  (. e = Expression(Operator::INDEX, {e}); .)
    {lbrack CalleeParams<e> rbrack }
  ].


Term< Expression& e>       (. std::wstring name; e = Expression(); .)
=                        
  (IF (checkParametersList()) Ident< name> 
                                    (. e = Expression(Operator::CALL, {Atom<Identifier_t>(name)}); root->recognizeVariantConstructor(e); .)
  '(' [CalleeParams<e>] ')'
  | VarIdent<e>                     (. recognizeIdentifier(e); .)
  | ListLiteral<e>                  (. /* tuple */.)    
  | StructLiteral<e>                (. /* struct */.)
  | LoopDecl<e>
  | IfDecl<e>   
  | SwitchDecl<e, SWITCH_NORMAL>
  | AdhocDecl<e>
  | IntrinsicDecl<e>
  | number                          (. e = Expression(Atom<Number_t>(t->val)); .)
  | string                          (. e = Expression(Atom<String_t>(t->val)); .)
  | "true"                          (. e = Expression(Atom<Number_t>(1)); e.bindType(TypePrimitive::Bool); .)
  | "false"                         (. e = Expression(Atom<Number_t>(0)); e.bindType(TypePrimitive::Bool); .)
  | '-' Term<e>                     (. e = Expression(Operator::NEG, {e}); .)
  | '(' ExprTyped<e> ')'  
  ).
  
StructLiteral<Expression& e> =                     (. std::wstring key; Expression val; std::list<Atom<Identifier_t>> keys; size_t keyCounter=0; .)
  lcurbrack 
        (IF(checkTokenAfterIdent(_assign)) Ident<key> '=' Expr<val>
        | Expr<val>                                (. key = to_wstring(keyCounter++); .)
        )                                          (. keys.push_back(Atom<Identifier_t>(key)); e = Expression(Operator::LIST_NAMED, {val}); .)
  {',' (IF(checkTokenAfterIdent(_assign)) Ident<key> '=' Expr<val>
        | Expr<val>                                (. key = to_wstring(keyCounter++); .)
       )                                           (. e.addArg(Expression(val)); keys.push_back(Atom<Identifier_t>(key)); .)
  } rcurbrack                                      (. e.addBindings(keys.begin(), keys.end()); .)
  .
  
ListLiteral<Expression& e> =  (. Expression eFrom, eTo; .)
'['                                                             
[ Expr<eFrom>                                                   (. e.addArg(Expression(eFrom)); .)
(".."  Expr<eTo>                                                (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .)
 |{',' Expr<eFrom>                                              (. e.addArg(Expression(eFrom)); .)
}                                                               (. e.setOp(Operator::LIST); .) 
) ] ']'.

AdhocDecl<Expression& e> = (. Expression command; .)
"ad" "hoc" MetaSimpExpr<command>       (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .).

CalleeParams<Expression& e> = (. Expression e2; .)
  ExprTyped<e2>		(. e.addArg(Expression(e2)); .)
  {',' ExprTyped<e2> 		(. e.addArg(Expression(e2)); .)
  }.

AddOp< Operator& op>
=                        (. op = Operator::ADD; .)
  ( '+'
  | '-'                  (. op = Operator::SUB; .)
  ).

MulOp< Operator& op>
=                        (. op = Operator::MUL; .)
  ( '*'
  | '/'                  (. op = Operator::DIV; .)
  ).

RelOp< Operator& op>
=                         (. op = Operator::EQU; .)
  ( equal
  | (ne1 | ne2)           (. op = Operator::NE; .)
  
  | lse                   (. op = Operator::LSE; .)
  | lss                   (. op = Operator::LSS; .)
  
  | gte                   (. op = Operator::GTE; .)
  | gtr                   (. op = Operator::GTR; .)
  
  ).
  
SkipModulesSection = "module" '{' {ANY} '}'.  
  
END Xreate.
