%{

//#define YYDEBUG

/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!                                                                           !!
!!         ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION       !!
!!                                                                           !!
!!                 DO NOT CHANGE THIS FILE (CqlParser.cs) BY HAND!!!!        !!
!!                          YOU HAVE BEEN WARNED !!!!                        !!
!!                                                                           !!
!!         ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION       !!
!!                                                                           !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

using System;
using System.Data.Common.EntitySql.AST;
using System.Data.Entity;

/*//////////////////////////////////////////////////////////////////////////////

 This pragma is needed since symbols used for defining precedence are not always
 code generated by yacc

///////////////////////////////////////////////////////////////////////////////*/
#pragma warning disable 414

%}

%token IDENTIFIER, ESCAPED_IDENTIFIER
%token PARAMETER, LITERAL

//
// Keywords
//
%token ALL, AND, ANYELEMENT, APPLY, AS, ASC
%token BETWEEN, BY
%token CASE, CAST, COLLATE, COLLECTION, CROSS, CREATEREF
%token DEREF, DESC, DISTINCT
%token ELEMENT, ELSE, END, EXCEPT, EXISTS, ESCAPE
%token FLATTEN, FROM, FULL, FUNCTION
%token GROUP, GROUPPARTITION
%token HAVING
%token IN, INNER, INTERSECT, IS
%token JOIN
%token KEY
%token LEFT, LIKE, LIMIT
%token MULTISET
%token NAVIGATE NOT NULL
%token OF, OFTYPE, ON, OR, ORDER, OUTER, OVERLAPS, ONLY
%token QMARK
%token REF, RELATIONSHIP, RIGHT, ROW
%token SELECT, SET, SKIP
%token THEN, TOP, TREAT
%token UNION, USING
%token VALUE
%token WHEN, WHERE, WITH

//
// Punctuators & Operators
//
%token COMMA, COLON, SCOLON, DOT, EQUAL
%token L_PAREN, R_PAREN, L_BRACE, R_BRACE, L_CURLY, R_CURLY
%token PLUS, MINUS
%token STAR, FSLASH, PERCENT
%token NOT, AND, OR
%token OP_EQ, OP_NEQ, OP_LT, OP_LE, OP_GT, OP_GE

//
// Precedence (increasing in the order of declaration)
//
%left OR
%left AND 
%right NOT
%nonassoc BETWEEN
%nonassoc IS  
%nonassoc IN
%nonassoc LIKE
%nonassoc ESCAPE
%left OVERLAPS
%left EXCEPT
%left UNION ALL
%left INTERSECT
%nonassoc OP_EQ EQUAL OP_NEQ
%nonassoc OP_GT OP_LT OP_GE OP_LE
%left PLUS MINUS
%left STAR FSLASH PERCENT
%right UNARYPLUS UNARYMINUS
%left DOT
%nonassoc LEFT RIGHT CROSS OUTER INNER FULL
%left APPLY JOIN
%left ON
%nonassoc AS

%start commandStart

%%

commandStart        : /* e */
                    {
                        $$ = _parsedTree = null;
                    }
                    | command
                    {
                        $$ = _parsedTree = (Node)$1;
                    }
                    ;

command             : optNamespaceImportList queryStatement
                    {
                        $$ = new Command(ToNodeList<NamespaceImport>($1),(Statement)$2);
                        SetErrCtx(AstNode($$), ($1 != null) ? AstNodePos($1) : AstNodePos($2), EntityRes.CtxCommandExpression);
                    }
                    ;

//~~~~~~~~~~~~~~
// Prolog
//~~~~~~~~~~~~~~

optNamespaceImportList: /* e */
                    {
                        $$ = null;
                    }
                    | namespaceImportList
                    {
                        $$ = $1;
                    }
                    ;

namespaceImportList : namespaceImport
                    {
                        $$ = new NodeList<NamespaceImport>((NamespaceImport)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxNamespaceImportList);
                    }
                    | namespaceImportList namespaceImport
                    {
                        $$ = ToNodeList<NamespaceImport>($1).Add((NamespaceImport)$2);
                    }
                    ;

namespaceImport     : USING identifier SCOLON
                    {
                        $$ = new NamespaceImport((Identifier)$2);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNamespaceImport);
                    }
                    | USING dotExpr SCOLON
                    {
                        $$ = new NamespaceImport((DotExpr)$2);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNamespaceImport);
                    }
                    | USING assignExpr SCOLON
                    {
                        $$ = new NamespaceImport((BuiltInExpr)$2);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxAliasedNamespaceImport);
                    }
                    ;

//~~~~~~~~~~~~~~~~
// Query statement
//~~~~~~~~~~~~~~~~

queryStatement      : optQueryDefList generalExpr optSemiColon
                    {
                        $$ = new QueryStatement(ToNodeList<AST.FunctionDefinition>($1),(Node)$2);
                        SetErrCtx(AstNode($$), ($1 != null) ? AstNodePos($1) : AstNodePos($2), EntityRes.CtxQueryStatement);
                    }
                    ;

