context: #region Copyright
  /*
   * Product: IronyScript.NET
   * Author: Petro Protsyk
   * Date: 11.02.2008
   * Time: 20:58
   * Update: June 2008
   *  
   * 
   * History:
   * 
   *  17.03.2008:  Evaluation implementation with Visitor pattern.
   *  02.04.2008:  Large refactoring to use Evaluation function instead of Visitor
   *   June 2008:  Getting things done
   */
  #endregion
  
  #region Using
  using System;
  using System.Globalization;
  using System.Collections.Generic;
  
  using Irony.Compiler;
  
  using ScriptNET.Ast;
  using ScriptNET.Runtime;
  #endregion
  
  namespace ScriptNET
  {
    /// <summary>
    /// This class represents Irony Grammar for Script.NET
    /// </summary>
    [Bindable(false)] 
    public class ScriptdotnetGrammar : Grammar
    {
      public ScriptdotnetGrammar(bool expressionGrammar)
      {
        #region 1. Terminals
        NumberLiteral n = TerminalFactory.CreateCSharpNumber("number");
        IdentifierTerminal v = CreateScriptNetIdentifier("Identifier");
        Terminal s = CreateScriptNetString("string");
  
        Terminal @is = Symbol("is");
        Terminal dot = Symbol(".", "dot");
        Terminal less = Symbol("<");
        Terminal greater = Symbol(">");
        Terminal arrow = Symbol("->");
        Terminal LSb = Symbol("[");
        Terminal RSb = Symbol("]");
        Terminal LCb = Symbol("(");
        Terminal RCb = Symbol(")");
        Terminal RFb = Symbol("}");
        Terminal LFb = Symbol("{");
        Terminal LMb = Symbol("<!");
        Terminal RMb = Symbol("!>");
        Terminal LGb = Symbol("<|");
        Terminal RGb = Symbol("|>");
        Terminal comma = Symbol(",");
        Terminal semicolon = Symbol(";");
        Terminal colon = Symbol(":");
        #endregion
  
        #region 2. Non-terminals
        #region 2.1 Expressions
        NonTerminal Expr = new NonTerminal("Expr", typeof(ScriptExpr));
        NonTerminal ConstExpr = new NonTerminal("ConstExpr", typeof(ScriptConstExpr));
        NonTerminal BinExpr = new NonTerminal("BinExpr", typeof(ScriptBinExpr));
        NonTerminal UnaryExpr = new NonTerminal("UnaryExpr", typeof(ScriptUnaryExpr));
        NonTerminal AssignExpr = new NonTerminal("AssignExpr", typeof(ScriptAssignExpr));
        NonTerminal TypeConvertExpr = new NonTerminal("TypeConvertExpr", typeof(ScriptTypeConvertExpr));
        NonTerminal IsExpr = new NonTerminal("IsExpr", typeof(ScriptIsExpr));
        NonTerminal MetaExpr = new NonTerminal("MetaExpr", typeof(ScriptMetaExpr));
        NonTerminal FuncDefExpr = new NonTerminal("FuncDefExpr", typeof(ScriptFunctionDefinition));  //typeof(ScriptFunctionDefExpression));
  
        NonTerminal TypeExpr = new NonTerminal("TypeExpr", typeof(ScriptTypeExpr));
        NonTerminal TypeConstructor = new NonTerminal("TypeConstructor", typeof(ScriptTypeConstructor));
        NonTerminal FunctionCall = new NonTerminal("FunctionCall", typeof(ScriptFunctionCall));
        NonTerminal ArrayResolution = new NonTerminal("ArrayResolution", typeof(ScriptArrayResolution));
  
        NonTerminal BinOp = new NonTerminal("BinOp");
        NonTerminal LUnOp = new NonTerminal("LUnOp");
        NonTerminal RUnOp = new NonTerminal("RUnOp");
  
        NonTerminal ArrayConstructor = new NonTerminal("ArrayConstructor", typeof(ScriptArrayConstructor));
        NonTerminal MObjectConstructor = new NonTerminal("MObjectConstructor", typeof(ScriptMObject));
        NonTerminal MObjectPart = new NonTerminal("MObjectPart", typeof(ScriptMObjectPart));
        NonTerminal MObjectParts = new NonTerminal("MObjectPart", typeof(ScriptAst));
  
        NonTerminal TypeList = new NonTerminal("TypeList", typeof(ScriptTypeExprList));
        #endregion
  
        #region 2.2 QualifiedName
        //Expression List:  expr1, expr2, expr3, ..
        NonTerminal ExprList = new NonTerminal("ExprList", typeof(ScriptExprList));
  
        //A name in form: a.b.c().d[1,2].e ....
        NonTerminal NewStmt = new NonTerminal("NewStmt", typeof(ScriptNewStmt));
        NonTerminal NewArrStmt = new NonTerminal("NewArrStmt", typeof(ScriptNewArrStmt));
        NonTerminal QualifiedName = new NonTerminal("QualifiedName", typeof(ScriptQualifiedName));
        NonTerminal GenericsPostfix = new NonTerminal("GenericsPostfix", typeof(ScriptGenericsPostfix));
  
        NonTerminal GlobalList = new NonTerminal("GlobalList", typeof(ScriptGlobalList));
        #endregion
  
        #region 2.3 Statement
        NonTerminal Condition = new NonTerminal("Condition", typeof(ScriptCondition));
        NonTerminal Statement = new NonTerminal("Statement", typeof(ScriptStatement));
  
        NonTerminal IfStatement = new NonTerminal("IfStatement", typeof(ScriptIfStatement));
        NonTerminal WhileStatement = new NonTerminal("WhileStatement", typeof(ScriptWhileStatement));
        NonTerminal ForStatement = new NonTerminal("ForStatement", typeof(ScriptForStatement));
        NonTerminal ForEachStatement = new NonTerminal("ForEachStatement", typeof(ScriptForEachStatement));
        NonTerminal OptionalExpression = new NonTerminal("OptionalExpression", typeof(ScriptExpr));
        NonTerminal SwitchStatement = new NonTerminal("SwitchStatement", typeof(ScriptStatement));
        NonTerminal SwitchStatements = new NonTerminal("SwitchStatements", typeof(ScriptSwitchStatement));
        NonTerminal SwitchCaseStatement = new NonTerminal("SwitchCaseStatement", typeof(ScriptSwitchCaseStatement));
        NonTerminal SwitchDefaultStatement = new NonTerminal("SwitchDefaultStatement", typeof(ScriptSwitchDefaultStatement));
        NonTerminal UsingStatement = new NonTerminal("UsingStatement", typeof(ScriptUsingStatement));
        NonTerminal TryCatchFinallyStatement = new NonTerminal("TryCatchFinallyStatement", typeof(ScriptTryCatchFinallyStatement));
        NonTerminal FlowControlStatement = new NonTerminal("FlowControl", typeof(ScriptFlowControlStatement));
        NonTerminal ExprStatement = new NonTerminal("ExprStatement", typeof(ScriptStatement));
  
        //Block
        NonTerminal BlockStatement = new NonTerminal("BlockStatement", typeof(ScriptStatement));
        NonTerminal Statements = new NonTerminal("Statements(Compound)", typeof(ScriptCompoundStatement));
        #endregion
  
        #region 2.4 Program and Functions
        NonTerminal Prog = new NonTerminal("Prog", typeof(ScriptProg));
        NonTerminal Element = new NonTerminal("Element", typeof(ScriptAst));
        NonTerminal Elements = new NonTerminal("Elements", typeof(ScriptElements));
        NonTerminal FuncDef = new NonTerminal("FuncDef", typeof(ScriptFunctionDefinition));
        NonTerminal FuncContract = new NonTerminal("FuncContract", typeof(ScriptFuncContract));
        NonTerminal ParameterList = new NonTerminal("ParamaterList", typeof(ScriptFuncParameters));
  
        NonTerminal FuncContractPre = new NonTerminal("Pre Conditions", typeof(ScriptFuncContractPre));
        NonTerminal FuncContractPost = new NonTerminal("Post Conditions", typeof(ScriptFuncContractPost));
        NonTerminal FuncContractInv = new NonTerminal("Invariant Conditions", typeof(ScriptFuncContractInv));
        #endregion
  
        #endregion
  
        #region 3. BNF rules
        #region 3.1 Expressions
        ConstExpr.Rule = Symbol("true")
                        | "false"
                        | "null"
                        | s
                        | n;
  
        BinExpr.Rule = Expr + BinOp + Expr
                       | IsExpr;
  
        UnaryExpr.Rule = LUnOp + Expr;
  
        IsExpr.Rule = Expr + @is + TypeExpr;
  
        TypeConvertExpr.Rule = LCb + Expr + RCb + Expr.Q();
                          
        AssignExpr.Rule = QualifiedName + "=" + Expr
                         | QualifiedName + "++"
                         | QualifiedName + "--"
                         | QualifiedName + ":=" + Expr
                         | QualifiedName + "+=" + Expr
                         | QualifiedName + "-=" + Expr;
  
        //TODO: MetaFeatures;
        // <[    ] + > because of conflict a[1]>2
        MetaExpr.Rule = LMb + Elements + RMb;
  
        GlobalList.Rule = "global" + LCb + ParameterList + RCb;
  
        FuncDefExpr.Rule = "function" + LCb + ParameterList + RCb 
          + GlobalList.Q()
          + FuncContract.Q()
          + BlockStatement;
  
        Expr.Rule =   ConstExpr
                    | BinExpr
                    | UnaryExpr
                    | QualifiedName
                    | AssignExpr
                    | NewStmt
                    | FuncDefExpr
                    | NewArrStmt
                    | ArrayConstructor
                    | MObjectConstructor                  
                    | TypeConvertExpr
                    | MetaExpr
                    ;
  
        NewStmt.Rule = "new" + TypeConstructor;
        NewArrStmt.Rule = "new" + TypeExpr + ArrayResolution;
        BinOp.Rule = Symbol("+") | "-" | "*" | "/" | "%" | "^" | "&" | "|"
                    | "&&" | "||" | "==" | "!=" | greater | less 
                    | ">=" | "<=";
  
        LUnOp.Rule = Symbol("~") | "-" | "!" | "$";
  
        ArrayConstructor.Rule = LSb + ExprList + RSb;
        
        MObjectPart.Rule = v + arrow + Expr;
        MObjectParts.Rule = MakePlusRule(MObjectParts, comma, MObjectPart);
        MObjectConstructor.Rule = LSb + MObjectParts + RSb;   
  
        OptionalExpression.Rule = Expr.Q();
        #endregion
  
        #region 3.2 QualifiedName
        TypeExpr.Rule = //MakePlusRule(TypeExpr, dot, v);
            v + GenericsPostfix.Q()
            | TypeExpr + dot + (v + GenericsPostfix.Q());
  
        GenericsPostfix.Rule = LGb + TypeList + RGb;
        FunctionCall.Rule = LCb + ExprList.Q() + RCb;
        ArrayResolution.Rule = LSb + ExprList + RSb;
          
        QualifiedName.Rule = v + (GenericsPostfix | ArrayResolution | FunctionCall).Star()
                            | QualifiedName + dot + v + (GenericsPostfix | ArrayResolution | FunctionCall).Star();
  
        ExprList.Rule = MakePlusRule(ExprList, comma, Expr);
        TypeList.Rule = MakePlusRule(TypeList, comma, TypeExpr);
        TypeConstructor.Rule = TypeExpr + FunctionCall;
        #endregion
  
        #region 3.3 Statement
        Condition.Rule = LCb + Expr + RCb;
        IfStatement.Rule = "if" + Condition + Statement + ("else" + Statement).Q();
        WhileStatement.Rule = "while" + Condition + Statement;
        ForStatement.Rule = "for" + LCb + OptionalExpression + semicolon + OptionalExpression + semicolon + OptionalExpression + RCb + Statement;      
        ForEachStatement.Rule = "foreach" + LCb + v + "in" + Expr + RCb + Statement;
        UsingStatement.Rule = "using" + LCb + Expr + RCb + BlockStatement;
        TryCatchFinallyStatement.Rule = "try" + BlockStatement + "catch" + LCb + v + RCb + BlockStatement + "finally" + BlockStatement;
        SwitchStatement.Rule = "switch" + LCb + Expr + RCb + LFb + SwitchStatements + RFb;
        ExprStatement.Rule = Expr + semicolon;
        FlowControlStatement.Rule = "break" + semicolon
                                  | "continue" + semicolon
                                  | "return" + Expr + semicolon
                                  | "throw" + Expr + semicolon;
                   
        Statement.Rule = semicolon
                        | IfStatement                 //1. If
                        | WhileStatement              //2. While
                        | ForStatement                //3. For
                        | ForEachStatement            //4. ForEach
                        | UsingStatement              //5. Using
                        | SwitchStatement             //6. Switch
                        | BlockStatement              //7. Block
                        | TryCatchFinallyStatement    //8. TryCatch
                        | ExprStatement               //9. Expr
                        | FlowControlStatement;       //10. FlowControl
  
        Statements.SetOption(TermOptions.IsList);
  
gt:       Statements.Rule = Statements + Statement | Empty;