//~~~~~~~~~~~~~~~~~~~~~~~~
// Query inline defintions
//~~~~~~~~~~~~~~~~~~~~~~~~

optQueryDefList:    /* e */
                    {
                        $$ = null;
                    }
                    | functionDefList
                    {
                        $$ = $1;
                    }
                    ;

functionDefList     : functionDef
                    {
                        $$ = new NodeList<AST.FunctionDefinition>((AST.FunctionDefinition)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | functionDefList functionDef
                    {
                        $$ = ToNodeList<AST.FunctionDefinition>($1).Add((AST.FunctionDefinition)$2);
                        SetErrCtx(AstNode($$), AstNodePos($$), AstNode($2).ErrCtx.ErrorContextInfo);
                    }
                    ;

functionDef         : FUNCTION identifier functionParamsDef AS L_PAREN generalExpr R_PAREN
                    {
                        $$ = new AST.FunctionDefinition((Identifier)$2, ToNodeList<PropDefinition>($3), (Node)$6, Terminal($1).IPos, Terminal($7).IPos);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxFunctionDefinition);
                    }
                    ;
                    
functionParamsDef   : L_PAREN /* e */ R_PAREN
                    {
                        $$ = null;
                    }
                    | L_PAREN functionParamDefList R_PAREN
                    {
                        $$ = $2;
                    }
                    ;

functionParamDefList : functionParamDef
                    {
                        $$ = new NodeList<PropDefinition>((PropDefinition)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | functionParamDefList COMMA functionParamDef
                    {
                        $$ = ToNodeList<PropDefinition>($1).Add((PropDefinition)$3);
                        SetErrCtx(AstNode($$), AstNodePos($$), AstNode($3).ErrCtx.ErrorContextInfo);
                    }
                    ;

functionParamDef    : identifier typeDef
                    {
                        $$ = new PropDefinition((Identifier)$1, (Node)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxFunctionDefinition);
                    }
                    ;

//~~~~~~~~~~~~~~
// General Expr
//~~~~~~~~~~~~~~

generalExpr         : queryExpr
                    {
                        $$ = $1;
                    }
                    | Expr
                    {
                        $$ = $1;
                    }
                    ;

optSemiColon        : /* e */
                    {
                        $$ = null;
                    }
                    | SCOLON
                    {
                        $$ = null;
                    }
                    ;

//~~~~~~~~~~~~~~
// Query Expr
//~~~~~~~~~~~~~~

queryExpr           : selectClause fromClause optWhereClause optGroupByClause optHavingClause optOrderByClause
                    {
                         $$ = new QueryExpr( (SelectClause)$1    ,
                                             (FromClause)$2      ,
                                             (Node)$3            ,
                                             (GroupByClause)$4   ,
                                             (HavingClause)$5    ,
                                             (OrderByClause)$6   );

                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxQueryExpression);
                    }
                    ;

selectClause        : SELECT 
                      { 
                          StartMethodExprCounting();
                      } 
                      optAllOrDistinct 
                      optTopClause 
                      aliasExprList
                    {
                        $$ = new SelectClause(ToNodeList<AliasedExpr>($5), SelectKind.Row, (DistinctKind)$3, (Node)$4, EndMethodExprCounting());
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxSelectRowClause);
                    }
                    | SELECT 
                      { 
                        StartMethodExprCounting();
                      } 
                      VALUE 
                      optAllOrDistinct 
                      optTopClause 
                      aliasExprList
                    {
                        $$ = new SelectClause(ToNodeList<AliasedExpr>($6), SelectKind.Value, (DistinctKind)$4, (Node)$5, EndMethodExprCounting());
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxSelectValueClause);
                    }
                    ;

optAllOrDistinct    : /* e */
                    {
                        $$ = DistinctKind.None;
                    }
                    | ALL
                    {
                        $$ = DistinctKind.All;
                    }
                    | DISTINCT
                    {
                        $$ = DistinctKind.Distinct;
                    }
                    ;

optTopClause        : /* e */
                    {
                        $$ = null;
                    }
                    | TOP L_PAREN generalExpr R_PAREN
                    {
                        $$ = $3;
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxTopSubClause);
                    }
                    ;

fromClause          : FROM fromClauseList
                    {
                        $$ = new FromClause(ToNodeList<FromClauseItem>($2));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxFromClause);
                    }
                    ;

fromClauseList      : fromClauseItem
                    {
                        $$ = new NodeList<FromClauseItem>((FromClauseItem)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | fromClauseList COMMA fromClauseItem
                    {
                        $$ = ToNodeList<FromClauseItem>($1).Add((FromClauseItem)$3);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxFromClauseList);
                    }
                    ;

fromClauseItem      : aliasExpr
                    {
                        $$ = new FromClauseItem((AliasedExpr)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxFromClauseItem);
                    }
                    | L_PAREN joinClauseItem R_PAREN
                    {
                        $$ = new FromClauseItem((JoinClauseItem)$2);
                        SetErrCtx(AstNode($$), AstNodePos($2), EntityRes.CtxFromJoinClause);
                    }
                    | joinClauseItem
                    {
                        $$ = new FromClauseItem((JoinClauseItem)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxFromJoinClause);
                    }
                    | L_PAREN applyClauseItem R_PAREN
                    {
                        $$ = new FromClauseItem((ApplyClauseItem)$2);
                        SetErrCtx(AstNode($$), AstNodePos($2), EntityRes.CtxFromApplyClause);
                    }
                    | applyClauseItem
                    {
                        $$ = new FromClauseItem((ApplyClauseItem)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxFromApplyClause);
                    }
                    ;

joinClauseItem      : fromClauseItem joinType fromClauseItem %prec JOIN
                    {
                        $$ = new JoinClauseItem((FromClauseItem)$1, (FromClauseItem)$3, (JoinKind)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxJoinClause);
                    }
                    | fromClauseItem joinType fromClauseItem ON Expr %prec ON
                    {
                        $$ = new JoinClauseItem((FromClauseItem)$1, (FromClauseItem)$3, (JoinKind)$2, (Node)$5);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxJoinOnClause);
                    }
                    ;

applyClauseItem     : fromClauseItem applyType fromClauseItem %prec APPLY
                    {
                        $$ = new ApplyClauseItem((FromClauseItem)$1, (FromClauseItem)$3, (ApplyKind)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxApplyClause);
                    }
                    ;

joinType            : CROSS JOIN
                    {
                        $$ = JoinKind.Cross;
                    }
                    | LEFT OUTER JOIN
                    {
                        $$ = JoinKind.LeftOuter;
                    }
                    | LEFT JOIN
                    {
                        $$ = JoinKind.LeftOuter;
                    }
                    | RIGHT OUTER JOIN
                    {
                        $$ = JoinKind.RightOuter;
                    }
                    | RIGHT JOIN
                    {
                        $$ = JoinKind.RightOuter;
                    }
                    | JOIN
                    {
                        $$ = JoinKind.Inner;
                    }
                    | INNER JOIN
                    {
                        $$ = JoinKind.Inner;
                    }
                    | FULL JOIN
                    {
                        $$ = JoinKind.FullOuter;
                    }
                    | FULL OUTER JOIN
                    {
                        $$ = JoinKind.FullOuter;
                    }
                    | FULL OUTER
                    {
                        $$ = JoinKind.FullOuter;
                    }
                    ;

applyType           : CROSS APPLY
                    {
                        $$ = ApplyKind.Cross;
                    }
                    | OUTER APPLY
                    {
                        $$ = ApplyKind.Outer;
                    };

optWhereClause      : /* e */
                    {
                        $$ = null;
                    }
                    | whereClause
                    {
                        $$ = $1;
                    }
                    ;

whereClause         : WHERE Expr
                    {
                        $$ = (Node)$2;
                        SetErrCtx(AstNode($$), AstNodePos($2), EntityRes.CtxWhereClause);
                    }
                    ;

optGroupByClause    : /* e */
                    {
                        $$ = null;
                    }
                    | groupByClause
                    {
                        $$ = $1;
                    }
                    ;

groupByClause       : GROUP BY aliasExprList
                    {
                        $$ = new GroupByClause(ToNodeList<AliasedExpr>($3));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxGroupByClause);
                    }
                    ;

optHavingClause     : /* e */
                    {
                        $$ = null;
                    }
                    | havingClause
                    {
                        $$ = $1;
                    }
                    ;

havingClause        : HAVING 
                    { 
                      StartMethodExprCounting();
                    } 
                    Expr
                    {
                        $$ = new HavingClause((Node)$3, EndMethodExprCounting());
                        SetErrCtx(AstNode($$), AstNodePos($3), EntityRes.CtxHavingClause);
                    }
                    ;

optOrderByClause    : /* e */
                    {
                        $$ = null;
                    }
                    | orderByClause
                    {
                        $$ = $1;
                    }
                    ;

orderByClause       : ORDER BY 
                      {
                        StartMethodExprCounting();
                      }
                      orderByItemList 
                      optSkipSubClause 
                      optLimitSubClause
                    {
                        $$ = new OrderByClause(ToNodeList<OrderByClauseItem>($4), (Node)$5, (Node)$6, EndMethodExprCounting());
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxOrderByClauseItem);
                    }
                    ;

optSkipSubClause    : /* e */
                    {
                        $$ = null;
                    }
                    | SKIP Expr
                    {
                        $$ = $2;
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxSkipSubClause);
                    }
                    ;

optLimitSubClause   : /* e */
                    {
                        $$ = null;
                    }
                    | LIMIT Expr
                    {
                        $$ = $2;
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxLimitSubClause);
                    }
                    ;

orderByItemList     : orderByClauseItem
                    {
                        $$ = new NodeList<OrderByClauseItem>((OrderByClauseItem)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | orderByItemList COMMA orderByClauseItem
                    {
                        $$ = ToNodeList<OrderByClauseItem>($1).Add((OrderByClauseItem)$3);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxOrderByClause);
                    }
                    ;

orderByClauseItem   : Expr optAscDesc
                    {
                        $$ = new OrderByClauseItem((Node)$1, (OrderKind)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxOrderByClauseItem);
                    }
                    | Expr COLLATE simpleIdentifier optAscDesc
                    {
                        $$ = new OrderByClauseItem((Node)$1, (OrderKind)$4, (Identifier)$3);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxCollatedOrderByClauseItem);
                    }
                    ;

optAscDesc          : /* e */
                    {
                        $$ = OrderKind.None;
                    }
                    | ASC
                    {
                        $$ = OrderKind.Asc;
                    }
                    | DESC
                    {
                        $$ = OrderKind.Desc;
                    };

//~~~~~~~~~~~~~~~~~~~~~
// Expressions
//~~~~~~~~~~~~~~~~~~~~~

exprList            : Expr
                    {
                        $$ = new NodeList<Node>((Node)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | exprList COMMA Expr
                    {
                        $$ = ToNodeList<Node>($1).Add((Node)$3);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxExpressionList);
                    }
                    ;

Expr                : parenExpr
                    {
                        $$ = $1;
                    }
                    | PARAMETER
                    {
                        $$ = (QueryParameter)$1;
                    }
                    | identifier
                    {
                        $$ = (Identifier)$1;
                    }
                    | builtInExpr
                    {
                        $$ = $1;
                    }
                    | dotExpr
                    {
                        $$ = $1;
                    }
                    | refExpr
                    {
                        $$ = $1;
                    }
                    | createRefExpr
                    {
                        $$ = $1;
                    }
                    | keyExpr
                    {
                        $$ = $1;
                    }
                    | groupPartitionExpr
                    {
                        $$ = $1;
                        IncrementMethodExprCount();
                    }
                    | methodExpr
                    {
                        $$ = $1;
                        IncrementMethodExprCount();
                    }
                    | ctorExpr
                    {
                        $$ = $1;
                    }
                    | derefExpr
                    {
                        $$ = $1;
                    }
                    | navigateExpr
                    {
                        $$ = $1;
                    }
                    | literalExpr
                    {
                        $$ = $1;
                    }
                    ;

parenExpr           : L_PAREN generalExpr R_PAREN
                    {
                        $$ = new ParenExpr((Node)$2);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxParen);
                    }
                    ;

betweenPrefix       : Expr BETWEEN Expr %prec BETWEEN
                    {
                        $$ = new NodeList<Node>((Node)$1).Add((Node)$3);
                    }
                    ;

notBetweenPrefix    : Expr NOT BETWEEN Expr %prec BETWEEN
                    {
                        $$ = new NodeList<Node>((Node)$1).Add((Node)$4);
                    }
                    ;

builtInExpr         //
                    // Arithmetic
                    //
                    : Expr PLUS Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Plus, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxPlus);
                    }
                    | Expr MINUS Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Minus, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxMinus);
                    }
                    | Expr STAR Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Multiply, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxMultiply);
                    }
                    | Expr FSLASH Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Divide, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxDivide);
                    }
                    | Expr PERCENT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Modulus, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxModulus);
                    }
                    | MINUS Expr %prec UNARYMINUS
                    {
                        Literal literal = $2 as Literal;
                        if ( literal != null && literal.IsNumber && !literal.IsSignedNumber )
                        {
                            literal.PrefixSign(Terminal($1).Token);
                            $$ = $2;
                        }
                        else
                        {
                            $$ = new BuiltInExpr(BuiltInKind.UnaryMinus, Terminal($1).Token, (Node)$2);
                            SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxUnaryMinus);
                        }

                    }
                    | PLUS Expr %prec UNARYPLUS
                    {
                        Literal literal = $2 as Literal;
                        if ( null != literal && literal.IsNumber && !literal.IsSignedNumber )
                        {
                            literal.PrefixSign(Terminal($1).Token);
                            $$ = $2;
                        }
                        else
                        {
                            $$ = new BuiltInExpr(BuiltInKind.UnaryPlus, Terminal($1).Token, (Node)$2);
                            SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxUnaryPlus);
                        }
                    }
                    //
                    // Comparison
                    //
                    | Expr OP_NEQ Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.NotEqual, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxNotEqual);
                    }
                    | Expr OP_GT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.GreaterThan, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxGreaterThan);
                    }
                    | Expr OP_GE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.GreaterEqual, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxGreaterThanEqual);
                    }
                    | Expr OP_LT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.LessThan, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxLessThan);
                    }
                    | Expr OP_LE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.LessEqual, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxLessThanEqual);
                    }
                    //
                    // Set & Multiset Operations
                    //
                    | Expr INTERSECT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Intersect, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIntersect);
                    }
                    | Expr UNION Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Union, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxUnion);
                    }
                    | Expr UNION ALL Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.UnionAll, Terminal($2).Token, (Node)$1, (Node)$4);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxUnionAll);
                    }
                    | Expr EXCEPT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Except, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxExcept);
                    }
                    | Expr OVERLAPS Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Overlaps, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxOverlaps);
                    }
                    | Expr IN Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.In, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIn);
                    }
                    | Expr NOT IN Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.NotIn, Terminal($2).Token, (Node)$1, (Node)$4);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxNotIn);
                    }
                    | EXISTS L_PAREN generalExpr R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Exists, Terminal($1).Token, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxExists);
                    }
                    | ANYELEMENT L_PAREN generalExpr R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.AnyElement, Terminal($1).Token, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxAnyElement);
                    }
                    | ELEMENT L_PAREN generalExpr R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Element, Terminal($1).Token, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxElement);
                    }
                    | FLATTEN L_PAREN generalExpr R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Flatten, Terminal($1).Token, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxFlatten);
                    }
                    | SET L_PAREN generalExpr R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Distinct, Terminal($1).Token, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxSet);
                    }
                    //
                    // Nullability Test Ops
                    //
                    | Expr IS NULL
                    {
                        $$ = new BuiltInExpr(BuiltInKind.IsNull, "IsNull", (Node)$1);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsNull);
                    }
                    | Expr IS NOT NULL
                    {
                        $$ = new BuiltInExpr(BuiltInKind.IsNotNull, "IsNotNull", (Node)$1);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsNotNull);
                    }
                    //
                    // Case When Then Expr
                    //
                    | searchedCaseExpr
                    {
                        $$ = (CaseExpr)$1;
                    }
                    //
                    // Type Ops
                    //
                    | TREAT L_PAREN Expr AS typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Treat, Terminal($1).Token, (Node)$3, (Node)$5);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxTreat);
                    }
                    | CAST L_PAREN Expr AS typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Cast, Terminal($1).Token, (Node)$3, (Node)$5);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCast);
                    }

                    //
                    // OFTYPE(e, [ONLY] T)
                    //
                    | OFTYPE L_PAREN Expr COMMA typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.OfType, 
                                             Terminal($1).Token, 
                                             (Node)$3, 
                                             (Node)$5,
                                             Literal.NewBooleanLiteral( false ) /* only */);
                                             
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxOfType);
                    }
                    | OFTYPE L_PAREN Expr COMMA ONLY typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(BuiltInKind.OfType, 
                                             "OFTYPE ONLY", 
                                             (Node)$3, 
                                             (Node)$6,
                                             Literal.NewBooleanLiteral( true ) /* only */);
                                             
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxOfTypeOnly);
                    }
                    //
                    // IS [NOT] OF ( [ONLY] T )
                    //
                    | Expr IS OF L_PAREN typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(   BuiltInKind.IsOf,
                                                "IS OF",
                                                (Node)$1,
                                                (Node)$5,
                                                Literal.NewBooleanLiteral( false ), /* only */
                                                Literal.NewBooleanLiteral( false )  /* not  */
                                            );

                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsOf);
                    }
                    | Expr IS NOT OF L_PAREN typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(   BuiltInKind.IsOf,
                                                "IS NOT OF",
                                                (Node)$1,  /* instance */
                                                (Node)$6,  /* type */
                                                Literal.NewBooleanLiteral( false ), /* only */
                                                Literal.NewBooleanLiteral( true  )  /* not  */
                                            );

                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsNotOf);
                    }
                    | Expr IS OF L_PAREN ONLY typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(   BuiltInKind.IsOf,
                                                "IS OF ONLY",
                                                (Node)$1,  /* instance */
                                                (Node)$6,  /* type */
                                                Literal.NewBooleanLiteral( true  ), /* only */
                                                Literal.NewBooleanLiteral( false )  /* not  */
                                            );

                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsOf);
                    }
                    | Expr IS NOT OF L_PAREN ONLY typeName R_PAREN
                    {
                        $$ = new BuiltInExpr(   BuiltInKind.IsOf,
                                                "IS NOT OF ONLY",
                                                (Node)$1,  /* instance */
                                                (Node)$7,  /* type */
                                                Literal.NewBooleanLiteral( true ), /* only */
                                                Literal.NewBooleanLiteral( true )  /* not  */
                                            );

                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxIsNotOf);
                    }
                    //
                    // Like
                    //
                    | Expr LIKE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Like, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxLike);
                    }
                    | Expr NOT LIKE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Not,
                                              Terminal($2).Token,
                                              new BuiltInExpr(BuiltInKind.Like, Terminal($3).Token, (Node)$1, (Node)$4));
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxNotLike);
                    }
                    | Expr LIKE Expr ESCAPE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Like, Terminal($2).Token, (Node)$1, (Node)$3, (Node)$5);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxLike);
                    }
                    | Expr NOT LIKE Expr ESCAPE Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Not,
                                              Terminal($2).Token,
                                              new BuiltInExpr(BuiltInKind.Like, Terminal($3).Token, (Node)$1, (Node)$4, (Node)$6));
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxNotLike);
                    }
                    //
                    // Between 
                    //
                    | betweenPrefix AND Expr
                    {
                        NodeList<Node> elist = (NodeList<Node>)$1;
                        System.Diagnostics.Debug.Assert(elist.Count==2);
                        $$ = new BuiltInExpr(BuiltInKind.Between, "between", elist[0], elist[1], (Node)$3 );
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxBetween);
                    }
                    //
                    // Not Between 
                    //
                    | notBetweenPrefix AND Expr
                    {
                        NodeList<Node> elist = (NodeList<Node>)$1;
                        System.Diagnostics.Debug.Assert(elist.Count==2);
                        $$ = new BuiltInExpr(BuiltInKind.NotBetween, "notbetween", elist[0], elist[1], (Node)$3 );
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxNotBetween);
                    }
                    //
                    // Logical
                    //
                    | Expr OR Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Or, "or", (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxOr);
                    }
                    | NOT Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Not, "not", (Node)$2);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNot);
                    }
                    | Expr AND Expr // see note (1) in the file header
                    {
                        $$ = new BuiltInExpr(BuiltInKind.And, "and", (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxAnd);
                    }
                    | equalsOrAssignExpr
                    {
                        $$ = $1;
                    }
                    ;

equalsOrAssignExpr  : assignExpr
                    {
                        $$ = $1;
                    }
                    | equalsExpr
                    {
                        $$ = $1;
                    }
                    ;

assignExpr          : Expr EQUAL Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Equal, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxEquals);
                    }
                    ;

equalsExpr          : Expr OP_EQ Expr
                    {
                        $$ = new BuiltInExpr(BuiltInKind.Equal, Terminal($2).Token, (Node)$1, (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxEquals);
                    }
                    ;

aliasExpr           : Expr AS identifier
                    {
                        $$ = new AliasedExpr((Node)$1, (Identifier)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxAlias);
                    }
                    | Expr
                    {
                        $$ = new AliasedExpr((Node)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    ;

aliasExprList       : aliasExpr
                    {
                       $$ = new NodeList<AliasedExpr>((AliasedExpr)$1);
                       SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | aliasExprList COMMA aliasExpr
                    {
                       $$ = ToNodeList<AliasedExpr>($1).Add((AliasedExpr)$3);
                        SetErrCtx(AstNode($$), AstNodePos($$), EntityRes.CtxExpressionList);
                    }
                    ;

searchedCaseExpr    : CASE whenThenExprList END
                    {
                        $$ = new CaseExpr(ToNodeList<WhenThenExpr>($2));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCase);
                    }
                    | CASE whenThenExprList caseElseExpr END
                    {
                        $$ = new CaseExpr(ToNodeList<WhenThenExpr>($2), (Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCase);
                    }
                    ;

whenThenExprList    : WHEN Expr THEN Expr
                    {
                        $$ = new NodeList<WhenThenExpr>(new WhenThenExpr((Node)$2, (Node)$4));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCaseWhenThen);
                    }
                    | whenThenExprList WHEN Expr THEN Expr
                    {
                        $$ = ToNodeList<WhenThenExpr>($1).Add(new WhenThenExpr((Node)$3, (Node)$5));
                    }
                    ;

caseElseExpr        : ELSE Expr
                    {
                        $$ = (Node)$2;
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCaseElse);
                    }
                    ;

ctorExpr            : ROW L_PAREN aliasExprList R_PAREN
                    {
                        $$ = new RowConstructorExpr(ToNodeList<AliasedExpr>($3));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRowCtor);
                    }
                    | MULTISET L_PAREN exprList R_PAREN
                    {
                        $$ = new MultisetConstructorExpr(ToNodeList<Node>($3));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxMultisetCtor);
                    }
                    | L_CURLY exprList R_CURLY
                    {
                        $$ = new MultisetConstructorExpr(ToNodeList<Node>($2));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxMultisetCtor);
                    }
                    ;

dotExpr             : Expr DOT identifier
                    {
                        $$ = new DotExpr((Node)$1, (Identifier)$3);
                        SetErrCtx(AstNode($$), Terminal($2), EntityRes.CtxMemberAccess);
                    }
                    ;

refExpr             : REF L_PAREN generalExpr R_PAREN
                    {
                        $$ = new RefExpr((Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRef);
                    }
                    ;

derefExpr           : DEREF L_PAREN generalExpr R_PAREN
                    {
                        $$ = new DerefExpr((Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxDeref);
                    }
                    ;

createRefExpr       : CREATEREF L_PAREN Expr COMMA Expr R_PAREN
                    {
                        $$ = new CreateRefExpr((Node)$3, (Node)$5);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCreateRef);
                    }
                    | CREATEREF L_PAREN Expr COMMA Expr COMMA typeName R_PAREN
                    {
                        $$ = new CreateRefExpr((Node)$3, (Node)$5, (Node)$7);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCreateRef);
                    }
                    ;

keyExpr             : KEY L_PAREN generalExpr R_PAREN
                    {
                        $$ = new KeyExpr((Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxKey);
                    }
                    ;

groupPartitionExpr  : GROUPPARTITION L_PAREN optAllOrDistinct generalExpr R_PAREN
                    {
                        $$ = new GroupPartitionExpr((DistinctKind)$3, (Node)$4);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxGroupPartition);
                    }
                    ;

methodExpr          : dotExpr L_PAREN /* e */ R_PAREN
                    {
                        $$ = new MethodExpr((Node)$1, DistinctKind.None, null);
                        SetErrCtx(AstNode($$), AstNodePos(((DotExpr)$1).Identifier), EntityRes.CtxMethod);
                    }
                    | dotExpr L_PAREN optAllOrDistinct exprList R_PAREN optWithRelationship
                    {
                        $$ = new MethodExpr((Node)$1, (DistinctKind)$3, ToNodeList<Node>($4), ToNodeList<RelshipNavigationExpr>($6));
                        SetErrCtx(AstNode($$), AstNodePos(((DotExpr)$1).Identifier), EntityRes.CtxMethod);
                    }
                    | dotExpr L_PAREN optAllOrDistinct queryExpr R_PAREN optWithRelationship
                    {
                        $$ = new MethodExpr((Node)$1, (DistinctKind)$3, new NodeList<Node>((Node)$4), ToNodeList<RelshipNavigationExpr>($6));
                        SetErrCtx(AstNode($$), AstNodePos(((DotExpr)$1).Identifier), EntityRes.CtxMethod);
                    }
                    | identifier L_PAREN /* e */ R_PAREN
                    {
                        $$ = new MethodExpr((Identifier)$1, DistinctKind.None, null);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxMethod);
                    }
                    | identifier L_PAREN optAllOrDistinct exprList R_PAREN optWithRelationship
                    {
                        $$ = new MethodExpr((Identifier)$1, (DistinctKind)$3, ToNodeList<Node>($4), ToNodeList<RelshipNavigationExpr>($6));
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxMethod);
                    }
                    | identifier L_PAREN optAllOrDistinct queryExpr R_PAREN optWithRelationship
                    {
                        $$ = new MethodExpr((Identifier)$1,(DistinctKind)$3, new NodeList<Node>((Node)$4), ToNodeList<RelshipNavigationExpr>($6));
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxMethod);
                    }
                    ;

                    //
                    // Navigate( e, relationType )
                    //
navigateExpr        : NAVIGATE L_PAREN Expr COMMA typeName R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, null, null);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNavigate);
                    }
                    //
                    // Navigate( e, relationType, toEnd )
                    //
                    | NAVIGATE L_PAREN Expr COMMA typeName COMMA identifier R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, (Identifier)$7, null);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNavigate);
                    }
                    //
                    // Navigate( e, relationType, ToEnd, FromEnd )
                    //
                    | NAVIGATE L_PAREN Expr COMMA typeName COMMA identifier COMMA identifier R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, (Identifier)$7, (Identifier)$9);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNavigate);
                    }
                    ;

optWithRelationship : /* e */
                    {
                        $$ = null;
                    }
                    | relationshipList
                    {
                        $$ = $1;
                    }
                    ;

relationshipList    : WITH relationshipExpr
                    {
                        $$ = new NodeList<RelshipNavigationExpr>((RelshipNavigationExpr)$2);
                        SetErrCtx(AstNode($$), AstNodePos($2), EntityRes.CtxRelationshipList);
                    }
                    | relationshipList relationshipExpr
                    {
                        $$ = ToNodeList<RelshipNavigationExpr>($1).Add((RelshipNavigationExpr)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxRelationshipList);
                    }
                    ;

                    //
                    // RELATIONSHIP( e, relationType )
                    //
relationshipExpr    : RELATIONSHIP L_PAREN Expr COMMA typeName R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, null, null);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRelationship);
                    }
                    //
                    // RELATIONSHIP( e, relationType, fromEnd )
                    //
                    | RELATIONSHIP L_PAREN Expr COMMA typeName COMMA identifier R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, null, (Identifier)$7);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRelationship);
                    }
                    //
                    // RELATIONSHIP( e, relationType, fromEnd, toEnd )
                    //
                    | RELATIONSHIP L_PAREN Expr COMMA typeName COMMA identifier COMMA identifier R_PAREN
                    {
                        $$ = new RelshipNavigationExpr((Node)$3, (Node)$5, (Identifier)$9, (Identifier)$7);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRelationship);
                    }
                    ;
                    
typeName            : identifier 
                    {
                        $$ = $1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    | qualifiedTypeName
                    {
                        $$ = $1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    | identifier ESCAPED_IDENTIFIER
                    {
                        Identifier identifier = (Identifier)$1;
                        Identifier escapedIdentifier = (Identifier)$2;
                        if (identifier.IsEscaped || escapedIdentifier.Name.Length > 0)
                        {
                            throw EntityUtil.EntitySqlError(identifier.ErrCtx, System.Data.Entity.Strings.InvalidMetadataMemberName);
                        }
                        $$ = new Identifier(identifier.Name + "[]", /*isEscaped*/false, _query, AstNodePos($1));
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    | qualifiedTypeName ESCAPED_IDENTIFIER
                    {
                        DotExpr dotExpr = (DotExpr)$1;
                        Identifier identifier = dotExpr.Identifier;
                        Identifier escapedIdentifier = (Identifier)$2;
                        if (identifier.IsEscaped || escapedIdentifier.Name.Length > 0)
                        {
                            throw EntityUtil.EntitySqlError(identifier.ErrCtx, System.Data.Entity.Strings.InvalidMetadataMemberName);
                        }
                        $$ = new DotExpr(dotExpr.Left, new Identifier(identifier.Name + "[]", /*isEscaped*/false, _query, AstNodePos($1)));
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    | typeNameWithTypeSpec
                    {
                        $$ = (MethodExpr)$1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    ;

qualifiedTypeName   : typeName DOT identifier
                    {
                        $$ = new DotExpr((Node)$1, (Identifier)$3);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeName);
                    }
                    ;
                    
typeNameWithTypeSpec : qualifiedTypeName L_PAREN /* e */ R_PAREN
                    {
                        $$ = new MethodExpr((Node)$1, DistinctKind.None, null);
                        SetErrCtx(AstNode($$), AstNodePos(((DotExpr)$1).Identifier), EntityRes.CtxTypeNameWithTypeSpec);
                    }
                    | qualifiedTypeName L_PAREN exprList R_PAREN
                    {
                        $$ = new MethodExpr((Node)$1, DistinctKind.None, ToNodeList<Node>($3));
                        SetErrCtx(AstNode($$), AstNodePos(((DotExpr)$1).Identifier), EntityRes.CtxTypeNameWithTypeSpec);
                    }
                    | identifier L_PAREN /* e */ R_PAREN
                    {
                        $$ = new MethodExpr((Identifier)$1, DistinctKind.None, null);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeNameWithTypeSpec);
                    }
                    | identifier L_PAREN exprList R_PAREN
                    {
                        $$ = new MethodExpr((Identifier)$1, DistinctKind.None, ToNodeList<Node>($3));
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxTypeNameWithTypeSpec);
                    }
                    ;

identifier          : ESCAPED_IDENTIFIER
                    {
                        $$ = (Identifier)$1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxEscapedIdentifier);
                    }
                    | simpleIdentifier
                    {
                        $$ = (Identifier)$1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxSimpleIdentifier);
                    }
                    ;

simpleIdentifier    : IDENTIFIER
                    {
                        $$ = (Identifier)$1;
                    }
                    ;

literalExpr         : LITERAL
                    {
                        $$ = $1;
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxLiteral);
                    }
                    | NULL
                    {
                        $$ = new Literal(null, LiteralKind.Null, _query, TerminalPos($1));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxNullLiteral);
                    }
                    ;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type defintions
//~~~~~~~~~~~~~~~~~~~~~~~~~~~

typeDef             : typeName
                    {
                        $$ = $1;
                    }
                    | collectionTypeDef
                    {
                        $$ = $1;
                    }
                    | refTypeDef
                    {
                        $$ = $1;
                    }
                    | rowTypeDef
                    {
                        $$ = $1;
                    }
                    ;
                    
collectionTypeDef   : COLLECTION L_PAREN typeDef R_PAREN
                    {
                        $$ = new CollectionTypeDefinition((Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxCollectionTypeDefinition);
                    }
                    ;
                    
refTypeDef          : REF L_PAREN typeName R_PAREN
                    {
                        $$ = new RefTypeDefinition((Node)$3);
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRefTypeDefinition);
                    }
                    ;
                    
rowTypeDef          : ROW L_PAREN propertyDefList R_PAREN
                    {
                        $$ = new RowTypeDefinition(ToNodeList<PropDefinition>($3));
                        SetErrCtx(AstNode($$), Terminal($1), EntityRes.CtxRowTypeDefinition);
                    }
                    ;
                    
propertyDefList     : propertyDef
                    {
                        $$ = new NodeList<PropDefinition>((PropDefinition)$1);
                        SetErrCtx(AstNode($$), AstNodePos($1), AstNode($1).ErrCtx.ErrorContextInfo);
                    }
                    | propertyDefList COMMA propertyDef
                    {
                        $$ = ToNodeList<PropDefinition>($1).Add((PropDefinition)$3);
                        SetErrCtx(AstNode($$), AstNodePos($$), AstNode($3).ErrCtx.ErrorContextInfo);
                    }
                    ;

propertyDef         : identifier typeDef
                    {
                        $$ = new PropDefinition((Identifier)$1, (Node)$2);
                        SetErrCtx(AstNode($$), AstNodePos($1), EntityRes.CtxRowTypeDefinition);
                    }
                    ;

%%

#pragma warning restore 414
