The Labs \ Source Viewer \ SSCLI \ Microsoft.JScript \ EndOfFile

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace Microsoft.JScript
  16. {
  17.    
  18.     using System;
  19.     using System.Collections;
  20.     using System.Reflection;
  21.     using System.Text.RegularExpressions;
  22.     using Microsoft.Vsa;
  23.     using System.Security.Permissions;
  24.     using System.Globalization;
  25.    
  26.     //***************************************************************************************
  27.     // JSParser
  28.     //
  29.     // The JScript Parser.
  30.     //***************************************************************************************
  31.     [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
  32.     public class JSParser
  33.     {
  34.        
  35.        
  36.         private bool demandFullTrustOnFunctionCreation;
  37.         private Context sourceContext;
  38.         private JSScanner scanner;
  39.         private Context currentToken;
  40.         private Context errorToken;
  41.         // used for errors to flag that the same token has to be returned.
  42.         // We could have used just a boolean but having a Context does not
  43.         // add any overhead and allow to really save the info, if that will ever be needed
  44.         private int tokensSkipped;
  45.         private const int c_MaxSkippedTokenNumber = 50;
  46.         private NoSkipTokenSet noSkipTokenSet;
  47.         private long goodTokensProcessed;
  48.        
  49.         private Block program;
  50.        
  51.         // label related info
  52.         private ArrayList blockType;
  53.         private SimpleHashtable labelTable;
  54.         enum BlockType
  55.         {
  56.             Block,
  57.             Loop,
  58.             Switch,
  59.             Finally
  60.         }
  61.         private int finallyEscaped;
  62.        
  63.         private int breakRecursion = 0;
  64.         private static int s_cDummyName;
  65.         #if DEBUG
  66.         private static int s_filenameSuffix = 0;
  67.         #endif
  68.        
  69.         Globals Globals;
  70.         private int Severity;
  71.        
  72.         //---------------------------------------------------------------------------------------
  73.         // JSParser
  74.         //
  75.         // create a parser with a context. The context is the code that has to be compiled.
  76.         // Typically used by the runtime
  77.         //---------------------------------------------------------------------------------------
  78.         public JSParser(Context context)
  79.         {
  80.             this.sourceContext = context;
  81.             this.currentToken = context.Clone();
  82.             this.scanner = new JSScanner(this.currentToken);
  83.             this.noSkipTokenSet = new NoSkipTokenSet();
  84.            
  85.             this.errorToken = null;
  86.             this.program = null;
  87.             this.blockType = new ArrayList(16);
  88.             this.labelTable = new SimpleHashtable(16);
  89.             this.finallyEscaped = 0;
  90.             this.Globals = context.document.engine.Globals;
  91.             this.Severity = 5;
  92.             this.demandFullTrustOnFunctionCreation = false;
  93.         }
  94.        
  95.         //---------------------------------------------------------------------------------------
  96.         // Parse
  97.         //
  98.         // Parser main entry point. Parse all the source code and return the root of the AST
  99.         //---------------------------------------------------------------------------------------
  100.         public ScriptBlock Parse()
  101.         {
  102.             Block ast = ParseStatements(false);
  103.             return new ScriptBlock(this.sourceContext.Clone(), ast);
  104.         }
  105.        
  106.         //---------------------------------------------------------------------------------------
  107.         // ParseEvalBody
  108.         //
  109.         // Parser main entry point for Eval. Parse all the source code and return the root of the AST
  110.         //---------------------------------------------------------------------------------------
  111.         public Block ParseEvalBody()
  112.         {
  113.             this.demandFullTrustOnFunctionCreation = true;
  114.             return ParseStatements(true);
  115.         }
  116.        
  117.         //---------------------------------------------------------------------------------------
  118.         // ParseExpressionItem
  119.         //
  120.         // A VSAITEMTYPE2.EXPRESSION call into here to parse an expression
  121.         //---------------------------------------------------------------------------------------
  122.         internal ScriptBlock ParseExpressionItem()
  123.         {
  124.             int scopeStackSize = Globals.ScopeStack.Size();
  125.             try {
  126.                 Block block = new Block(this.sourceContext.Clone());
  127.                 GetNextToken();
  128.                 block.Append(new Expression(this.sourceContext.Clone(), ParseExpression()));
  129.                 return new ScriptBlock(this.sourceContext.Clone(), block);
  130.             }
  131.             catch (EndOfFile) {
  132.             }
  133.             catch (ScannerException se) {
  134.                 // a scanner exception implies that the end of file has been reached with an error.
  135.                 // Mark the end of file as the error location
  136.                 EOFError(se.m_errorId);
  137.             }
  138.             catch (StackOverflowException) {
  139.                 // On stack overflow, finally clauses are not executed so we explicitly
  140.                 // restore the global stack here.
  141.                 Globals.ScopeStack.TrimToSize(scopeStackSize);
  142.                 ReportError(JSError.OutOfStack, true);
  143.             }
  144.             return null;
  145.         }
  146.        
  147.         //---------------------------------------------------------------------------------------
  148.         // ParseStatements
  149.         //
  150.         // statements :
  151.         // <empty> |
  152.         // statement statements |
  153.         // ImportStatement
  154.         //
  155.         //---------------------------------------------------------------------------------------
  156.         private Block ParseStatements(bool insideEval)
  157.         {
  158.             int scopeStackSize = Globals.ScopeStack.Size();
  159.             this.program = new Block(this.sourceContext.Clone());
  160.             this.blockType.Add(BlockType.Block);
  161.             this.errorToken = null;
  162.             try {
  163.                 GetNextToken();
  164.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  165.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_TopLevelNoSkipTokenSet);
  166.                
  167.                 try {
  168.                     while (this.currentToken.token != JSToken.EndOfFile) {
  169.                         AST ast = null;
  170.                         try {
  171.                             if (this.currentToken.token == JSToken.Package && !insideEval) {
  172.                                 ast = ParsePackage(this.currentToken.Clone());
  173.                             }
  174.                             else if (this.currentToken.token == JSToken.Import && !insideEval) {
  175.                                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  176.                                 try {
  177.                                     ast = ParseImportStatement();
  178.                                 }
  179.                                 catch (RecoveryTokenException exc) {
  180.                                     if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) != -1) {
  181.                                         ast = exc._partiallyComputedNode;
  182.                                         if (exc._token == JSToken.Semicolon)
  183.                                             GetNextToken();
  184.                                     }
  185.                                     else {
  186.                                         throw exc;
  187.                                     }
  188.                                 }
  189.                                 finally {
  190.                                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  191.                                 }
  192.                             }
  193.                             else
  194.                                 ast = ParseStatement();
  195.                         }
  196.                         catch (RecoveryTokenException exc) {
  197.                             if (TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, exc) || TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc)) {
  198.                                 ast = exc._partiallyComputedNode;
  199.                             }
  200.                             else {
  201.                                 this.errorToken = null;
  202.                                 do {
  203.                                     GetNextToken();
  204.                                 }
  205.                                 while (this.currentToken.token != JSToken.EndOfFile && !TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, this.currentToken.token) && !TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, this.currentToken.token));
  206.                             }
  207.                         }
  208.                        
  209.                         if (null != ast)
  210.                             this.program.Append(ast);
  211.                     }
  212.                    
  213.                 }
  214.                 finally {
  215.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_TopLevelNoSkipTokenSet);
  216.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  217.                 }
  218.                
  219.             }
  220.             catch (EndOfFile) {
  221.             }
  222.             catch (ScannerException se) {
  223.                 // a scanner exception implies that the end of file has been reached with an error.
  224.                 // Mark the end of file as the error location
  225.                 EOFError(se.m_errorId);
  226.             }
  227.             catch (StackOverflowException) {
  228.                 // On stack overflow, finally clauses are not executed so we explicitly
  229.                 // restore the global stack here.
  230.                 Globals.ScopeStack.TrimToSize(scopeStackSize);
  231.                 ReportError(JSError.OutOfStack, true);
  232.             }
  233.             return this.program;
  234.         }
  235.        
  236.         //---------------------------------------------------------------------------------------
  237.         // ParseStatement
  238.         //
  239.         // OptionalStatement:
  240.         // Statement |
  241.         // <empty>
  242.         //
  243.         // Statement :
  244.         // Block |
  245.         // VariableStatement |
  246.         // EmptyStatement |
  247.         // ExpressionStatement |
  248.         // IfStatement |
  249.         // IterationStatement |
  250.         // ContinueStatement |
  251.         // BreakStatement |
  252.         // ReturnStatement |
  253.         // WithStatement |
  254.         // LabeledStatement |
  255.         // SwitchStatement |
  256.         // ThrowStatement |
  257.         // TryStatement |
  258.         // QualifiedDeclaration |
  259.         // Class |
  260.         // FunctionDeclaration
  261.         //
  262.         // IterationStatement :
  263.         // 'for' '(' ForLoopControl ')' | ===> ForStatement
  264.         // 'do' Statement 'while' '(' Expression ')' | ===> DoStatement
  265.         // 'while' '(' Expression ')' Statement ===> WhileStatement
  266.         //
  267.         //---------------------------------------------------------------------------------------
  268.        
  269.         // ParseStatement deals with the end of statement issue (EOL vs ';') so if any of the
  270.         // ParseXXX routine does it as well, it should return directly from the switch statement
  271.         // without any further execution in the ParseStatement
  272.         private AST ParseStatement()
  273.         {
  274.             AST statement = null;
  275.             string id = null;
  276.            
  277.             switch (this.currentToken.token) {
  278.                 case JSToken.EndOfFile:
  279.                     EOFError(JSError.ErrEOF);
  280.                     throw new EndOfFile();
  281.                     break;
  282.                 case JSToken.Debugger:
  283.                     // abort parsing, get back to the main parse routine
  284.                     statement = new DebugBreak(this.currentToken.Clone());
  285.                     GetNextToken();
  286.                     break;
  287.                 case JSToken.Semicolon:
  288.                     // make an empty statement
  289.                     statement = new Block(this.currentToken.Clone());
  290.                     GetNextToken();
  291.                     return statement;
  292.                 case JSToken.RightCurly:
  293.                     ReportError(JSError.SyntaxError);
  294.                     SkipTokensAndThrow();
  295.                     break;
  296.                 case JSToken.LeftCurly:
  297.                     return ParseBlock();
  298.                 case JSToken.Var:
  299.                 case JSToken.Const:
  300.                     return ParseVariableStatement((FieldAttributes)0, null, this.currentToken.token);
  301.                 case JSToken.If:
  302.                     return ParseIfStatement();
  303.                 case JSToken.For:
  304.                     return ParseForStatement();
  305.                 case JSToken.Do:
  306.                     return ParseDoStatement();
  307.                 case JSToken.While:
  308.                     return ParseWhileStatement();
  309.                 case JSToken.Continue:
  310.                     statement = ParseContinueStatement();
  311.                     if (null == statement)
  312.                         return new Block(CurrentPositionContext());
  313.                     else
  314.                         return statement;
  315.                     break;
  316.                 case JSToken.Break:
  317.                     statement = ParseBreakStatement();
  318.                     if (null == statement)
  319.                         return new Block(CurrentPositionContext());
  320.                     else
  321.                         return statement;
  322.                     break;
  323.                 case JSToken.Return:
  324.                     statement = ParseReturnStatement();
  325.                     if (null == statement)
  326.                         return new Block(CurrentPositionContext());
  327.                     else
  328.                         return statement;
  329.                     break;
  330.                 case JSToken.With:
  331.                     return ParseWithStatement();
  332.                 case JSToken.Switch:
  333.                     return ParseSwitchStatement();
  334.                 case JSToken.Super:
  335.                 case JSToken.This:
  336.                     Context superCtx = this.currentToken.Clone();
  337.                     if (JSToken.LeftParen == this.scanner.PeekToken())
  338.                         statement = ParseConstructorCall(superCtx);
  339.                     else
  340.                         goto default;
  341.                     break;
  342.                 case JSToken.Throw:
  343.                     statement = ParseThrowStatement();
  344.                     if (statement == null)
  345.                         return new Block(CurrentPositionContext());
  346.                     else
  347.                         break;
  348.                     break;
  349.                 case JSToken.Try:
  350.                     return ParseTryStatement();
  351.                 case JSToken.Internal:
  352.                 case JSToken.Public:
  353.                 case JSToken.Static:
  354.                 case JSToken.Private:
  355.                 case JSToken.Protected:
  356.                 case JSToken.Abstract:
  357.                 case JSToken.Final:
  358.                     bool parsedOK;
  359.                     statement = ParseAttributes(null, false, false, out parsedOK);
  360.                     if (!parsedOK) {
  361.                         statement = ParseExpression(statement, false, true, JSToken.None);
  362.                         statement = new Expression(statement.context.Clone(), statement);
  363.                         break;
  364.                     }
  365.                     else
  366.                         return statement;
  367.                     break;
  368.                 case JSToken.Package:
  369.                     Context packageContext = this.currentToken.Clone();
  370.                     statement = ParsePackage(packageContext);
  371.                     if (statement is Package) {
  372.                         // handle common error of using import in function
  373.                         ReportError(JSError.PackageInWrongContext, packageContext, true);
  374.                         // make an empty statement
  375.                         statement = new Block(packageContext);
  376.                     }
  377.                     break;
  378.                 case JSToken.Interface:
  379.                 case JSToken.Class:
  380.                     return ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null);
  381.                 case JSToken.Enum:
  382.                     return ParseEnum((FieldAttributes)0, this.currentToken.Clone(), null);
  383.                 case JSToken.Function:
  384.                     return ParseFunction((FieldAttributes)0, false, this.currentToken.Clone(), false, false, false, false, null);
  385.                 case JSToken.Else:
  386.                     //Parse a function as a statement
  387.                     ReportError(JSError.InvalidElse);
  388.                     SkipTokensAndThrow();
  389.                     break;
  390.                 case JSToken.Import:
  391.                     // handle common error of using import in function
  392.                     ReportError(JSError.InvalidImport, true);
  393.                     // make an empty statement
  394.                     statement = new Block(this.currentToken.Clone());
  395.                     try {
  396.                         ParseImportStatement();
  397.                     }
  398.                     catch (RecoveryTokenException) {
  399.                     }
  400.                     break;
  401.                 default:
  402.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  403.                     bool exprError = false;
  404.                     try {
  405.                         bool bAssign;
  406.                         bool canBeAttribute = true;
  407.                         statement = ParseUnaryExpression(out bAssign, ref canBeAttribute, false);
  408.                         if (canBeAttribute) {
  409.                             // look for labels
  410.                             if (statement is Lookup) {
  411.                                 if (JSToken.Colon == this.currentToken.token) {
  412.                                     // can be a label
  413.                                     id = statement.ToString();
  414.                                     if (null != this.labelTable[id]) {
  415.                                         // there is already a label with that name. Ignore the current label
  416.                                         ReportError(JSError.BadLabel, statement.context.Clone(), true);
  417.                                         id = null;
  418.                                         GetNextToken();
  419.                                         // skip over ':'
  420.                                         return new Block(CurrentPositionContext());
  421.                                     }
  422.                                     else {
  423.                                         GetNextToken();
  424.                                         this.labelTable[id] = this.blockType.Count;
  425.                                         if (JSToken.EndOfFile != this.currentToken.token)
  426.                                             statement = ParseStatement();
  427.                                         else
  428.                                             statement = new Block(CurrentPositionContext());
  429.                                         this.labelTable.Remove(id);
  430.                                         return statement;
  431.                                     }
  432.                                 }
  433.                             }
  434.                             // look for custom attributes
  435.                             if (JSToken.Semicolon != this.currentToken.token && !this.scanner.GotEndOfLine()) {
  436.                                 bool parsed;
  437.                                 statement = ParseAttributes(statement, false, false, out parsed);
  438.                                 if (parsed)
  439.                                     return statement;
  440.                             }
  441.                         }
  442.                         statement = ParseExpression(statement, false, bAssign, JSToken.None);
  443.                         statement = new Expression(statement.context.Clone(), statement);
  444.                     }
  445.                     catch (RecoveryTokenException exc) {
  446.                         if (exc._partiallyComputedNode != null)
  447.                             statement = exc._partiallyComputedNode;
  448.                        
  449.                         if (statement == null) {
  450.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  451.                             exprError = true;
  452.                             SkipTokensAndThrow();
  453.                         }
  454.                        
  455.                         if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1) {
  456.                             exc._partiallyComputedNode = statement;
  457.                             throw exc;
  458.                         }
  459.                     }
  460.                     finally {
  461.                         if (!exprError)
  462.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  463.                     }
  464.                     break;
  465.             }
  466.            
  467.             if (JSToken.Semicolon == this.currentToken.token) {
  468.                 statement.context.UpdateWith(this.currentToken);
  469.                 GetNextToken();
  470.             }
  471.             else if (!this.scanner.GotEndOfLine() && JSToken.RightCurly != this.currentToken.token && JSToken.EndOfFile != this.currentToken.token)
  472.                 ReportError(JSError.NoSemicolon, true);
  473.             return statement;
  474.         }
  475.        
  476.         //---------------------------------------------------------------------------------------
  477.         // ParseAttributes
  478.         //
  479.         // Package :
  480.         // Attributes 'package' QualifiedIdentifier '{' ClassList '}'
  481.         // AttributesStart 'package' QualifiedIdentifier '{' ClassList '}'
  482.         //
  483.         // Class :
  484.         // Attributes 'class' Identifier ['extends' QualifiedIdentifier] '{' ClassBody '}'
  485.         // AttributesStart 'class' Identifier ['extends' QualifiedIdentifier] '{' ClassBody '}'
  486.         //
  487.         // FunctionDeclaration :
  488.         // Attributes 'function' Identifier '(' [FormalParameterList] ')' [':' TypeExpression] '{' FunctionBody '}'
  489.         // AttributesStart 'function' Identifier '(' [FormalParameterList] ')' [':' TypeExpression] '{' FunctionBody '}'
  490.         //
  491.         // VariableStatement :
  492.         // Attributes 'var' VariableDeclarationList
  493.         // AttributesStart 'var' VariableDeclarationList
  494.         //
  495.         // Attributes :
  496.         // AttributesStart AttributesNext |
  497.         // Modifier [AttributeNext]
  498.         //
  499.         // AttributesStart :
  500.         // QualifiedIdentifier /no LineTerminator here/ |
  501.         // QualifiedIdentifier Arguments /no LineTerminator here/
  502.         //
  503.         // AttributesNext :
  504.         // QualifiedIdentifier [AttributesNext] |
  505.         // QualifiedIdentifier Arguments [AttributesNext] |
  506.         // Modifier [AttributesNext]
  507.         //
  508.         // Modifier :
  509.         // 'private' |
  510.         // 'public' |
  511.         // 'protected' |
  512.         // 'internal' |
  513.         // 'package' | //This is going away
  514.         // 'static' |
  515.         // 'abstract'
  516.         //
  517.         //
  518.         // Parse the list of attributes and the statement those attributes refer to.
  519.         // It comes back with one of the following: package, class, function, variable declaration.
  520.         // When in error it may return other AST constructs depending on the context.
  521.         // The input is a possible attribute in the form of 'QualifiedIdentifier' or a sequence
  522.         // 'QualifiedIdentifier Arguments' or null when the first attribute was a Modifier.
  523.         // The whole sequence may be an error in the first place, so we want to keep
  524.         // things such that we can always parse the supposed list of attributes as an ast list
  525.         //---------------------------------------------------------------------------------------
  526.        
  527.         AST ParseAttributes(AST statement, bool unambiguousContext, bool isInsideClass, out bool parsedOK)
  528.         {
  529.            
  530.             // used later to verify whether anything at all has been processed
  531.             AST inputAST = statement;
  532.            
  533.             // keep two list of errors. One holds the 'missing ;' errors that would result in the token
  534.             // stream being parsed as a list of expressions, the other is the list of attributes errors
  535.             // that would result from the token stream being parsed as a list of attributes. We need both because
  536.             // we don't know until the end which is which
  537.             ArrayList semicolonErrors = new ArrayList();
  538.            
  539.             // keep track of the modifiers context in case they'll have to be parsed as identifiers, we give the warning out
  540.             ArrayList modifiersAsIdentifier = new ArrayList();
  541.            
  542.             // this list has two elements for each error, the first (even position - 0 based) is the error type
  543.             // the second is the context
  544.             ArrayList attributesErrors = new ArrayList();
  545.            
  546.             // keep the last ast node parsed. Used if we have to "revert" to the expression list production.
  547.             // We just return the last ast processed, after all is an error condition
  548.             AST lastAST = null;
  549.            
  550.             // keep the list of attributes
  551.             ArrayList attributes = new ArrayList();
  552.            
  553.             // hold the context for the 'abstract' keyword and it is used as a flag for its presence
  554.             Context abstractContext = null;
  555.             // hold the context for the 'static' keyword and it is used as a flag for its presence
  556.             Context staticContext = null;
  557.             // hold the context for the 'final' keyword and it is used as a flag for its presence
  558.             Context finalContext = null;
  559.            
  560.             // keep the number of consecutive token no separated by end of line. Once that number
  561.             // reaches 2 the token stream is parsed *only* as a sequence of attributes
  562.             int TokenCountNoEOL = 0;
  563.             if (unambiguousContext)
  564.                 TokenCountNoEOL = 2;
  565.            
  566.             FieldAttributes visibilitySpec = (FieldAttributes)0;
  567.             FieldAttributes currVis = (FieldAttributes)0;
  568.            
  569.             Context statementContext = null;
  570.             // null when coming from a visibility modifier
  571.             if (statement != null) {
  572.                 lastAST = statement;
  573.                 attributes.Add(statement);
  574.                 semicolonErrors.Add(CurrentPositionContext());
  575.                 statementContext = statement.context.Clone();
  576.                 TokenCountNoEOL = 1;
  577.             }
  578.             else {
  579.                 statementContext = this.currentToken.Clone();
  580.             }
  581.            
  582.             parsedOK = true;
  583.             while (true) {
  584.                 JSToken attributeToken = JSToken.None;
  585.                 switch (this.currentToken.token) {
  586.                     case JSToken.Public:
  587.                     case JSToken.Static:
  588.                     case JSToken.Private:
  589.                     case JSToken.Protected:
  590.                     case JSToken.Abstract:
  591.                     case JSToken.Final:
  592.                     case JSToken.Internal:
  593.                         attributeToken = this.currentToken.token;
  594.                         goto case JSToken.Identifier;
  595.                         break;
  596.                     case JSToken.Var:
  597.                     case JSToken.Const:
  598.                         for (int i = 0int n = attributesErrors.Count; i < n; i += 2)
  599.                             ReportError((JSError)attributesErrors[i], (Context)attributesErrors[i + 1], true);
  600.                         if (abstractContext != null)
  601.                             ReportError(JSError.IllegalVisibility, abstractContext, true);
  602.                         if (finalContext != null)
  603.                             ReportError(JSError.IllegalVisibility, finalContext, true);
  604.                         statementContext.UpdateWith(this.currentToken);
  605.                         return ParseVariableStatement(visibilitySpec, FromASTListToCustomAttributeList(attributes), this.currentToken.token);
  606.                     case JSToken.Function:
  607.                         for (int i = 0int n = attributesErrors.Count; i < n; i += 2)
  608.                             ReportError((JSError)attributesErrors[i], (Context)attributesErrors[i + 1], true);
  609.                         statementContext.UpdateWith(this.currentToken);
  610.                         if (staticContext != null)
  611.                             if (abstractContext != null) {
  612.                                 staticContext.HandleError(JSError.AbstractCannotBeStatic);
  613.                                 staticContext = null;
  614.                             }
  615.                             else if (finalContext != null) {
  616.                                 finalContext.HandleError(JSError.StaticIsAlreadyFinal);
  617.                                 finalContext = null;
  618.                             }
  619.                         if (abstractContext != null) {
  620.                             if (finalContext != null) {
  621.                                 finalContext.HandleError(JSError.FinalPrecludesAbstract);
  622.                                 finalContext = null;
  623.                             }
  624.                             if (currVis == FieldAttributes.Private) {
  625.                                 abstractContext.HandleError(JSError.AbstractCannotBePrivate);
  626.                                 currVis = FieldAttributes.Family;
  627.                             }
  628.                         }
  629.                         return ParseFunction(visibilitySpec, false, statementContext, isInsideClass, abstractContext != null, finalContext != null, false, FromASTListToCustomAttributeList(attributes));
  630.                     case JSToken.Interface:
  631.                         if (abstractContext != null) {
  632.                             ReportError(JSError.IllegalVisibility, abstractContext, true);
  633.                             abstractContext = null;
  634.                         }
  635.                         if (finalContext != null) {
  636.                             ReportError(JSError.IllegalVisibility, finalContext, true);
  637.                             finalContext = null;
  638.                         }
  639.                         if (staticContext != null) {
  640.                             ReportError(JSError.IllegalVisibility, staticContext, true);
  641.                             staticContext = null;
  642.                         }
  643.                         goto case JSToken.Class;
  644.                         break;
  645.                     case JSToken.Class:
  646.                         for (int i = 0int n = attributesErrors.Count; i < n; i += 2)
  647.                             ReportError((JSError)attributesErrors[i], (Context)attributesErrors[i + 1], true);
  648.                         statementContext.UpdateWith(this.currentToken);
  649.                         if (finalContext != null && abstractContext != null)
  650.                             finalContext.HandleError(JSError.FinalPrecludesAbstract);
  651.                         return ParseClass(visibilitySpec, staticContext != null, statementContext, abstractContext != null, finalContext != null, FromASTListToCustomAttributeList(attributes));
  652.                     case JSToken.Enum:
  653.                         for (int i = 0int n = attributesErrors.Count; i < n; i += 2)
  654.                             ReportError((JSError)attributesErrors[i], (Context)attributesErrors[i + 1], true);
  655.                         statementContext.UpdateWith(this.currentToken);
  656.                         if (abstractContext != null)
  657.                             ReportError(JSError.IllegalVisibility, abstractContext, true);
  658.                         if (finalContext != null)
  659.                             ReportError(JSError.IllegalVisibility, finalContext, true);
  660.                         if (staticContext != null)
  661.                             ReportError(JSError.IllegalVisibility, staticContext, true);
  662.                         return ParseEnum(visibilitySpec, statementContext, FromASTListToCustomAttributeList(attributes));
  663.                     case JSToken.Void:
  664.                     case JSToken.Boolean:
  665.                     case JSToken.Byte:
  666.                     case JSToken.Char:
  667.                     case JSToken.Double:
  668.                     case JSToken.Float:
  669.                     case JSToken.Int:
  670.                     case JSToken.Long:
  671.                     case JSToken.Short:
  672.                        
  673.                         {
  674.                            
  675.                             // The user has some sequence like "public int foo()", which
  676.                             // is probably a C-style function declaration. Save that away,
  677.                             // keep parsing and see if this ends in what looks like a function
  678.                             // or variable declaration.
  679.                            
  680.                             parsedOK = false;
  681.                             lastAST = new Lookup(this.currentToken);
  682.                             attributeToken = JSToken.None;
  683.                             attributes.Add(lastAST);
  684.                             GetNextToken();
  685.                             goto continueLoop;
  686.                         }
  687.                         break;
  688.                     case JSToken.Identifier:
  689.                        
  690.                         {
  691.                             bool bAssign;
  692.                             bool canBeAttribute = true;
  693.                             statement = ParseUnaryExpression(out bAssign, ref canBeAttribute, false, attributeToken == JSToken.None);
  694.                             lastAST = statement;
  695.                             if (attributeToken != JSToken.None) {
  696.                                 if (statement is Lookup)
  697.                                     break;
  698.                                 else {
  699.                                     if (TokenCountNoEOL != 2)
  700.                                         modifiersAsIdentifier.Add(this.currentToken.Clone());
  701.                                 }
  702.                             }
  703.                             attributeToken = JSToken.None;
  704.                             if (canBeAttribute) {
  705.                                 attributes.Add(statement);
  706.                                 goto continueLoop;
  707.                             }
  708.                             else
  709.                                 goto default;
  710.                         }
  711.                         break;
  712.                     default:
  713.                         // the following cases are somewhat interesting because they can be determined by a user missing
  714.                         // the keyword 'var' or 'function', as, for instance, when coming from C/C++/C# code
  715.                         parsedOK = false;
  716.                         if (TokenCountNoEOL != 2) {
  717.                             if (inputAST != statement || statement == null) {
  718.                                 Debug.Assert(lastAST != null);
  719.                                 // only return the last statement
  720.                                 statement = lastAST;
  721.                                 // output the semicolon errors
  722.                                 for (int i = 0int n = modifiersAsIdentifier.Count; i < n; i++)
  723.                                     ForceReportInfo((Context)modifiersAsIdentifier[i], JSError.KeywordUsedAsIdentifier);
  724.                                 for (int i = 0int n = semicolonErrors.Count; i < n; i++)
  725.                                     if (!this.currentToken.Equals((Context)semicolonErrors[i]))
  726.                                         ReportError(JSError.NoSemicolon, (Context)semicolonErrors[i], true);
  727.                             }
  728.                             return statement;
  729.                         }
  730.                         else {
  731.                             if (attributes.Count > 0) {
  732.                                 // check for possible common mistakes
  733.                                 AST ast = (AST)attributes[attributes.Count - 1];
  734.                                 if (ast is Lookup) {
  735.                                     if (JSToken.Semicolon == this.currentToken.token || JSToken.Colon == this.currentToken.token) {
  736.                                         ReportError(JSError.BadVariableDeclaration, ast.context.Clone());
  737.                                         SkipTokensAndThrow();
  738.                                     }
  739.                                 }
  740.                                 else if (ast is Call && ((Call)ast).CanBeFunctionDeclaration()) {
  741.                                     if (JSToken.Colon == this.currentToken.token || JSToken.LeftCurly == this.currentToken.token) {
  742.                                         ReportError(JSError.BadFunctionDeclaration, ast.context.Clone(), true);
  743.                                         if (JSToken.Colon == this.currentToken.token) {
  744.                                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartBlockNoSkipTokenSet);
  745.                                             try {
  746.                                                 SkipTokensAndThrow();
  747.                                             }
  748.                                             catch (RecoveryTokenException) {
  749.                                             }
  750.                                             finally {
  751.                                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartBlockNoSkipTokenSet);
  752.                                             }
  753.                                         }
  754.                                         this.errorToken = null;
  755.                                         if (JSToken.LeftCurly == this.currentToken.token) {
  756.                                             FunctionScope fscope = new FunctionScope(Globals.ScopeStack.Peek(), isInsideClass);
  757.                                             Globals.ScopeStack.Push(fscope);
  758.                                             try {
  759.                                                 ParseBlock();
  760.                                             }
  761.                                             finally {
  762.                                                 Globals.ScopeStack.Pop();
  763.                                             }
  764.                                             SkipTokensAndThrow();
  765.                                         }
  766.                                     }
  767.                                     else
  768.                                         ReportError(JSError.SyntaxError, ast.context.Clone());
  769.                                     SkipTokensAndThrow();
  770.                                 }
  771.                             }
  772.                            
  773.                             if (JSToken.LeftCurly == this.currentToken.token) {
  774.                                 if (isInsideClass) {
  775.                                     // parse it like a static initializer
  776.                                    
  777.                                     // flush all the possible attribute errors
  778.                                     for (int i = 0int n = attributesErrors.Count; i < n; i += 2)
  779.                                         ReportError((JSError)attributesErrors[i], (Context)attributesErrors[i + 1]);
  780.                                     if (staticContext == null)
  781.                                         ReportError(JSError.StaticMissingInStaticInit, CurrentPositionContext());
  782.                                     string className = ((ClassScope)Globals.ScopeStack.Peek()).name;
  783.                                     bool reportNoIdentifier = true;
  784.                                     foreach (object attr in attributes) {
  785.                                         reportNoIdentifier = false;
  786.                                         if (staticContext != null && attr is Lookup && attr.ToString() == className && ((Lookup)attr).context.StartColumn > staticContext.StartColumn)
  787.                                             continue;
  788.                                         ReportError(JSError.SyntaxError, ((AST)attr).context);
  789.                                     }
  790.                                     if (reportNoIdentifier)
  791.                                         ReportError(JSError.NoIdentifier, CurrentPositionContext());
  792.                                    
  793.                                     this.errorToken = null;
  794.                                     // we want to go to next token regardless of whether or not we had an error
  795.                                     // return a static initializer
  796.                                     parsedOK = true;
  797.                                     return ParseStaticInitializer(statementContext);
  798.                                 }
  799.                             }
  800.                            
  801.                             //mark them all as errors
  802.                             ReportError(JSError.MissingConstructForAttributes, statementContext.CombineWith(this.currentToken));
  803.                         }
  804.                        
  805.                         SkipTokensAndThrow();
  806.                         break;
  807.                 }
  808.                
  809.                 switch (attributeToken) {
  810.                     case JSToken.Public:
  811.                         currVis = FieldAttributes.Public;
  812.                         break;
  813.                     case JSToken.Static:
  814.                         if (isInsideClass) {
  815.                             currVis = FieldAttributes.Static;
  816.                             if (staticContext != null) {
  817.                                 attributesErrors.Add(JSError.SyntaxError);
  818.                                 attributesErrors.Add(statement.context.Clone());
  819.                             }
  820.                             else
  821.                                 staticContext = statement.context.Clone();
  822.                         }
  823.                         else {
  824.                             attributesErrors.Add(JSError.NotInsideClass);
  825.                             attributesErrors.Add(statement.context.Clone());
  826.                         }
  827.                         break;
  828.                     case JSToken.Private:
  829.                         if (isInsideClass)
  830.                             currVis = FieldAttributes.Private;
  831.                         else {
  832.                             attributesErrors.Add(JSError.NotInsideClass);
  833.                             attributesErrors.Add(statement.context.Clone());
  834.                         }
  835.                         break;
  836.                     case JSToken.Protected:
  837.                         if (isInsideClass) {
  838.                             currVis = FieldAttributes.Family;
  839.                         }
  840.                         else {
  841.                             attributesErrors.Add(JSError.NotInsideClass);
  842.                             attributesErrors.Add(statement.context.Clone());
  843.                         }
  844.                         break;
  845.                     case JSToken.Abstract:
  846.                         if (abstractContext != null) {
  847.                             attributesErrors.Add(JSError.SyntaxError);
  848.                             attributesErrors.Add(statement.context.Clone());
  849.                         }
  850.                         else
  851.                             abstractContext = statement.context.Clone();
  852.                         goto continueLoop;
  853.                         break;
  854.                     case JSToken.Final:
  855.                         if (finalContext != null) {
  856.                             attributesErrors.Add(JSError.SyntaxError);
  857.                             attributesErrors.Add(statement.context.Clone());
  858.                         }
  859.                         else
  860.                             finalContext = statement.context.Clone();
  861.                         goto continueLoop;
  862.                         break;
  863.                     case JSToken.Internal:
  864.                         currVis = FieldAttributes.Assembly;
  865.                         break;
  866.                     default:
  867.                         break;
  868.                 }
  869.                 // come here only after a visibility Modifer
  870.                 if ((visibilitySpec & FieldAttributes.FieldAccessMask) == currVis && currVis != (FieldAttributes)0) {
  871.                     attributesErrors.Add(JSError.DupVisibility);
  872.                     attributesErrors.Add(statement.context.Clone());
  873.                 }
  874.                 else if ((visibilitySpec & FieldAttributes.FieldAccessMask) > (FieldAttributes)0 && (currVis & FieldAttributes.FieldAccessMask) > (FieldAttributes)0) {
  875.                     if ((currVis == FieldAttributes.Family && (visibilitySpec & FieldAttributes.FieldAccessMask) == FieldAttributes.Assembly) || (currVis == FieldAttributes.Assembly && (visibilitySpec & FieldAttributes.FieldAccessMask) == FieldAttributes.Family)) {
  876.                         visibilitySpec &= ~FieldAttributes.FieldAccessMask;
  877.                         visibilitySpec |= FieldAttributes.FamORAssem;
  878.                     }
  879.                     else {
  880.                         attributesErrors.Add(JSError.IncompatibleVisibility);
  881.                         attributesErrors.Add(statement.context.Clone());
  882.                     }
  883.                 }
  884.                 else {
  885.                     visibilitySpec |= currVis;
  886.                     statementContext.UpdateWith(statement.context);
  887.                 }
  888.                 continueLoop:
  889.                 if (TokenCountNoEOL != 2) {
  890.                     if (this.scanner.GotEndOfLine()) {
  891.                         TokenCountNoEOL = 0;
  892.                     }
  893.                     else {
  894.                         TokenCountNoEOL++;
  895.                         semicolonErrors.Add(this.currentToken.Clone());
  896.                     }
  897.                 }
  898.             }
  899.         }
  900.        
  901.         //---------------------------------------------------------------------------------------
  902.         // ParseBlock
  903.         //
  904.         // Block :
  905.         // '{' OptionalStatements '}'
  906.         //---------------------------------------------------------------------------------------
  907.         Block ParseBlock()
  908.         {
  909.             Context ctx;
  910.             return ParseBlock(out ctx);
  911.         }
  912.        
  913.         Block ParseBlock(out Context closingBraceContext)
  914.         {
  915.             closingBraceContext = null;
  916.             this.blockType.Add(BlockType.Block);
  917.             Block codeBlock = new Block(this.currentToken.Clone());
  918.             GetNextToken();
  919.            
  920.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  921.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  922.             try {
  923.                 try {
  924.                     while (JSToken.RightCurly != this.currentToken.token) {
  925.                         try {
  926.                             codeBlock.Append(ParseStatement());
  927.                         }
  928.                         catch (RecoveryTokenException exc) {
  929.                             if (exc._partiallyComputedNode != null)
  930.                                 codeBlock.Append(exc._partiallyComputedNode);
  931.                             if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
  932.                                 throw exc;
  933.                         }
  934.                     }
  935.                 }
  936.                 catch (RecoveryTokenException exc) {
  937.                     if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) {
  938.                         exc._partiallyComputedNode = codeBlock;
  939.                         throw exc;
  940.                     }
  941.                 }
  942.             }
  943.             finally {
  944.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  945.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  946.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  947.             }
  948.            
  949.             closingBraceContext = this.currentToken.Clone();
  950.             // update the block context
  951.             codeBlock.context.UpdateWith(this.currentToken);
  952.             GetNextToken();
  953.             return codeBlock;
  954.         }
  955.        
  956.         //---------------------------------------------------------------------------------------
  957.         // ParseVariableStatement
  958.         //
  959.         // VariableStatement :
  960.         // ('var' | 'const') VariableDeclarationList
  961.         //
  962.         // VariableDeclarationList :
  963.         // VariableDeclaration |
  964.         // VariableDeclaration ',' VariableDeclarationList
  965.         //
  966.         // VariableDeclaration :
  967.         // Identifier Type Initializer
  968.         //
  969.         // Type :
  970.         // <empty> |
  971.         // ':' TypeExpression
  972.         //
  973.         // Initializer :
  974.         // <empty> |
  975.         // '=' AssignmentExpression
  976.         //---------------------------------------------------------------------------------------
  977.         private AST ParseVariableStatement(FieldAttributes visibility, CustomAttributeList customAttributes, JSToken kind)
  978.         {
  979.             Block varList = new Block(this.currentToken.Clone());
  980.             bool single = true;
  981.             AST vdecl = null;
  982.            
  983.             for (;;) {
  984.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfLineToken);
  985.                 try {
  986.                     vdecl = ParseIdentifierInitializer(JSToken.None, visibility, customAttributes, kind);
  987.                 }
  988.                 catch (RecoveryTokenException exc) {
  989.                     // an exception is passing by, possibly bringing some info, save the info if any
  990.                     if (exc._partiallyComputedNode != null) {
  991.                         if (!single) {
  992.                             varList.Append(exc._partiallyComputedNode);
  993.                             varList.context.UpdateWith(exc._partiallyComputedNode.context);
  994.                             exc._partiallyComputedNode = varList;
  995.                         }
  996.                     }
  997.                     if (IndexOfToken(NoSkipTokenSet.s_EndOfLineToken, exc) == -1)
  998.                         throw exc;
  999.                     else {
  1000.                         if (single)
  1001.                             vdecl = exc._partiallyComputedNode;
  1002.                     }
  1003.                 }
  1004.                 finally {
  1005.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfLineToken);
  1006.                 }
  1007.                
  1008.                 if (JSToken.Semicolon == this.currentToken.token || JSToken.RightCurly == this.currentToken.token) {
  1009.                     if (JSToken.Semicolon == this.currentToken.token) {
  1010.                         vdecl.context.UpdateWith(this.currentToken);
  1011.                         GetNextToken();
  1012.                     }
  1013.                     break;
  1014.                 }
  1015.                 else if (JSToken.Comma == this.currentToken.token) {
  1016.                     single = false;
  1017.                     varList.Append(vdecl);
  1018.                     continue;
  1019.                 }
  1020.                 else if (this.scanner.GotEndOfLine()) {
  1021.                     break;
  1022.                 }
  1023.                 else {
  1024.                     // assume the variable statement was terminated and move on
  1025.                     ReportError(JSError.NoSemicolon, true);
  1026.                     break;
  1027.                 }
  1028.             }
  1029.            
  1030.             if (single)
  1031.                 return vdecl;
  1032.             else {
  1033.                 varList.Append(vdecl);
  1034.                 varList.context.UpdateWith(vdecl.context);
  1035.                 return varList;
  1036.             }
  1037.         }
  1038.        
  1039.         //---------------------------------------------------------------------------------------
  1040.         // ParseIdentifierInitializer
  1041.         //
  1042.         // Does the real work of parsing a single variable declaration.
  1043.         // inToken is JSToken.In whenever the potential expression that initialize a variable
  1044.         // cannot contain an 'in', as in the for statement. inToken is JSToken.None otherwise
  1045.         //---------------------------------------------------------------------------------------
  1046.         private AST ParseIdentifierInitializer(JSToken inToken, FieldAttributes visibility, CustomAttributeList customAttributes, JSToken kind)
  1047.         {
  1048.             Lookup id = null;
  1049.             TypeExpression typeExpr = null;
  1050.             AST assignmentExpr = null;
  1051.             RecoveryTokenException except = null;
  1052.            
  1053.             GetNextToken();
  1054.             if (JSToken.Identifier != this.currentToken.token) {
  1055.                 string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  1056.                 if (null != identifier) {
  1057.                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  1058.                     id = new Lookup(identifier, this.currentToken.Clone());
  1059.                 }
  1060.                 else {
  1061.                     // make up an identifier and keep going; life goes on...
  1062.                     ReportError(JSError.NoIdentifier);
  1063.                     id = new Lookup("#_Missing Identifier_#" + s_cDummyName++, CurrentPositionContext());
  1064.                 }
  1065.             }
  1066.             else
  1067.                 id = new Lookup(this.scanner.GetIdentifier(), this.currentToken.Clone());
  1068.             GetNextToken();
  1069.             Context context = id.context.Clone();
  1070.            
  1071.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
  1072.             try {
  1073.                 if (JSToken.Colon == this.currentToken.token) {
  1074.                     try {
  1075.                         typeExpr = ParseTypeExpression();
  1076.                     }
  1077.                     catch (RecoveryTokenException exc) {
  1078.                         typeExpr = (TypeExpression)exc._partiallyComputedNode;
  1079.                         throw exc;
  1080.                     }
  1081.                     finally {
  1082.                         if (null != typeExpr)
  1083.                             context.UpdateWith(typeExpr.context);
  1084.                     }
  1085.                 }
  1086.                
  1087.                 if (JSToken.Assign == this.currentToken.token || JSToken.Equal == this.currentToken.token) {
  1088.                     if (JSToken.Equal == this.currentToken.token)
  1089.                         ReportError(JSError.NoEqual, true);
  1090.                     GetNextToken();
  1091.                     try {
  1092.                         assignmentExpr = ParseExpression(true, inToken);
  1093.                     }
  1094.                     catch (RecoveryTokenException exc) {
  1095.                         assignmentExpr = exc._partiallyComputedNode;
  1096.                         throw exc;
  1097.                     }
  1098.                     finally {
  1099.                         if (null != assignmentExpr)
  1100.                             context.UpdateWith(assignmentExpr.context);
  1101.                     }
  1102.                 }
  1103.             }
  1104.             catch (RecoveryTokenException exc) {
  1105.                 // If the exception is in the vardecl no-skip set then we successfully
  1106.                 // recovered to the end of the declaration and can just return
  1107.                 // normally. Otherwise we re-throw after constructing the partial result.
  1108.                 if (IndexOfToken(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet, exc) == -1)
  1109.                     except = exc;
  1110.             }
  1111.             finally {
  1112.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
  1113.             }
  1114.            
  1115.             AST result = null;
  1116.             if (JSToken.Var == kind)
  1117.                 result = new VariableDeclaration(context, id, typeExpr, assignmentExpr, visibility, customAttributes);
  1118.             else {
  1119.                 if (assignmentExpr == null)
  1120.                     ForceReportInfo(JSError.NoEqual);
  1121.                 result = new Constant(context, id, typeExpr, assignmentExpr, visibility, customAttributes);
  1122.             }
  1123.             if (customAttributes != null)
  1124.                 customAttributes.SetTarget(result);
  1125.             if (null != except) {
  1126.                 except._partiallyComputedNode = result;
  1127.                 throw except;
  1128.             }
  1129.             return result;
  1130.         }
  1131.        
  1132.         //---------------------------------------------------------------------------------------
  1133.         // ParseQualifiedIdentifier
  1134.         //
  1135.         // QualifiedIdentifier :
  1136.         // 'double' | 'float' | 'int' | 'long' | Scope Identifier
  1137.         //
  1138.         // Scope
  1139.         // <empty> |
  1140.         // Identifier '.' Scope
  1141.         //
  1142.         // The argument error is passed by the caller and it is used in error situation
  1143.         // to provide better error information. The caller knows in which context this
  1144.         // qualified identifier is parsed (i.e. var x : QualifiedIdentifier vs.
  1145.         // import QualifiedIdentifier)
  1146.         // On error condition this method may return null. Regardless of its return value, though,
  1147.         // this method will always be pointing to the next token and no error token will be set.
  1148.         //---------------------------------------------------------------------------------------
  1149.         private AST ParseQualifiedIdentifier(JSError error)
  1150.         {
  1151.             GetNextToken();
  1152.             AST qualid = null;
  1153.             string identifier = null;
  1154.             Context idContext = this.currentToken.Clone();
  1155.             if (JSToken.Identifier != this.currentToken.token) {
  1156.                 identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  1157.                 if (null != identifier) {
  1158.                     switch (this.currentToken.token) {
  1159.                         case JSToken.Boolean:
  1160.                         case JSToken.Byte:
  1161.                         case JSToken.Char:
  1162.                         case JSToken.Double:
  1163.                         case JSToken.Float:
  1164.                         case JSToken.Int:
  1165.                         case JSToken.Long:
  1166.                         case JSToken.Short:
  1167.                         case JSToken.Void:
  1168.                             break;
  1169.                         default:
  1170.                             ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  1171.                             break;
  1172.                     }
  1173.                     qualid = new Lookup(identifier, idContext);
  1174.                 }
  1175.                 else {
  1176.                     ReportError(error, true);
  1177.                     SkipTokensAndThrow();
  1178.                     // this will always throw
  1179.                 }
  1180.             }
  1181.             else {
  1182.                 qualid = new Lookup(this.scanner.GetIdentifier(), idContext);
  1183.             }
  1184.             GetNextToken();
  1185.             if (JSToken.AccessField == this.currentToken.token)
  1186.                 qualid = ParseScopeSequence(qualid, error);
  1187.            
  1188.             return qualid;
  1189.         }
  1190.        
  1191.         //---------------------------------------------------------------------------------------
  1192.         // ParseScopeSequence
  1193.         //
  1194.         // Scope
  1195.         // <empty> |
  1196.         // Identifier '.' Scope
  1197.         //
  1198.         // The argument error is passed by the caller and it is used in error situation
  1199.         // to provide better error information. The caller knows in which context this
  1200.         // qualified identifier is parsed (i.e. var x : QualifiedIdentifier vs.
  1201.         // import QualifiedIdentifier)
  1202.         // This function is called after a 'JSToken.Identifier JSToken.AccessField' sequence
  1203.         // has been processed and the whole scope production has to be returned
  1204.         //---------------------------------------------------------------------------------------
  1205.         private AST ParseScopeSequence(AST qualid, JSError error)
  1206.         {
  1207.             ConstantWrapper id = null;
  1208.             string identifier = null;
  1209.             do {
  1210.                 GetNextToken();
  1211.                 // move after '.'
  1212.                 if (JSToken.Identifier != this.currentToken.token) {
  1213.                     identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  1214.                     if (null != identifier) {
  1215.                         ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  1216.                         id = new ConstantWrapper(identifier, this.currentToken.Clone());
  1217.                     }
  1218.                     else {
  1219.                         ReportError(error, true);
  1220.                         SkipTokensAndThrow(qualid);
  1221.                         // this will always throw
  1222.                     }
  1223.                 }
  1224.                 else
  1225.                     id = new ConstantWrapper(this.scanner.GetIdentifier(), this.currentToken.Clone());
  1226.                 qualid = new Member(qualid.context.CombineWith(this.currentToken), qualid, id);
  1227.                 GetNextToken();
  1228.             }
  1229.             while (JSToken.AccessField == this.currentToken.token);
  1230.            
  1231.             return qualid;
  1232.         }
  1233.        
  1234.         //---------------------------------------------------------------------------------------
  1235.         // ParseTypeExpression
  1236.         //
  1237.         // TypeExpression :
  1238.         // QualifiedIdentifier |
  1239.         // TypeExpression <no line break> '[' ']'
  1240.         //
  1241.         //--------------------------------------------------------------------------------------
  1242.         private TypeExpression ParseTypeExpression()
  1243.         {
  1244.             AST typeId = null;
  1245.             try {
  1246.                 typeId = ParseQualifiedIdentifier(JSError.NeedType);
  1247.             }
  1248.             catch (RecoveryTokenException exc) {
  1249.                 if (exc._partiallyComputedNode != null) {
  1250.                     exc._partiallyComputedNode = new TypeExpression(exc._partiallyComputedNode);
  1251.                 }
  1252.                 throw exc;
  1253.             }
  1254.             TypeExpression type = new TypeExpression(typeId);
  1255.             if (type != null) {
  1256.                 while (!this.scanner.GotEndOfLine() && JSToken.LeftBracket == this.currentToken.token) {
  1257.                     GetNextToken();
  1258.                     int rank = 1;
  1259.                     while (JSToken.Comma == this.currentToken.token) {
  1260.                         GetNextToken();
  1261.                         rank++;
  1262.                     }
  1263.                     if (JSToken.RightBracket != this.currentToken.token)
  1264.                         ReportError(JSError.NoRightBracket);
  1265.                     GetNextToken();
  1266.                     if (type.isArray)
  1267.                         type = new TypeExpression(type);
  1268.                     type.isArray = true;
  1269.                     type.rank = rank;
  1270.                 }
  1271.             }
  1272.             return type;
  1273.         }
  1274.        
  1275.         //---------------------------------------------------------------------------------------
  1276.         // ParseIfStatement
  1277.         //
  1278.         // IfStatement :
  1279.         // 'if' '(' Expression ')' Statement ElseStatement
  1280.         //
  1281.         // ElseStatement :
  1282.         // <empty> |
  1283.         // 'else' Statement
  1284.         //---------------------------------------------------------------------------------------
  1285.         private If ParseIfStatement()
  1286.         {
  1287.             Context ifCtx = this.currentToken.Clone();
  1288.             AST condition = null;
  1289.             AST trueBranch = null;
  1290.             AST falseBranch = null;
  1291.            
  1292.             this.blockType.Add(BlockType.Block);
  1293.             try {
  1294.                 // parse condition
  1295.                 GetNextToken();
  1296.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1297.                 try {
  1298.                     if (JSToken.LeftParen != this.currentToken.token)
  1299.                         ReportError(JSError.NoLeftParen);
  1300.                     GetNextToken();
  1301.                     condition = ParseExpression();
  1302.                    
  1303.                     // parse statements
  1304.                     if (JSToken.RightParen != this.currentToken.token) {
  1305.                         ifCtx.UpdateWith(condition.context);
  1306.                         ReportError(JSError.NoRightParen);
  1307.                     }
  1308.                     else
  1309.                         ifCtx.UpdateWith(this.currentToken);
  1310.                    
  1311.                     GetNextToken();
  1312.                 }
  1313.                 catch (RecoveryTokenException exc) {
  1314.                     // make up an if condition
  1315.                     if (exc._partiallyComputedNode != null)
  1316.                         condition = exc._partiallyComputedNode;
  1317.                     else
  1318.                         condition = new ConstantWrapper(true, CurrentPositionContext());
  1319.                    
  1320.                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  1321.                         exc._partiallyComputedNode = null;
  1322.                         // really not much to pass up
  1323.                         // the if condition was so bogus we do not have a chance to make an If node, give up
  1324.                         throw exc;
  1325.                     }
  1326.                     else {
  1327.                         if (exc._token == JSToken.RightParen)
  1328.                             GetNextToken();
  1329.                     }
  1330.                 }
  1331.                 finally {
  1332.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1333.                 }
  1334.                
  1335.                 if (condition is Assign)
  1336.                     condition.context.HandleError(JSError.SuspectAssignment);
  1337.                
  1338.                 if (JSToken.Semicolon == this.currentToken.token)
  1339.                     ForceReportInfo(JSError.SuspectSemicolon);
  1340.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_IfBodyNoSkipTokenSet);
  1341.                 try {
  1342.                     trueBranch = ParseStatement();
  1343.                 }
  1344.                 catch (RecoveryTokenException exc) {
  1345.                     // make up a block for the if part
  1346.                     if (exc._partiallyComputedNode != null)
  1347.                         trueBranch = exc._partiallyComputedNode;
  1348.                     else
  1349.                         trueBranch = new Block(CurrentPositionContext());
  1350.                     if (IndexOfToken(NoSkipTokenSet.s_IfBodyNoSkipTokenSet, exc) == -1) {
  1351.                         // we have to pass the exception to someone else, make as much as you can from the if
  1352.                         exc._partiallyComputedNode = new If(ifCtx, condition, trueBranch, falseBranch);
  1353.                         throw exc;
  1354.                     }
  1355.                 }
  1356.                 finally {
  1357.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_IfBodyNoSkipTokenSet);
  1358.                 }
  1359.                
  1360.                 // parse else, if any
  1361.                 if (JSToken.Else == this.currentToken.token) {
  1362.                     GetNextToken();
  1363.                     if (JSToken.Semicolon == this.currentToken.token)
  1364.                         ForceReportInfo(JSError.SuspectSemicolon);
  1365.                     try {
  1366.                         falseBranch = ParseStatement();
  1367.                     }
  1368.                     catch (RecoveryTokenException exc) {
  1369.                         // make up a block for the else part
  1370.                         if (exc._partiallyComputedNode != null)
  1371.                             falseBranch = exc._partiallyComputedNode;
  1372.                         else
  1373.                             falseBranch = new Block(CurrentPositionContext());
  1374.                         exc._partiallyComputedNode = new If(ifCtx, condition, trueBranch, falseBranch);
  1375.                         throw exc;
  1376.                     }
  1377.                 }
  1378.             }
  1379.             finally {
  1380.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  1381.             }
  1382.            
  1383.             return new If(ifCtx, condition, trueBranch, falseBranch);
  1384.         }
  1385.        
  1386.         //---------------------------------------------------------------------------------------
  1387.         // ParseForStatement
  1388.         //
  1389.         // ForStatement :
  1390.         // 'for' '(' OptionalExpressionNoIn ';' OptionalExpression ';' OptionalExpression ')'
  1391.         // 'for' '(' 'var' VariableDeclarationListNoIn ';' OptionalExpression ';' OptionalExpression ')'
  1392.         // 'for' '(' LeftHandSideExpression 'in' Expression')'
  1393.         // 'for' '(' 'var' Identifier OptionalInitializerNoIn 'in' Expression')'
  1394.         //
  1395.         // OptionalExpressionNoIn :
  1396.         // <empty> |
  1397.         // ExpressionNoIn // same as Expression but does not process 'in' as an operator
  1398.         //
  1399.         // OptionalInitializerNoIn :
  1400.         // <empty> |
  1401.         // InitializerNoIn // same as initializer but does not process 'in' as an operator
  1402.         //---------------------------------------------------------------------------------------
  1403.         private AST ParseForStatement()
  1404.         {
  1405.             this.blockType.Add(BlockType.Loop);
  1406.             AST forNode = null;
  1407.             try {
  1408.                 Context forCtx = this.currentToken.Clone();
  1409.                 GetNextToken();
  1410.                 if (JSToken.LeftParen != this.currentToken.token)
  1411.                     ReportError(JSError.NoLeftParen);
  1412.                 GetNextToken();
  1413.                 bool isForIn = false;
  1414.                 bool recoveryInForIn = false;
  1415.                 AST lhs = null;
  1416.                 AST initializer = null;
  1417.                 AST condOrColl = null;
  1418.                 AST increment = null;
  1419.                
  1420.                 try {
  1421.                     if (JSToken.Var == this.currentToken.token) {
  1422.                         isForIn = true;
  1423.                         initializer = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var);
  1424.                        
  1425.                         // a list of variable initializers is allowed only in a for(;;)
  1426.                         AST var = null;
  1427.                         while (JSToken.Comma == this.currentToken.token) {
  1428.                             isForIn = false;
  1429.                             var = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var);
  1430.                             initializer = new Comma(initializer.context.CombineWith(var.context), initializer, var);
  1431.                         }
  1432.                        
  1433.                         // if it could still be a for..in, now it's time to get the 'in'
  1434.                         if (isForIn) {
  1435.                             if (JSToken.In == this.currentToken.token) {
  1436.                                 GetNextToken();
  1437.                                 condOrColl = ParseExpression();
  1438.                             }
  1439.                             else
  1440.                                 isForIn = false;
  1441.                         }
  1442.                     }
  1443.                     else {
  1444.                         if (JSToken.Semicolon != this.currentToken.token) {
  1445.                             bool isLHS;
  1446.                             initializer = ParseUnaryExpression(out isLHS, false);
  1447.                             if (isLHS && JSToken.In == this.currentToken.token) {
  1448.                                 isForIn = true;
  1449.                                 lhs = initializer;
  1450.                                 initializer = null;
  1451.                                 GetNextToken();
  1452.                                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1453.                                 try {
  1454.                                     condOrColl = ParseExpression();
  1455.                                 }
  1456.                                 catch (RecoveryTokenException exc) {
  1457.                                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  1458.                                         exc._partiallyComputedNode = null;
  1459.                                         throw exc;
  1460.                                     }
  1461.                                     else {
  1462.                                         if (exc._partiallyComputedNode == null)
  1463.                                             condOrColl = new ConstantWrapper(true, CurrentPositionContext());
  1464.                                         else
  1465.                                             // what could we put here?
  1466.                                             condOrColl = exc._partiallyComputedNode;
  1467.                                     }
  1468.                                     if (exc._token == JSToken.RightParen) {
  1469.                                         GetNextToken();
  1470.                                         recoveryInForIn = true;
  1471.                                     }
  1472.                                 }
  1473.                                 finally {
  1474.                                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1475.                                 }
  1476.                             }
  1477.                             else
  1478.                                 initializer = ParseExpression(initializer, false, isLHS, JSToken.In);
  1479.                         }
  1480.                         else
  1481.                             initializer = new EmptyLiteral(CurrentPositionContext());
  1482.                     }
  1483.                 }
  1484.                 catch (RecoveryTokenException exc) {
  1485.                     // error is too early abort for
  1486.                     exc._partiallyComputedNode = null;
  1487.                     throw exc;
  1488.                 }
  1489.                
  1490.                 // at this point we know whether or not is a for..in
  1491.                 if (isForIn) {
  1492.                     if (!recoveryInForIn) {
  1493.                         if (JSToken.RightParen != this.currentToken.token)
  1494.                             ReportError(JSError.NoRightParen);
  1495.                         forCtx.UpdateWith(this.currentToken);
  1496.                         GetNextToken();
  1497.                     }
  1498.                     AST body = null;
  1499.                     try {
  1500.                         body = ParseStatement();
  1501.                     }
  1502.                     catch (RecoveryTokenException exc) {
  1503.                         if (exc._partiallyComputedNode == null)
  1504.                             body = new Block(CurrentPositionContext());
  1505.                         else
  1506.                             body = exc._partiallyComputedNode;
  1507.                         exc._partiallyComputedNode = new ForIn(forCtx, lhs, initializer, condOrColl, body);
  1508.                         throw exc;
  1509.                     }
  1510.                     forNode = new ForIn(forCtx, lhs, initializer, condOrColl, body);
  1511.                 }
  1512.                 else {
  1513.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1514.                     try {
  1515.                         if (JSToken.Semicolon != this.currentToken.token) {
  1516.                             ReportError(JSError.NoSemicolon);
  1517.                             if (JSToken.Colon == this.currentToken.token) {
  1518.                                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
  1519.                                 try {
  1520.                                     SkipTokensAndThrow();
  1521.                                 }
  1522.                                 catch (RecoveryTokenException exc) {
  1523.                                     if (JSToken.Semicolon == this.currentToken.token)
  1524.                                         this.errorToken = null;
  1525.                                     else
  1526.                                         throw exc;
  1527.                                 }
  1528.                                 finally {
  1529.                                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
  1530.                                 }
  1531.                             }
  1532.                         }
  1533.                         GetNextToken();
  1534.                         if (JSToken.Semicolon != this.currentToken.token) {
  1535.                             condOrColl = ParseExpression();
  1536.                             if (JSToken.Semicolon != this.currentToken.token)
  1537.                                 ReportError(JSError.NoSemicolon);
  1538.                         }
  1539.                         else
  1540.                             condOrColl = new ConstantWrapper(true, CurrentPositionContext());
  1541.                         GetNextToken();
  1542.                         if (JSToken.RightParen != this.currentToken.token)
  1543.                             increment = ParseExpression();
  1544.                         else
  1545.                             increment = new EmptyLiteral(CurrentPositionContext());
  1546.                         if (JSToken.RightParen != this.currentToken.token)
  1547.                             ReportError(JSError.NoRightParen);
  1548.                         forCtx.UpdateWith(this.currentToken);
  1549.                         GetNextToken();
  1550.                     }
  1551.                     catch (RecoveryTokenException exc) {
  1552.                         if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  1553.                             exc._partiallyComputedNode = null;
  1554.                             throw exc;
  1555.                         }
  1556.                         else {
  1557.                             // discard any partial info, just genrate empty condition and increment and keep going
  1558.                             exc._partiallyComputedNode = null;
  1559.                             if (condOrColl == null)
  1560.                                 condOrColl = new ConstantWrapper(true, CurrentPositionContext());
  1561.                             if (increment == null)
  1562.                                 increment = new EmptyLiteral(CurrentPositionContext());
  1563.                         }
  1564.                         if (exc._token == JSToken.RightParen) {
  1565.                             GetNextToken();
  1566.                         }
  1567.                     }
  1568.                     finally {
  1569.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1570.                     }
  1571.                     AST body = null;
  1572.                     try {
  1573.                         body = ParseStatement();
  1574.                     }
  1575.                     catch (RecoveryTokenException exc) {
  1576.                         if (exc._partiallyComputedNode == null)
  1577.                             body = new Block(CurrentPositionContext());
  1578.                         else
  1579.                             body = exc._partiallyComputedNode;
  1580.                         exc._partiallyComputedNode = new For(forCtx, initializer, condOrColl, increment, body);
  1581.                         throw exc;
  1582.                     }
  1583.                     forNode = new For(forCtx, initializer, condOrColl, increment, body);
  1584.                 }
  1585.             }
  1586.             finally {
  1587.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  1588.             }
  1589.            
  1590.             return forNode;
  1591.         }
  1592.        
  1593.         //---------------------------------------------------------------------------------------
  1594.         // ParseDoStatement
  1595.         //
  1596.         // DoStatement:
  1597.         // 'do' Statement 'while' '(' Expression ')'
  1598.         //---------------------------------------------------------------------------------------
  1599.         private DoWhile ParseDoStatement()
  1600.         {
  1601.             Context doCtx = null;
  1602.             // this.currentToken.Clone();
  1603.             AST body = null;
  1604.             AST condition = null;
  1605.             this.blockType.Add(BlockType.Loop);
  1606.             try {
  1607.                 GetNextToken();
  1608.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet);
  1609.                 try {
  1610.                     body = ParseStatement();
  1611.                 }
  1612.                 catch (RecoveryTokenException exc) {
  1613.                     // make up a block for the do while
  1614.                     if (exc._partiallyComputedNode != null)
  1615.                         body = exc._partiallyComputedNode;
  1616.                     else
  1617.                         body = new Block(CurrentPositionContext());
  1618.                     if (IndexOfToken(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet, exc) == -1) {
  1619.                         // we have to pass the exception to someone else, make as much as you can from the 'do while'
  1620.                         exc._partiallyComputedNode = new DoWhile(CurrentPositionContext(), body, new ConstantWrapper(false, CurrentPositionContext()));
  1621.                         throw exc;
  1622.                     }
  1623.                 }
  1624.                 finally {
  1625.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet);
  1626.                 }
  1627.                 if (JSToken.While != this.currentToken.token) {
  1628.                     ReportError(JSError.NoWhile);
  1629.                 }
  1630.                 doCtx = this.currentToken.Clone();
  1631.                 GetNextToken();
  1632.                 if (JSToken.LeftParen != this.currentToken.token) {
  1633.                     ReportError(JSError.NoLeftParen);
  1634.                 }
  1635.                 GetNextToken();
  1636.                 // catch here so the body of the do_while is not thrown away
  1637.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1638.                 try {
  1639.                     condition = ParseExpression();
  1640.                     if (JSToken.RightParen != this.currentToken.token) {
  1641.                         ReportError(JSError.NoRightParen);
  1642.                         doCtx.UpdateWith(condition.context);
  1643.                     }
  1644.                     else
  1645.                         doCtx.UpdateWith(this.currentToken);
  1646.                     GetNextToken();
  1647.                 }
  1648.                 catch (RecoveryTokenException exc) {
  1649.                     // make up a condition
  1650.                     if (exc._partiallyComputedNode != null)
  1651.                         condition = exc._partiallyComputedNode;
  1652.                     else
  1653.                         condition = new ConstantWrapper(false, CurrentPositionContext());
  1654.                    
  1655.                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  1656.                         exc._partiallyComputedNode = new DoWhile(doCtx, body, condition);
  1657.                         throw exc;
  1658.                     }
  1659.                     else {
  1660.                         if (JSToken.RightParen == this.currentToken.token)
  1661.                             GetNextToken();
  1662.                     }
  1663.                 }
  1664.                 finally {
  1665.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1666.                 }
  1667.                 if (JSToken.Semicolon == this.currentToken.token) {
  1668.                     // JScript 5 allowed statements like
  1669.                     // do{print(++x)}while(x<10) print(0)
  1670.                     // even though that does not strictly follow the automatic semicolon insertion
  1671.                     // rules for the required semi after the while(). For backwards compatibility
  1672.                     // we should continue to support this.
  1673.                     doCtx.UpdateWith(this.currentToken);
  1674.                     GetNextToken();
  1675.                 }
  1676.                
  1677.             }
  1678.             finally {
  1679.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  1680.             }
  1681.            
  1682.             return new DoWhile(doCtx, body, condition);
  1683.         }
  1684.        
  1685.         //---------------------------------------------------------------------------------------
  1686.         // ParseWhileStatement
  1687.         //
  1688.         // WhileStatement :
  1689.         // 'while' '(' Expression ')' Statement
  1690.         //---------------------------------------------------------------------------------------
  1691.         private While ParseWhileStatement()
  1692.         {
  1693.             Context whileCtx = this.currentToken.Clone();
  1694.             AST condition = null;
  1695.             AST body = null;
  1696.             this.blockType.Add(BlockType.Loop);
  1697.             try {
  1698.                 GetNextToken();
  1699.                 if (JSToken.LeftParen != this.currentToken.token) {
  1700.                     ReportError(JSError.NoLeftParen);
  1701.                 }
  1702.                 GetNextToken();
  1703.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1704.                 try {
  1705.                     condition = ParseExpression();
  1706.                     if (JSToken.RightParen != this.currentToken.token) {
  1707.                         ReportError(JSError.NoRightParen);
  1708.                         whileCtx.UpdateWith(condition.context);
  1709.                     }
  1710.                     else
  1711.                         whileCtx.UpdateWith(this.currentToken);
  1712.                    
  1713.                     GetNextToken();
  1714.                 }
  1715.                 catch (RecoveryTokenException exc) {
  1716.                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  1717.                         // abort the while there is really no much to do here
  1718.                         exc._partiallyComputedNode = null;
  1719.                         throw exc;
  1720.                     }
  1721.                     else {
  1722.                         // make up a condition
  1723.                         if (exc._partiallyComputedNode != null)
  1724.                             condition = exc._partiallyComputedNode;
  1725.                         else
  1726.                             condition = new ConstantWrapper(false, CurrentPositionContext());
  1727.                        
  1728.                         if (JSToken.RightParen == this.currentToken.token)
  1729.                             GetNextToken();
  1730.                     }
  1731.                 }
  1732.                 finally {
  1733.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  1734.                 }
  1735.                
  1736.                 try {
  1737.                     body = ParseStatement();
  1738.                 }
  1739.                 catch (RecoveryTokenException exc) {
  1740.                     if (exc._partiallyComputedNode != null)
  1741.                         body = exc._partiallyComputedNode;
  1742.                     else
  1743.                         body = new Block(CurrentPositionContext());
  1744.                    
  1745.                     exc._partiallyComputedNode = new While(whileCtx, condition, body);
  1746.                     throw exc;
  1747.                 }
  1748.                
  1749.             }
  1750.             finally {
  1751.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  1752.             }
  1753.            
  1754.             return new While(whileCtx, condition, body);
  1755.         }
  1756.        
  1757.         //---------------------------------------------------------------------------------------
  1758.         // ParseContinueStatement
  1759.         //
  1760.         // ContinueStatement :
  1761.         // 'continue' OptionalLabel
  1762.         //
  1763.         // OptionalLabel :
  1764.         // <empty> |
  1765.         // Identifier
  1766.         //
  1767.         // This function may return a null AST under error condition. The caller should handle
  1768.         // that case.
  1769.         // Regardless of error conditions, on exit the parser points to the first token after
  1770.         // the continue statement
  1771.         //---------------------------------------------------------------------------------------
  1772.         private Continue ParseContinueStatement()
  1773.         {
  1774.             Context context = this.currentToken.Clone();
  1775.             int blocks = 0;
  1776.             GetNextToken();
  1777.             string label = null;
  1778.             if (!this.scanner.GotEndOfLine() && (JSToken.Identifier == this.currentToken.token || (label = JSKeyword.CanBeIdentifier(this.currentToken.token)) != null)) {
  1779.                 context.UpdateWith(this.currentToken);
  1780.                 // get the label block
  1781.                 if (null != label)
  1782.                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  1783.                 else
  1784.                     label = this.scanner.GetIdentifier();
  1785.                 object value = this.labelTable[label];
  1786.                 if (null == value) {
  1787.                     // the label does not exist. Continue as if it there was no continue at all
  1788.                     ReportError(JSError.NoLabel, true);
  1789.                     GetNextToken();
  1790.                     return null;
  1791.                     // ignore it
  1792.                 }
  1793.                 else {
  1794.                     blocks = (int)value;
  1795.                     if ((BlockType)this.blockType[blocks] != BlockType.Loop) {
  1796.                         ReportError(JSError.BadContinue, context.Clone(), true);
  1797.                     }
  1798.                     GetNextToken();
  1799.                 }
  1800.             }
  1801.             else {
  1802.                 blocks = this.blockType.Count - 1;
  1803.                 while (blocks >= 0 && (BlockType)this.blockType[blocks] != BlockType.Loop)
  1804.                     blocks--;
  1805.                 if (blocks < 0) {
  1806.                     // the continue is malformed. Continue as if there was no continue at all
  1807.                     ReportError(JSError.BadContinue, context, true);
  1808.                     return null;
  1809.                 }
  1810.             }
  1811.            
  1812.             if (JSToken.Semicolon == this.currentToken.token) {
  1813.                 context.UpdateWith(this.currentToken);
  1814.                 GetNextToken();
  1815.             }
  1816.             else if (JSToken.RightCurly != this.currentToken.token && !this.scanner.GotEndOfLine()) {
  1817.                 ReportError(JSError.NoSemicolon, true);
  1818.             }
  1819.            
  1820.             // must ignore the Finally block
  1821.             int finallyNum = 0;
  1822.             for (int i = blocksint n = this.blockType.Count; i < n; i++)
  1823.                 if ((BlockType)this.blockType[i] == BlockType.Finally) {
  1824.                     blocks++;
  1825.                     finallyNum++;
  1826.                 }
  1827.             if (finallyNum > this.finallyEscaped)
  1828.                 this.finallyEscaped = finallyNum;
  1829.            
  1830.             return new Continue(context, this.blockType.Count - blocks, finallyNum > 0);
  1831.         }
  1832.        
  1833.         //---------------------------------------------------------------------------------------
  1834.         // ParseBreakStatement
  1835.         //
  1836.         // BreakStatement :
  1837.         // 'break' OptionalLabel
  1838.         //
  1839.         // This function may return a null AST under error condition. The caller should handle
  1840.         // that case.
  1841.         // Regardless of error conditions, on exit the parser points to the first token after
  1842.         // the break statement.
  1843.         //---------------------------------------------------------------------------------------
  1844.         private Break ParseBreakStatement()
  1845.         {
  1846.             Context context = this.currentToken.Clone();
  1847.             int blocks = 0;
  1848.             GetNextToken();
  1849.             string label = null;
  1850.             if (!this.scanner.GotEndOfLine() && (JSToken.Identifier == this.currentToken.token || (label = JSKeyword.CanBeIdentifier(this.currentToken.token)) != null)) {
  1851.                 context.UpdateWith(this.currentToken);
  1852.                 // get the label block
  1853.                 if (null != label)
  1854.                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  1855.                 else
  1856.                     label = this.scanner.GetIdentifier();
  1857.                 object value = this.labelTable[label];
  1858.                 if (null == value) {
  1859.                     // as if it was a non label case
  1860.                     ReportError(JSError.NoLabel, true);
  1861.                     GetNextToken();
  1862.                     return null;
  1863.                     // ignore it
  1864.                 }
  1865.                 else {
  1866.                     blocks = (int)value - 1;
  1867.                     // the outer block
  1868.                     Debug.Assert((BlockType)this.blockType[blocks] != BlockType.Finally);
  1869.                     GetNextToken();
  1870.                 }
  1871.             }
  1872.             else {
  1873.                 blocks = this.blockType.Count - 1;
  1874.                 // search for an enclosing loop, if there is no loop it is an error
  1875.                 while (((BlockType)this.blockType[blocks] == BlockType.Block || (BlockType)this.blockType[blocks] == BlockType.Finally) && --blocks >= 0)
  1876.                     ;
  1877.                 --blocks;
  1878.                 if (blocks < 0) {
  1879.                     ReportError(JSError.BadBreak, context, true);
  1880.                     return null;
  1881.                 }
  1882.             }
  1883.            
  1884.             if (JSToken.Semicolon == this.currentToken.token) {
  1885.                 context.UpdateWith(this.currentToken);
  1886.                 GetNextToken();
  1887.             }
  1888.             else if (JSToken.RightCurly != this.currentToken.token && !this.scanner.GotEndOfLine()) {
  1889.                 ReportError(JSError.NoSemicolon, true);
  1890.             }
  1891.            
  1892.             // must ignore the Finally block
  1893.             int finallyNum = 0;
  1894.             for (int i = blocksint n = this.blockType.Count; i < n; i++)
  1895.                 if ((BlockType)this.blockType[i] == BlockType.Finally) {
  1896.                     blocks++;
  1897.                     finallyNum++;
  1898.                 }
  1899.             if (finallyNum > this.finallyEscaped)
  1900.                 this.finallyEscaped = finallyNum;
  1901.            
  1902.             return new Break(context, this.blockType.Count - blocks - 1, finallyNum > 0);
  1903.         }
  1904.        
  1905.         private bool CheckForReturnFromFinally()
  1906.         {
  1907.             int finallyNum = 0;
  1908.             for (int i = this.blockType.Count - 1; i >= 0; i--)
  1909.                 if ((BlockType)this.blockType[i] == BlockType.Finally)
  1910.                     finallyNum++;
  1911.            
  1912.             if (finallyNum > this.finallyEscaped)
  1913.                 this.finallyEscaped = finallyNum;
  1914.            
  1915.             return finallyNum > 0;
  1916.         }
  1917.        
  1918.         //---------------------------------------------------------------------------------------
  1919.         // ParseReturnStatement
  1920.         //
  1921.         // ReturnStatement :
  1922.         // 'return' Expression
  1923.         //
  1924.         // This function may return a null AST under error condition. The caller should handle
  1925.         // that case.
  1926.         // Regardless of error conditions, on exit the parser points to the first token after
  1927.         // the return statement.
  1928.         //---------------------------------------------------------------------------------------
  1929.         private Return ParseReturnStatement()
  1930.         {
  1931.             Context retCtx = this.currentToken.Clone();
  1932.             if (Globals.ScopeStack.Peek() is FunctionScope) {
  1933.                 AST expr = null;
  1934.                 GetNextToken();
  1935.                 if (!this.scanner.GotEndOfLine()) {
  1936.                     if (JSToken.Semicolon != this.currentToken.token && JSToken.RightCurly != this.currentToken.token) {
  1937.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  1938.                         try {
  1939.                             expr = ParseExpression();
  1940.                         }
  1941.                         catch (RecoveryTokenException exc) {
  1942.                             expr = exc._partiallyComputedNode;
  1943.                             if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1) {
  1944.                                 if (expr != null)
  1945.                                     retCtx.UpdateWith(expr.context);
  1946.                                 exc._partiallyComputedNode = new Return(retCtx, expr, CheckForReturnFromFinally());
  1947.                                 throw exc;
  1948.                             }
  1949.                         }
  1950.                         finally {
  1951.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  1952.                         }
  1953.                         if (JSToken.Semicolon != this.currentToken.token && JSToken.RightCurly != this.currentToken.token && !this.scanner.GotEndOfLine()) {
  1954.                             ReportError(JSError.NoSemicolon, true);
  1955.                         }
  1956.                     }
  1957.                     if (JSToken.Semicolon == this.currentToken.token) {
  1958.                         retCtx.UpdateWith(this.currentToken);
  1959.                         GetNextToken();
  1960.                     }
  1961.                     else if (expr != null)
  1962.                         retCtx.UpdateWith(expr.context);
  1963.                 }
  1964.                 return new Return(retCtx, expr, CheckForReturnFromFinally());
  1965.             }
  1966.             else {
  1967.                 // the return is not inside a function, report an error and skip to the next token
  1968.                 ReportError(JSError.BadReturn, retCtx, true);
  1969.                 GetNextToken();
  1970.                 return null;
  1971.             }
  1972.         }
  1973.        
  1974.         //---------------------------------------------------------------------------------------
  1975.         // ParseImportStatement
  1976.         //
  1977.         // ImportStatement :
  1978.         // 'import' QualifiedIdentifier
  1979.         //---------------------------------------------------------------------------------------
  1980.         private Import ParseImportStatement()
  1981.         {
  1982.             Context context = this.currentToken.Clone();
  1983.             AST name = null;
  1984.             try {
  1985.                 name = ParseQualifiedIdentifier(JSError.PackageExpected);
  1986.             }
  1987.             catch (RecoveryTokenException exc) {
  1988.                 // an exception is passing by, mae an Import if possible and rethrow
  1989.                 if (exc._partiallyComputedNode != null) {
  1990.                     exc._partiallyComputedNode = new Import(context, exc._partiallyComputedNode);
  1991.                 }
  1992.             }
  1993.             if (this.currentToken.token != JSToken.Semicolon && !this.scanner.GotEndOfLine())
  1994.                 ReportError(JSError.NoSemicolon, this.currentToken.Clone());
  1995.             return new Import(context, name);
  1996.         }
  1997.        
  1998.         //---------------------------------------------------------------------------------------
  1999.         // ParseWithStatement
  2000.         //
  2001.         // WithStatement :
  2002.         // 'with' '(' Expression ')' Statement
  2003.         //---------------------------------------------------------------------------------------
  2004.         private With ParseWithStatement()
  2005.         {
  2006.             Context withCtx = this.currentToken.Clone();
  2007.             AST obj = null;
  2008.             AST block = null;
  2009.             this.blockType.Add(BlockType.Block);
  2010.             try {
  2011.                 GetNextToken();
  2012.                 if (JSToken.LeftParen != this.currentToken.token)
  2013.                     ReportError(JSError.NoLeftParen);
  2014.                 GetNextToken();
  2015.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2016.                 try {
  2017.                     obj = ParseExpression();
  2018.                     if (JSToken.RightParen != this.currentToken.token) {
  2019.                         withCtx.UpdateWith(obj.context);
  2020.                         ReportError(JSError.NoRightParen);
  2021.                     }
  2022.                     else
  2023.                         withCtx.UpdateWith(this.currentToken);
  2024.                     GetNextToken();
  2025.                 }
  2026.                 catch (RecoveryTokenException exc) {
  2027.                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  2028.                         // give up
  2029.                         exc._partiallyComputedNode = null;
  2030.                         throw exc;
  2031.                     }
  2032.                     else {
  2033.                         if (exc._partiallyComputedNode == null)
  2034.                             obj = new ConstantWrapper(true, CurrentPositionContext());
  2035.                         else
  2036.                             obj = exc._partiallyComputedNode;
  2037.                         withCtx.UpdateWith(obj.context);
  2038.                        
  2039.                         if (exc._token == JSToken.RightParen)
  2040.                             GetNextToken();
  2041.                     }
  2042.                 }
  2043.                 finally {
  2044.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2045.                 }
  2046.                
  2047.                 try {
  2048.                     block = ParseStatement();
  2049.                 }
  2050.                 catch (RecoveryTokenException exc) {
  2051.                     if (exc._partiallyComputedNode == null)
  2052.                         block = new Block(CurrentPositionContext());
  2053.                     else
  2054.                         block = exc._partiallyComputedNode;
  2055.                     exc._partiallyComputedNode = new With(withCtx, obj, block);
  2056.                 }
  2057.             }
  2058.             finally {
  2059.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  2060.             }
  2061.            
  2062.             return new With(withCtx, obj, block);
  2063.         }
  2064.        
  2065.         //---------------------------------------------------------------------------------------
  2066.         // ParseSwitchStatement
  2067.         //
  2068.         // SwitchStatement :
  2069.         // 'switch' '(' Expression ')' '{' CaseBlock '}'
  2070.         //
  2071.         // CaseBlock :
  2072.         // CaseList DefaultCaseClause CaseList
  2073.         //
  2074.         // CaseList :
  2075.         // <empty> |
  2076.         // CaseClause CaseList
  2077.         //
  2078.         // CaseClause :
  2079.         // 'case' Expression ':' OptionalStatements
  2080.         //
  2081.         // DefaultCaseClause :
  2082.         // <empty> |
  2083.         // 'default' ':' OptionalStatements
  2084.         //---------------------------------------------------------------------------------------
  2085.         private AST ParseSwitchStatement()
  2086.         {
  2087.             Context switchCtx = this.currentToken.Clone();
  2088.             AST expr = null;
  2089.             ASTList cases = null;
  2090.             this.blockType.Add(BlockType.Switch);
  2091.             try {
  2092.                 // read switch(expr)
  2093.                 GetNextToken();
  2094.                 if (JSToken.LeftParen != this.currentToken.token)
  2095.                     ReportError(JSError.NoLeftParen);
  2096.                 GetNextToken();
  2097.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2098.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
  2099.                 try {
  2100.                     expr = ParseExpression();
  2101.                    
  2102.                     if (JSToken.RightParen != this.currentToken.token) {
  2103.                         ReportError(JSError.NoRightParen);
  2104.                     }
  2105.                    
  2106.                     GetNextToken();
  2107.                     if (JSToken.LeftCurly != this.currentToken.token) {
  2108.                         ReportError(JSError.NoLeftCurly);
  2109.                     }
  2110.                     GetNextToken();
  2111.                    
  2112.                 }
  2113.                 catch (RecoveryTokenException exc) {
  2114.                     if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1 && IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1) {
  2115.                         // give up
  2116.                         exc._partiallyComputedNode = null;
  2117.                         throw exc;
  2118.                     }
  2119.                     else {
  2120.                         if (exc._partiallyComputedNode == null)
  2121.                             expr = new ConstantWrapper(true, CurrentPositionContext());
  2122.                         else
  2123.                             expr = exc._partiallyComputedNode;
  2124.                        
  2125.                         if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) != -1) {
  2126.                             if (exc._token == JSToken.RightParen)
  2127.                                 GetNextToken();
  2128.                            
  2129.                             if (JSToken.LeftCurly != this.currentToken.token) {
  2130.                                 ReportError(JSError.NoLeftCurly);
  2131.                             }
  2132.                             GetNextToken();
  2133.                         }
  2134.                        
  2135.                     }
  2136.                 }
  2137.                 finally {
  2138.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
  2139.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2140.                 }
  2141.                
  2142.                 // parse the switch body
  2143.                 cases = new ASTList(this.currentToken.Clone());
  2144.                 bool defaultStatement = false;
  2145.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  2146.                 try {
  2147.                     while (JSToken.RightCurly != this.currentToken.token) {
  2148.                         SwitchCase caseClause = null;
  2149.                         AST caseValue = null;
  2150.                         Context caseCtx = this.currentToken.Clone();
  2151.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_CaseNoSkipTokenSet);
  2152.                         try {
  2153.                             if (JSToken.Case == this.currentToken.token) {
  2154.                                 // get the case
  2155.                                 GetNextToken();
  2156.                                 caseValue = ParseExpression();
  2157.                             }
  2158.                             else if (JSToken.Default == this.currentToken.token) {
  2159.                                 // get the default
  2160.                                 if (defaultStatement)
  2161.                                     ReportError(JSError.DupDefault, true);
  2162.                                 else
  2163.                                     // we report an error but we still accept the default
  2164.                                     defaultStatement = true;
  2165.                                 GetNextToken();
  2166.                             }
  2167.                             else {
  2168.                                 // This is an error, there is no case or default. Assume a default was missing and keep going
  2169.                                 defaultStatement = true;
  2170.                                 ReportError(JSError.BadSwitch);
  2171.                             }
  2172.                             if (JSToken.Colon != this.currentToken.token)
  2173.                                 ReportError(JSError.NoColon);
  2174.                            
  2175.                             // read the statements inside the case or default
  2176.                             GetNextToken();
  2177.                         }
  2178.                         catch (RecoveryTokenException exc) {
  2179.                             // right now we can only get here for the 'case' statement
  2180.                             if (IndexOfToken(NoSkipTokenSet.s_CaseNoSkipTokenSet, exc) == -1) {
  2181.                                 // ignore the current case or default
  2182.                                 exc._partiallyComputedNode = null;
  2183.                                 throw exc;
  2184.                             }
  2185.                             else {
  2186.                                 caseValue = exc._partiallyComputedNode;
  2187.                                
  2188.                                 if (exc._token == JSToken.Colon)
  2189.                                     GetNextToken();
  2190.                             }
  2191.                         }
  2192.                         finally {
  2193.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_CaseNoSkipTokenSet);
  2194.                         }
  2195.                        
  2196.                         this.blockType.Add(BlockType.Block);
  2197.                         try {
  2198.                             Block statements = new Block(this.currentToken.Clone());
  2199.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
  2200.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  2201.                             try {
  2202.                                 while (JSToken.RightCurly != this.currentToken.token && JSToken.Case != this.currentToken.token && JSToken.Default != this.currentToken.token) {
  2203.                                     try {
  2204.                                         statements.Append(ParseStatement());
  2205.                                     }
  2206.                                     catch (RecoveryTokenException exc) {
  2207.                                         if (exc._partiallyComputedNode != null) {
  2208.                                             statements.Append(exc._partiallyComputedNode);
  2209.                                             exc._partiallyComputedNode = null;
  2210.                                         }
  2211.                                         if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
  2212.                                             throw exc;
  2213.                                     }
  2214.                                 }
  2215.                             }
  2216.                             catch (RecoveryTokenException exc) {
  2217.                                 if (IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1) {
  2218.                                     if (null == caseValue)
  2219.                                         caseClause = new SwitchCase(caseCtx, statements);
  2220.                                     else
  2221.                                         caseClause = new SwitchCase(caseCtx, caseValue, statements);
  2222.                                     cases.Append(caseClause);
  2223.                                    
  2224.                                     throw exc;
  2225.                                 }
  2226.                             }
  2227.                             finally {
  2228.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  2229.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
  2230.                             }
  2231.                             if (JSToken.RightCurly == this.currentToken.token)
  2232.                                 statements.context.UpdateWith(this.currentToken);
  2233.                             if (null == caseValue) {
  2234.                                 caseCtx.UpdateWith(statements.context);
  2235.                                 caseClause = new SwitchCase(caseCtx, statements);
  2236.                             }
  2237.                             else {
  2238.                                 caseCtx.UpdateWith(statements.context);
  2239.                                 caseClause = new SwitchCase(caseCtx, caseValue, statements);
  2240.                             }
  2241.                             cases.Append(caseClause);
  2242.                         }
  2243.                         finally {
  2244.                             this.blockType.RemoveAt(this.blockType.Count - 1);
  2245.                         }
  2246.                     }
  2247.                 }
  2248.                 catch (RecoveryTokenException exc) {
  2249.                     if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) {
  2250.                         //save what you can a rethrow
  2251.                         switchCtx.UpdateWith(CurrentPositionContext());
  2252.                         exc._partiallyComputedNode = new Switch(switchCtx, expr, cases);
  2253.                         throw exc;
  2254.                     }
  2255.                 }
  2256.                 finally {
  2257.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  2258.                 }
  2259.                 switchCtx.UpdateWith(this.currentToken);
  2260.                 GetNextToken();
  2261.             }
  2262.             finally {
  2263.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  2264.             }
  2265.            
  2266.             return new Switch(switchCtx, expr, cases);
  2267.         }
  2268.        
  2269.         //---------------------------------------------------------------------------------------
  2270.         // ParseThrowStatement
  2271.         //
  2272.         // ThrowStatement :
  2273.         // throw |
  2274.         // throw Expression
  2275.         //---------------------------------------------------------------------------------------
  2276.         private AST ParseThrowStatement()
  2277.         {
  2278.             Context throwCtx = this.currentToken.Clone();
  2279.             GetNextToken();
  2280.             AST operand = null;
  2281.             if (!this.scanner.GotEndOfLine()) {
  2282.                 if (JSToken.Semicolon != this.currentToken.token) {
  2283.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  2284.                     try {
  2285.                         operand = ParseExpression();
  2286.                     }
  2287.                     catch (RecoveryTokenException exc) {
  2288.                         operand = exc._partiallyComputedNode;
  2289.                         if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1) {
  2290.                             if (operand != null)
  2291.                                 exc._partiallyComputedNode = new Throw(throwCtx, exc._partiallyComputedNode);
  2292.                             throw exc;
  2293.                         }
  2294.                     }
  2295.                     finally {
  2296.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  2297.                     }
  2298.                 }
  2299.             }
  2300.            
  2301.             if (operand != null)
  2302.                 throwCtx.UpdateWith(operand.context);
  2303.             return new Throw(throwCtx, operand);
  2304.         }
  2305.        
  2306.         //---------------------------------------------------------------------------------------
  2307.         // ParseTryStatement
  2308.         //
  2309.         // TryStatement :
  2310.         // 'try' Block CatchList Finally
  2311.         //
  2312.         // CatchList :
  2313.         // <empty> |
  2314.         // CatchList Catch
  2315.         //
  2316.         // Catch :
  2317.         // 'catch' '(' Identifier Type ')' Block
  2318.         //
  2319.         // Finally :
  2320.         // <empty> |
  2321.         // 'finally' Block
  2322.         //---------------------------------------------------------------------------------------
  2323.         private AST ParseTryStatement()
  2324.         {
  2325.             Context tryCtx = this.currentToken.Clone();
  2326.             Context tryEndContext = null;
  2327.             AST body = null;
  2328.             AST id = null;
  2329.             AST handler = null;
  2330.             AST finally_block = null;
  2331.             RecoveryTokenException excInFinally = null;
  2332.             TypeExpression type = null;
  2333.             this.blockType.Add(BlockType.Block);
  2334.             try {
  2335.                 bool catchOrFinally = false;
  2336.                 bool foundCatchAll = false;
  2337.                 GetNextToken();
  2338.                 if (JSToken.LeftCurly != this.currentToken.token)
  2339.                     ReportError(JSError.NoLeftCurly);
  2340.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet);
  2341.                 try {
  2342.                     body = ParseBlock(out tryEndContext);
  2343.                 }
  2344.                 catch (RecoveryTokenException exc) {
  2345.                     if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1)
  2346.                         throw exc;
  2347.                     else
  2348.                         // do nothing and just return the containing block, if any
  2349.                         body = exc._partiallyComputedNode;
  2350.                 }
  2351.                 finally {
  2352.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet);
  2353.                 }
  2354.                 while (JSToken.Catch == this.currentToken.token) {
  2355.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_NoTrySkipTokenSet);
  2356.                     try {
  2357.                         if (handler != null) {
  2358.                             body = new Try(tryCtx, body, id, type, handler, null, false, tryEndContext);
  2359.                             id = null;
  2360.                             type = null;
  2361.                             handler = null;
  2362.                         }
  2363.                         catchOrFinally = true;
  2364.                         GetNextToken();
  2365.                         if (JSToken.LeftParen != this.currentToken.token)
  2366.                             ReportError(JSError.NoLeftParen);
  2367.                         GetNextToken();
  2368.                         if (JSToken.Identifier != this.currentToken.token) {
  2369.                             string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  2370.                             if (null != identifier) {
  2371.                                 ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  2372.                                 id = new Lookup(identifier, this.currentToken.Clone());
  2373.                             }
  2374.                             else {
  2375.                                 ReportError(JSError.NoIdentifier);
  2376.                                 id = new Lookup("##Exc##" + s_cDummyName++, CurrentPositionContext());
  2377.                             }
  2378.                         }
  2379.                         else
  2380.                             id = new Lookup(this.scanner.GetIdentifier(), this.currentToken.Clone());
  2381.                         GetNextToken();
  2382.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2383.                         try {
  2384.                             if (JSToken.Colon == this.currentToken.token)
  2385.                                 type = ParseTypeExpression();
  2386.                             else {
  2387.                                 if (foundCatchAll)
  2388.                                     //no point in having another
  2389.                                     ForceReportInfo(id.context, JSError.UnreachableCatch);
  2390.                                 foundCatchAll = true;
  2391.                             }
  2392.                             if (JSToken.RightParen != this.currentToken.token)
  2393.                                 ReportError(JSError.NoRightParen);
  2394.                             GetNextToken();
  2395.                         }
  2396.                         catch (RecoveryTokenException exc) {
  2397.                             if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) {
  2398.                                 exc._partiallyComputedNode = null;
  2399.                                 // rethrow
  2400.                                 throw exc;
  2401.                             }
  2402.                             else {
  2403.                                 type = (TypeExpression)exc._partiallyComputedNode;
  2404.                                 if (this.currentToken.token == JSToken.RightParen)
  2405.                                     GetNextToken();
  2406.                             }
  2407.                         }
  2408.                         finally {
  2409.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
  2410.                         }
  2411.                         if (JSToken.LeftCurly != this.currentToken.token)
  2412.                             ReportError(JSError.NoLeftCurly);
  2413.                         handler = ParseBlock();
  2414.                         tryCtx.UpdateWith(handler.context);
  2415.                     }
  2416.                     catch (RecoveryTokenException exc) {
  2417.                         if (exc._partiallyComputedNode == null)
  2418.                             handler = new Block(CurrentPositionContext());
  2419.                         else
  2420.                             handler = exc._partiallyComputedNode;
  2421.                         if (IndexOfToken(NoSkipTokenSet.s_NoTrySkipTokenSet, exc) == -1) {
  2422.                             Debug.Assert((type == null) ? exc._partiallyComputedNode == null : true);
  2423.                             if (type != null)
  2424.                                 exc._partiallyComputedNode = new Try(tryCtx, body, id, type, handler, null, false, tryEndContext);
  2425.                             throw exc;
  2426.                         }
  2427.                     }
  2428.                     finally {
  2429.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_NoTrySkipTokenSet);
  2430.                     }
  2431.                 }
  2432.                
  2433.                 try {
  2434.                     if (JSToken.Finally == this.currentToken.token) {
  2435.                         GetNextToken();
  2436.                         this.blockType.Add(BlockType.Finally);
  2437.                         try {
  2438.                             finally_block = ParseBlock();
  2439.                             catchOrFinally = true;
  2440.                         }
  2441.                         finally {
  2442.                             this.blockType.RemoveAt(this.blockType.Count - 1);
  2443.                         }
  2444.                         tryCtx.UpdateWith(finally_block.context);
  2445.                     }
  2446.                 }
  2447.                 catch (RecoveryTokenException exc) {
  2448.                     excInFinally = exc;
  2449.                     // thrown later so we can execute code below
  2450.                 }
  2451.                
  2452.                 if (!catchOrFinally) {
  2453.                     ReportError(JSError.NoCatch, true);
  2454.                     finally_block = new Block(CurrentPositionContext());
  2455.                     // make a dummy empty block
  2456.                 }
  2457.             }
  2458.             finally {
  2459.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  2460.             }
  2461.            
  2462.             bool isFinallyEscaped = false;
  2463.             if (this.finallyEscaped > 0) {
  2464.                 this.finallyEscaped--;
  2465.                 isFinallyEscaped = true;
  2466.             }
  2467.             if (excInFinally != null) {
  2468.                 excInFinally._partiallyComputedNode = new Try(tryCtx, body, id, type, handler, finally_block, isFinallyEscaped, tryEndContext);
  2469.                 throw excInFinally;
  2470.             }
  2471.             else
  2472.                 return new Try(tryCtx, body, id, type, handler, finally_block, isFinallyEscaped, tryEndContext);
  2473.         }
  2474.        
  2475.         //---------------------------------------------------------------------------------------
  2476.         // ParseClass
  2477.         //
  2478.         // Class :
  2479.         // 'class' identifier OptionalExtends ClassBody
  2480.         //
  2481.         // Extends :
  2482.         // 'extends' QualifiedIdentifier
  2483.         //
  2484.         //---------------------------------------------------------------------------------------
  2485.         private AST ParseClass(FieldAttributes visibilitySpec, bool isStatic, Context classCtx, bool isAbstract, bool isFinal, CustomAttributeList customAttributes)
  2486.         {
  2487.             AST name = null;
  2488.             AST baseId = null;
  2489.             TypeExpression baseType = null;
  2490.             Block body = null;
  2491.             ArrayList interfaces = new ArrayList();
  2492.            
  2493.             bool isInterface = JSToken.Interface == this.currentToken.token;
  2494.            
  2495.             GetNextToken();
  2496.             if (JSToken.Identifier == this.currentToken.token) {
  2497.                 name = new IdentifierLiteral(this.scanner.GetIdentifier(), this.currentToken.Clone());
  2498.             }
  2499.             else {
  2500.                 ReportError(JSError.NoIdentifier);
  2501.                 if (JSToken.Extends != this.currentToken.token && JSToken.Implements != this.currentToken.token && JSToken.LeftCurly != this.currentToken.token)
  2502.                     SkipTokensAndThrow();
  2503.                 name = new IdentifierLiteral("##Missing Class Name##" + s_cDummyName++, CurrentPositionContext());
  2504.             }
  2505.            
  2506.             GetNextToken();
  2507.             if (JSToken.Extends == this.currentToken.token || JSToken.Implements == this.currentToken.token) {
  2508.                 if (isInterface && JSToken.Extends == this.currentToken.token)
  2509.                     this.currentToken.token = JSToken.Implements;
  2510.                 if (JSToken.Extends == this.currentToken.token) {
  2511.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_ClassExtendsNoSkipTokenSet);
  2512.                     try {
  2513.                         baseId = ParseQualifiedIdentifier(JSError.NeedType);
  2514.                     }
  2515.                     catch (RecoveryTokenException exc) {
  2516.                         if (IndexOfToken(NoSkipTokenSet.s_ClassExtendsNoSkipTokenSet, exc) == -1) {
  2517.                             exc._partiallyComputedNode = null;
  2518.                             throw exc;
  2519.                         }
  2520.                         else {
  2521.                             baseId = exc._partiallyComputedNode;
  2522.                         }
  2523.                     }
  2524.                     finally {
  2525.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ClassExtendsNoSkipTokenSet);
  2526.                     }
  2527.                 }
  2528.                 if (JSToken.Implements == this.currentToken.token) {
  2529.                     do {
  2530.                         AST typeId = null;
  2531.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_ClassImplementsNoSkipTokenSet);
  2532.                         try {
  2533.                             typeId = ParseQualifiedIdentifier(JSError.NeedType);
  2534.                             interfaces.Add(new TypeExpression(typeId));
  2535.                         }
  2536.                         catch (RecoveryTokenException exc) {
  2537.                             if (IndexOfToken(NoSkipTokenSet.s_ClassImplementsNoSkipTokenSet, exc) == -1) {
  2538.                                 exc._partiallyComputedNode = null;
  2539.                                 throw exc;
  2540.                             }
  2541.                             else {
  2542.                                 if (exc._partiallyComputedNode != null)
  2543.                                     interfaces.Add(new TypeExpression(exc._partiallyComputedNode));
  2544.                             }
  2545.                         }
  2546.                         finally {
  2547.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ClassImplementsNoSkipTokenSet);
  2548.                         }
  2549.                     }
  2550.                     while (JSToken.Comma == this.currentToken.token);
  2551.                 }
  2552.             }
  2553.             if (baseId != null)
  2554.                 baseType = new TypeExpression(baseId);
  2555.             if (JSToken.LeftCurly != this.currentToken.token) {
  2556.                 ReportError(JSError.NoLeftCurly);
  2557.             }
  2558.            
  2559.             // make a new state and save the old one
  2560.             ArrayList blockType = this.blockType;
  2561.             this.blockType = new ArrayList(16);
  2562.             SimpleHashtable labelTable = this.labelTable;
  2563.             this.labelTable = new SimpleHashtable(16);
  2564.            
  2565.             Globals.ScopeStack.Push(new ClassScope(name, ((IActivationObject)Globals.ScopeStack.Peek()).GetGlobalScope()));
  2566.             //Give declarations a place to go while building AST
  2567.             TypeExpression[] ifaces;
  2568.             try {
  2569.                 body = ParseClassBody(false, isInterface);
  2570.                 classCtx.UpdateWith(body.context);
  2571.                 ifaces = new TypeExpression[interfaces.Count];
  2572.                 interfaces.CopyTo(ifaces);
  2573.                 Class result = new Class(classCtx, name, baseType, ifaces, body, visibilitySpec, isAbstract, isFinal, isStatic, isInterface,
  2574.                 customAttributes);
  2575.                 if (customAttributes != null)
  2576.                     customAttributes.SetTarget(result);
  2577.                 return result;
  2578.             }
  2579.             catch (RecoveryTokenException exc) {
  2580.                 classCtx.UpdateWith(exc._partiallyComputedNode.context);
  2581.                 ifaces = new TypeExpression[interfaces.Count];
  2582.                 interfaces.CopyTo(ifaces);
  2583.                 exc._partiallyComputedNode = new Class(classCtx, name, baseType, ifaces, (Block)exc._partiallyComputedNode, visibilitySpec, isAbstract, isFinal, isStatic, isInterface,
  2584.                 customAttributes);
  2585.                 if (customAttributes != null)
  2586.                     customAttributes.SetTarget(exc._partiallyComputedNode);
  2587.                 throw exc;
  2588.             }
  2589.             finally {
  2590.                 Globals.ScopeStack.Pop();
  2591.                 this.blockType = blockType;
  2592.                 this.labelTable = labelTable;
  2593.             }
  2594.            
  2595.         }
  2596.        
  2597.         //---------------------------------------------------------------------------------------
  2598.         // ParseClassBody
  2599.         //
  2600.         // ClassBody :
  2601.         // '{' OptionalClassMembers '}'
  2602.         //---------------------------------------------------------------------------------------
  2603.         Block ParseClassBody(bool isEnum, bool isInterface)
  2604.         {
  2605.             this.blockType.Add(BlockType.Block);
  2606.             Block codeBlock = new Block(this.currentToken.Clone());
  2607.             try {
  2608.                 GetNextToken();
  2609.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  2610.                 JSToken[] noSkip = null;
  2611.                 if (isEnum)
  2612.                     noSkip = NoSkipTokenSet.s_EnumBodyNoSkipTokenSet;
  2613.                 else if (isInterface)
  2614.                     noSkip = NoSkipTokenSet.s_InterfaceBodyNoSkipTokenSet;
  2615.                 else
  2616.                     noSkip = NoSkipTokenSet.s_ClassBodyNoSkipTokenSet;
  2617.                 try {
  2618.                     while (JSToken.RightCurly != this.currentToken.token) {
  2619.                         if (JSToken.EndOfFile == this.currentToken.token) {
  2620.                             ReportError(JSError.NoRightCurly, true);
  2621.                             SkipTokensAndThrow();
  2622.                         }
  2623.                         this.noSkipTokenSet.Add(noSkip);
  2624.                         try {
  2625.                             AST classMember = isEnum ? ParseEnumMember() : ParseClassMember(isInterface);
  2626.                             if (classMember != null)
  2627.                                 codeBlock.Append(classMember);
  2628.                         }
  2629.                         catch (RecoveryTokenException exc) {
  2630.                             if (exc._partiallyComputedNode != null)
  2631.                                 codeBlock.Append(exc._partiallyComputedNode);
  2632.                             if (IndexOfToken(noSkip, exc) == -1) {
  2633.                                 exc._partiallyComputedNode = null;
  2634.                                 throw exc;
  2635.                             }
  2636.                         }
  2637.                         finally {
  2638.                             this.noSkipTokenSet.Remove(noSkip);
  2639.                         }
  2640.                     }
  2641.                    
  2642.                 }
  2643.                 catch (RecoveryTokenException exc) {
  2644.                     exc._partiallyComputedNode = codeBlock;
  2645.                     throw exc;
  2646.                 }
  2647.                 finally {
  2648.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  2649.                 }
  2650.                 codeBlock.context.UpdateWith(this.currentToken);
  2651.                 GetNextToken();
  2652.             }
  2653.             finally {
  2654.                 this.blockType.RemoveAt(this.blockType.Count - 1);
  2655.             }
  2656.            
  2657.             return codeBlock;
  2658.         }
  2659.        
  2660.         //---------------------------------------------------------------------------------------
  2661.         // ParseClassMember
  2662.         //
  2663.         // OptionalClassMembers:
  2664.         // ClassMember OptionalClassMembers |
  2665.         // <empty>
  2666.         //
  2667.         // ClassMember :
  2668.         // VariableStatement |
  2669.         // Class |
  2670.         // Enum |
  2671.         // FunctionDeclaration
  2672.         //
  2673.         //---------------------------------------------------------------------------------------
  2674.         private AST ParseClassMember(bool isInterface)
  2675.         {
  2676.             bool parsed = false;
  2677.             // Interface members can be declared public ( as a no-op).
  2678.             if (isInterface && this.currentToken.token == JSToken.Public)
  2679.                 GetNextToken();
  2680.             switch (this.currentToken.token) {
  2681.                 case JSToken.RightCurly:
  2682.                     return null;
  2683.                 case JSToken.Semicolon:
  2684.                     GetNextToken();
  2685.                     return ParseClassMember(isInterface);
  2686.                 case JSToken.Const:
  2687.                 case JSToken.Var:
  2688.                     if (isInterface) {
  2689.                         ReportError(JSError.VarIllegalInInterface, true);
  2690.                         GetNextToken();
  2691.                         SkipTokensAndThrow();
  2692.                     }
  2693.                     return ParseVariableStatement((FieldAttributes)0, null, this.currentToken.token);
  2694.                 case JSToken.Internal:
  2695.                 case JSToken.Public:
  2696.                 case JSToken.Static:
  2697.                 case JSToken.Private:
  2698.                 case JSToken.Protected:
  2699.                 case JSToken.Abstract:
  2700.                 case JSToken.Final:
  2701.                     if (isInterface) {
  2702.                         ReportError(JSError.BadModifierInInterface, true);
  2703.                         GetNextToken();
  2704.                         SkipTokensAndThrow();
  2705.                     }
  2706.                     return ParseAttributes(null, true, true, out parsed);
  2707.                 case JSToken.Interface:
  2708.                     if (isInterface) {
  2709.                         ReportError(JSError.InterfaceIllegalInInterface, true);
  2710.                         GetNextToken();
  2711.                         SkipTokensAndThrow();
  2712.                     }
  2713.                     return ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null);
  2714.                 case JSToken.Class:
  2715.                     if (isInterface) {
  2716.                         ReportError(JSError.SyntaxError, true);
  2717.                         GetNextToken();
  2718.                         SkipTokensAndThrow();
  2719.                     }
  2720.                     return ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null);
  2721.                 case JSToken.Enum:
  2722.                     return ParseEnum((FieldAttributes)0, this.currentToken.Clone(), null);
  2723.                 case JSToken.Function:
  2724.                     return ParseFunction((FieldAttributes)0, false, this.currentToken.Clone(), true, isInterface, false, isInterface, null);
  2725.                 case JSToken.Identifier:
  2726.                     if (isInterface) {
  2727.                         ReportError(JSError.SyntaxError, true);
  2728.                         GetNextToken();
  2729.                         SkipTokensAndThrow();
  2730.                     }
  2731.                     bool bAssign;
  2732.                     bool canBeAttribute = true;
  2733.                     AST ast = ParseUnaryExpression(out bAssign, ref canBeAttribute, false);
  2734.                     if (canBeAttribute) {
  2735.                         ast = ParseAttributes(ast, true, true, out parsed);
  2736.                         if (parsed)
  2737.                             return ast;
  2738.                     }
  2739.                     ReportError(JSError.SyntaxError, ast.context.Clone(), true);
  2740.                     SkipTokensAndThrow();
  2741.                     return null;
  2742.                 case JSToken.Import:
  2743.                     // we'll never be executed, make the compiler happy
  2744.                     // handle common error of using import in class
  2745.                     ReportError(JSError.InvalidImport, true);
  2746.                     try {
  2747.                         ParseImportStatement();
  2748.                     }
  2749.                     catch (RecoveryTokenException) {
  2750.                     }
  2751.                     return null;
  2752.                 case JSToken.Package:
  2753.                     // handle common error of using package in class
  2754.                     Context packageContext = this.currentToken.Clone();
  2755.                     AST statement = ParsePackage(packageContext);
  2756.                     if (statement is Package)
  2757.                         ReportError(JSError.PackageInWrongContext, packageContext, true);
  2758.                     return null;
  2759.                 default:
  2760.                     ReportError(JSError.SyntaxError, true);
  2761.                     GetNextToken();
  2762.                     SkipTokensAndThrow();
  2763.                     return null;
  2764.                 // we'll never be executed, make the compiler happy
  2765.             }
  2766.         }
  2767.        
  2768.         //---------------------------------------------------------------------------------------
  2769.         // ParseEnum
  2770.         //
  2771.         // Enum :
  2772.         // 'enum' identifier [':' baseType] EnumBody (in the guise of ClassBody with a param)
  2773.         //
  2774.         //---------------------------------------------------------------------------------------
  2775.         private AST ParseEnum(FieldAttributes visibilitySpec, Context enumCtx, CustomAttributeList customAttributes)
  2776.         {
  2777.             IdentifierLiteral name = null;
  2778.             AST baseId = null;
  2779.             TypeExpression baseType = null;
  2780.             Block body = null;
  2781.            
  2782.             GetNextToken();
  2783.             if (JSToken.Identifier == this.currentToken.token) {
  2784.                 name = new IdentifierLiteral(this.scanner.GetIdentifier(), this.currentToken.Clone());
  2785.             }
  2786.             else {
  2787.                 ReportError(JSError.NoIdentifier);
  2788.                 if (JSToken.Colon != this.currentToken.token && JSToken.LeftCurly != this.currentToken.token)
  2789.                     SkipTokensAndThrow();
  2790.                 // what the heck is this?
  2791.                 name = new IdentifierLiteral("##Missing Enum Name##" + s_cDummyName++, CurrentPositionContext());
  2792.             }
  2793.            
  2794.             GetNextToken();
  2795.             if (JSToken.Colon == this.currentToken.token) {
  2796.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_EnumBaseTypeNoSkipTokenSet);
  2797.                 try {
  2798.                     baseId = ParseQualifiedIdentifier(JSError.NeedType);
  2799.                 }
  2800.                 catch (RecoveryTokenException exc) {
  2801.                     if (IndexOfToken(NoSkipTokenSet.s_ClassExtendsNoSkipTokenSet, exc) == -1) {
  2802.                         exc._partiallyComputedNode = null;
  2803.                         throw exc;
  2804.                     }
  2805.                     else {
  2806.                         baseId = exc._partiallyComputedNode;
  2807.                     }
  2808.                 }
  2809.                 finally {
  2810.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EnumBaseTypeNoSkipTokenSet);
  2811.                 }
  2812.             }
  2813.             if (baseId != null)
  2814.                 baseType = new TypeExpression(baseId);
  2815.             if (JSToken.LeftCurly != this.currentToken.token)
  2816.                 ReportError(JSError.NoLeftCurly);
  2817.            
  2818.             // make a new state and save the old one
  2819.             ArrayList blockType = this.blockType;
  2820.             this.blockType = new ArrayList(16);
  2821.             SimpleHashtable labelTable = this.labelTable;
  2822.             this.labelTable = new SimpleHashtable(16);
  2823.            
  2824.             Globals.ScopeStack.Push(new ClassScope(name, ((IActivationObject)Globals.ScopeStack.Peek()).GetGlobalScope()));
  2825.             //Give declarations a place to go while building AST
  2826.             try {
  2827.                 body = ParseClassBody(true, false);
  2828.                 enumCtx.UpdateWith(body.context);
  2829.                 EnumDeclaration result = new EnumDeclaration(enumCtx, name, baseType, body, visibilitySpec, customAttributes);
  2830.                 if (customAttributes != null)
  2831.                     customAttributes.SetTarget(result);
  2832.                 return result;
  2833.             }
  2834.             catch (RecoveryTokenException exc) {
  2835.                 enumCtx.UpdateWith(exc._partiallyComputedNode.context);
  2836.                 exc._partiallyComputedNode = new EnumDeclaration(enumCtx, name, baseType, (Block)exc._partiallyComputedNode, visibilitySpec, customAttributes);
  2837.                 if (customAttributes != null)
  2838.                     customAttributes.SetTarget(exc._partiallyComputedNode);
  2839.                 throw exc;
  2840.             }
  2841.             finally {
  2842.                 Globals.ScopeStack.Pop();
  2843.                 this.blockType = blockType;
  2844.                 this.labelTable = labelTable;
  2845.             }
  2846.         }
  2847.        
  2848.         //---------------------------------------------------------------------------------------
  2849.         // ParseEnumMember
  2850.         //
  2851.         // OptionalEnumMembers:
  2852.         // EnumMember ',' OptionalEnumMembers |
  2853.         // <empty>
  2854.         //
  2855.         // EnumMember :
  2856.         // Identifier |
  2857.         // Identifer '=' IntegerLiteral
  2858.         //
  2859.         //---------------------------------------------------------------------------------------
  2860.         private AST ParseEnumMember()
  2861.         {
  2862.             AST ast = null;
  2863.             Lookup memberName = null;
  2864.             AST memberValue = null;
  2865.             switch (this.currentToken.token) {
  2866.                 case JSToken.Semicolon:
  2867.                     GetNextToken();
  2868.                     return ParseEnumMember();
  2869.                 case JSToken.Identifier:
  2870.                     memberName = new Lookup(this.currentToken.Clone());
  2871.                     Context context = this.currentToken.Clone();
  2872.                     GetNextToken();
  2873.                     if (JSToken.Assign == this.currentToken.token) {
  2874.                         GetNextToken();
  2875.                         memberValue = ParseExpression(true);
  2876.                     }
  2877.                     if (JSToken.Comma == this.currentToken.token)
  2878.                         GetNextToken();
  2879.                     else if (JSToken.RightCurly != this.currentToken.token)
  2880.                         ReportError(JSError.NoComma, true);
  2881.                     return new Constant(context, memberName, null, memberValue, FieldAttributes.Public, null);
  2882.                 case JSToken.Var:
  2883.                     // handle common error
  2884.                     ReportError(JSError.NoVarInEnum, true);
  2885.                     GetNextToken();
  2886.                     return ParseEnumMember();
  2887.                 default:
  2888.                     ReportError(JSError.SyntaxError, true);
  2889.                     SkipTokensAndThrow();
  2890.                     return ast;
  2891.                 // will never be executed, but make the C# compiler happy
  2892.             }
  2893.         }
  2894.        
  2895.         private bool GuessIfAbstract()
  2896.         {
  2897.             //
  2898.             // We have a class method declaraction without the "abstract"
  2899.             // attribute and need to know whether to treat it as abstract
  2900.             // for error reporting purposes.
  2901.             //
  2902.             // function bar(); -- clearly abstract, "missing abstract" error
  2903.             // function bar(){ -- clearly concrete, correct
  2904.             // function bar() -- clearly an error, but should it be
  2905.             // "missing abstract" or "missing left curly"?
  2906.             //
  2907.             // In the last case we look what comes next.
  2908.             //
  2909.             // * If it looks like something that would start a function body -- a "var" statement or
  2910.             // an expression for instance -- then we assume that the curly is missing.
  2911.             //
  2912.             // * If it looks like a global/package/class level declaration then we assume that it was supposed
  2913.             // to be abstract.
  2914.             //
  2915.             // * If it is a right-curly then we assume that the class scope is being
  2916.             // closed and this is therefore an abstract function.
  2917.             //
  2918.            
  2919.             switch (this.currentToken.token) {
  2920.                 case JSToken.Const:
  2921.                 case JSToken.Package:
  2922.                 case JSToken.Internal:
  2923.                 case JSToken.Public:
  2924.                 case JSToken.Static:
  2925.                 case JSToken.Private:
  2926.                 case JSToken.Protected:
  2927.                 case JSToken.Abstract:
  2928.                 case JSToken.Final:
  2929.                 case JSToken.Interface:
  2930.                 case JSToken.Class:
  2931.                 case JSToken.Enum:
  2932.                 case JSToken.Function:
  2933.                 case JSToken.RightCurly:
  2934.                     return true;
  2935.                 case JSToken.Semicolon:
  2936.                     GetNextToken();
  2937.                     return true;
  2938.                 case JSToken.Var:
  2939.                 case JSToken.LeftCurly:
  2940.                 default:
  2941.                     return false;
  2942.             }
  2943.         }
  2944.        
  2945.         //---------------------------------------------------------------------------------------
  2946.         // ParseFunction
  2947.         //
  2948.         // FunctionDeclaration :
  2949.         // VisibilityModifier 'function' GetSet Identifier '('
  2950.         // FormalParameterList ')' '{' FunctionBody '}'
  2951.         //
  2952.         // GetSet:
  2953.         // <empty> |
  2954.         // 'get' |
  2955.         // 'set'
  2956.         //
  2957.         // FormalParameterList :
  2958.         // <empty> |
  2959.         // IdentifierList Identifier
  2960.         //
  2961.         // IdentifierList :
  2962.         // <empty> |
  2963.         // Identifier, IdentifierList
  2964.         //---------------------------------------------------------------------------------------
  2965.         private AST ParseFunction(FieldAttributes visibilitySpec, bool inExpression, Context fncCtx, bool isMethod, bool isAbstract, bool isFinal, bool isInterface, CustomAttributeList customAttributes)
  2966.         {
  2967.             return ParseFunction(visibilitySpec, inExpression, fncCtx, isMethod, isAbstract, isFinal, isInterface, customAttributes, null);
  2968.         }
  2969.        
  2970.         private AST ParseFunction(FieldAttributes visibilitySpec, bool inExpression, Context fncCtx, bool isMethod, bool isAbstract, bool isFinal, bool isInterface, CustomAttributeList customAttributes, Call function)
  2971.         {
  2972.             if (this.demandFullTrustOnFunctionCreation)
  2973.                 (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Demand();
  2974.             IdentifierLiteral name = null;
  2975.             AST interfaceName = null;
  2976.             ArrayList formalParameters = null;
  2977.             TypeExpression returnType = null;
  2978.             Block body = null;
  2979.             bool isGetter = false;
  2980.             bool isSetter = false;
  2981.            
  2982.             if (function == null) {
  2983.                 GetNextToken();
  2984.                 if (isMethod)
  2985.                     if (JSToken.Get == this.currentToken.token) {
  2986.                         isGetter = true;
  2987.                         GetNextToken();
  2988.                     }
  2989.                     else if (JSToken.Set == this.currentToken.token) {
  2990.                         isSetter = true;
  2991.                         GetNextToken();
  2992.                     }
  2993.                
  2994.                 // get the function name or make an anonymous function if in expression "position"
  2995.                 if (JSToken.Identifier == this.currentToken.token) {
  2996.                     name = new IdentifierLiteral(this.scanner.GetIdentifier(), this.currentToken.Clone());
  2997.                     GetNextToken();
  2998.                     if (JSToken.AccessField == this.currentToken.token) {
  2999.                         if (isInterface)
  3000.                             // "function IBar.foo()" is illegal in an interface declaration
  3001.                             ReportError(JSError.SyntaxError, true);
  3002.                         GetNextToken();
  3003.                         if (JSToken.Identifier == this.currentToken.token) {
  3004.                             interfaceName = new Lookup(name.context);
  3005.                             name = new IdentifierLiteral(this.scanner.GetIdentifier(), this.currentToken.Clone());
  3006.                             GetNextToken();
  3007.                             while (JSToken.AccessField == this.currentToken.token) {
  3008.                                 GetNextToken();
  3009.                                 if (JSToken.Identifier == this.currentToken.token) {
  3010.                                     interfaceName = new Member(interfaceName.context.CombineWith(this.currentToken), interfaceName, new ConstantWrapper(name.ToString(), name.context));
  3011.                                     name = new IdentifierLiteral(this.scanner.GetIdentifier(), this.currentToken.Clone());
  3012.                                     GetNextToken();
  3013.                                 }
  3014.                                 else
  3015.                                     ReportError(JSError.NoIdentifier, true);
  3016.                             }
  3017.                         }
  3018.                         else
  3019.                             ReportError(JSError.NoIdentifier, true);
  3020.                     }
  3021.                 }
  3022.                 else {
  3023.                     string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  3024.                     if (null != identifier) {
  3025.                         ForceReportInfo(JSError.KeywordUsedAsIdentifier, isMethod);
  3026.                         name = new IdentifierLiteral(identifier, this.currentToken.Clone());
  3027.                         GetNextToken();
  3028.                     }
  3029.                     else {
  3030.                         if (!inExpression) {
  3031.                             identifier = this.currentToken.GetCode();
  3032.                             ReportError(JSError.NoIdentifier, true);
  3033.                             GetNextToken();
  3034.                         }
  3035.                         else
  3036.                             identifier = "";
  3037.                         name = new IdentifierLiteral(identifier, CurrentPositionContext());
  3038.                     }
  3039.                 }
  3040.             }
  3041.             else {
  3042.                 // function was passed in, this is an error condition
  3043.                 name = function.GetName();
  3044.             }
  3045.            
  3046.             // make a new state and save the old one
  3047.             ArrayList blockType = this.blockType;
  3048.             this.blockType = new ArrayList(16);
  3049.             SimpleHashtable labelTable = this.labelTable;
  3050.             this.labelTable = new SimpleHashtable(16);
  3051.             FunctionScope fscope = new FunctionScope(Globals.ScopeStack.Peek(), isMethod);
  3052.             Globals.ScopeStack.Push(fscope);
  3053.             //Give declarations a place to go while building AST
  3054.             try {
  3055.                 formalParameters = new ArrayList();
  3056.                 Context paramArrayContext = null;
  3057.                 if (function == null) {
  3058.                     // get the formal parameters
  3059.                     if (JSToken.LeftParen != this.currentToken.token)
  3060.                         ReportError(JSError.NoLeftParen);
  3061.                     GetNextToken();
  3062.                     // create the list of arguments and update the context
  3063.                     while (JSToken.RightParen != this.currentToken.token) {
  3064.                         if (paramArrayContext != null) {
  3065.                             ReportError(JSError.ParamListNotLast, paramArrayContext, true);
  3066.                             paramArrayContext = null;
  3067.                         }
  3068.                         string id = null;
  3069.                         TypeExpression typeExpr = null;
  3070.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet);
  3071.                         try {
  3072.                             if (JSToken.ParamArray == this.currentToken.token) {
  3073.                                 paramArrayContext = this.currentToken.Clone();
  3074.                                 GetNextToken();
  3075.                             }
  3076.                             if (JSToken.Identifier != this.currentToken.token && (id = JSKeyword.CanBeIdentifier(this.currentToken.token)) == null) {
  3077.                                 if (JSToken.LeftCurly == this.currentToken.token) {
  3078.                                     ReportError(JSError.NoRightParen);
  3079.                                     break;
  3080.                                 }
  3081.                                 else if (JSToken.Comma == this.currentToken.token) {
  3082.                                     // We're missing an argument (or previous argument was malformed and
  3083.                                     // we skipped to the comma.) Keep trying to parse the argument list --
  3084.                                     // we will skip the comma below.
  3085.                                     ReportError(JSError.SyntaxError, true);
  3086.                                 }
  3087.                                 else {
  3088.                                     ReportError(JSError.SyntaxError, true);
  3089.                                     SkipTokensAndThrow();
  3090.                                 }
  3091.                             }
  3092.                             else {
  3093.                                 if (null == id)
  3094.                                     id = this.scanner.GetIdentifier();
  3095.                                 else
  3096.                                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  3097.                                 Context paramCtx = this.currentToken.Clone();
  3098.                                 GetNextToken();
  3099.                                 if (JSToken.Colon == this.currentToken.token) {
  3100.                                     typeExpr = ParseTypeExpression();
  3101.                                     if (null != typeExpr)
  3102.                                         paramCtx.UpdateWith(typeExpr.context);
  3103.                                 }
  3104.                                
  3105.                                
  3106.                                 CustomAttributeList custAttrs = null;
  3107.                                 if (paramArrayContext != null) {
  3108.                                     custAttrs = new CustomAttributeList(paramArrayContext);
  3109.                                     custAttrs.Append(new CustomAttribute(paramArrayContext, new Lookup("...", paramArrayContext), new ASTList(null)));
  3110.                                 }
  3111.                                 formalParameters.Add(new ParameterDeclaration(paramCtx, id, typeExpr, custAttrs));
  3112.                             }
  3113.                            
  3114.                             // got an arg, it should be either a ',' or ')'
  3115.                             if (JSToken.RightParen == this.currentToken.token)
  3116.                                 break;
  3117.                             else if (JSToken.Comma != this.currentToken.token) {
  3118.                                 // deal with error in some "intelligent" way
  3119.                                 if (JSToken.LeftCurly == this.currentToken.token) {
  3120.                                     ReportError(JSError.NoRightParen);
  3121.                                     break;
  3122.                                 }
  3123.                                 else {
  3124.                                     if (JSToken.Identifier == this.currentToken.token && typeExpr == null) {
  3125.                                         // it's possible that the guy was writing the type in C/C++ style (i.e. int x)
  3126.                                         ReportError(JSError.NoCommaOrTypeDefinitionError);
  3127.                                     }
  3128.                                     else
  3129.                                         ReportError(JSError.NoComma);
  3130.                                 }
  3131.                             }
  3132.                             GetNextToken();
  3133.                         }
  3134.                         catch (RecoveryTokenException exc) {
  3135.                             if (IndexOfToken(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet, exc) == -1)
  3136.                                 throw exc;
  3137.                         }
  3138.                         finally {
  3139.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet);
  3140.                         }
  3141.                     }
  3142.                     fncCtx.UpdateWith(this.currentToken);
  3143.                     // if it is a getter/setter must have 0/1 arg only
  3144.                     if (isGetter && formalParameters.Count != 0) {
  3145.                         ReportError(JSError.BadPropertyDeclaration, true);
  3146.                         isGetter = false;
  3147.                     }
  3148.                     else if (isSetter && formalParameters.Count != 1) {
  3149.                         ReportError(JSError.BadPropertyDeclaration, true);
  3150.                         isSetter = false;
  3151.                     }
  3152.                     GetNextToken();
  3153.                    
  3154.                     // check the return type
  3155.                     if (JSToken.Colon == this.currentToken.token) {
  3156.                         if (isSetter)
  3157.                             ReportError(JSError.SyntaxError);
  3158.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartBlockNoSkipTokenSet);
  3159.                         try {
  3160.                             returnType = ParseTypeExpression();
  3161.                         }
  3162.                         catch (RecoveryTokenException exc) {
  3163.                             if (IndexOfToken(NoSkipTokenSet.s_StartBlockNoSkipTokenSet, exc) == -1) {
  3164.                                 exc._partiallyComputedNode = null;
  3165.                                 throw exc;
  3166.                             }
  3167.                             else {
  3168.                                 if (exc._partiallyComputedNode != null)
  3169.                                     returnType = (TypeExpression)exc._partiallyComputedNode;
  3170.                             }
  3171.                         }
  3172.                         finally {
  3173.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartBlockNoSkipTokenSet);
  3174.                         }
  3175.                         if (isSetter)
  3176.                             returnType = null;
  3177.                     }
  3178.                 }
  3179.                 else {
  3180.                     // function was passed in, this is an error condition
  3181.                     function.GetParameters(formalParameters);
  3182.                 }
  3183.                
  3184.                 // read the function body of non-abstract functions.
  3185.                
  3186.                 if (JSToken.LeftCurly != this.currentToken.token && (isAbstract || (isMethod && GuessIfAbstract()))) {
  3187.                     if (!isAbstract) {
  3188.                         isAbstract = true;
  3189.                         ReportError(JSError.ShouldBeAbstract, fncCtx, true);
  3190.                     }
  3191.                     body = new Block(this.currentToken.Clone());
  3192.                 }
  3193.                 else {
  3194.                     if (JSToken.LeftCurly != this.currentToken.token)
  3195.                         ReportError(JSError.NoLeftCurly, true);
  3196.                     else if (isAbstract)
  3197.                         ReportError(JSError.AbstractWithBody, fncCtx, true);
  3198.                    
  3199.                     this.blockType.Add(BlockType.Block);
  3200.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3201.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  3202.                     try {
  3203.                         // parse the block locally to get the exact end of function
  3204.                         body = new Block(this.currentToken.Clone());
  3205.                         GetNextToken();
  3206.                        
  3207.                         while (JSToken.RightCurly != this.currentToken.token) {
  3208.                             try {
  3209.                                 body.Append(ParseStatement());
  3210.                             }
  3211.                             catch (RecoveryTokenException exc) {
  3212.                                 if (exc._partiallyComputedNode != null) {
  3213.                                     body.Append(exc._partiallyComputedNode);
  3214.                                 }
  3215.                                 if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
  3216.                                     throw exc;
  3217.                             }
  3218.                         }
  3219.                        
  3220.                         body.context.UpdateWith(this.currentToken);
  3221.                         fncCtx.UpdateWith(this.currentToken);
  3222.                     }
  3223.                     catch (RecoveryTokenException exc) {
  3224.                         if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) {
  3225.                             Globals.ScopeStack.Pop();
  3226.                             //Pop current scope so that FunctionDeclaration sees proper scope stack
  3227.                             try {
  3228.                                 ParameterDeclaration[] foParameters = new ParameterDeclaration[formalParameters.Count];
  3229.                                 formalParameters.CopyTo(foParameters);
  3230.                                 if (inExpression)
  3231.                                     exc._partiallyComputedNode = new FunctionExpression(fncCtx, name, foParameters, returnType, body, fscope, visibilitySpec);
  3232.                                 else
  3233.                                     exc._partiallyComputedNode = new FunctionDeclaration(fncCtx, interfaceName, name, foParameters, returnType, body, fscope, visibilitySpec, isMethod, isGetter,
  3234.                                     isSetter, isAbstract, isFinal, customAttributes);
  3235.                                 if (customAttributes != null)
  3236.                                     customAttributes.SetTarget(exc._partiallyComputedNode);
  3237.                             }
  3238.                             finally {
  3239.                                 Globals.ScopeStack.Push(fscope);
  3240.                                 //Push it back so that the next finally can pop it
  3241.                             }
  3242.                             throw exc;
  3243.                         }
  3244.                     }
  3245.                     finally {
  3246.                         this.blockType.RemoveAt(this.blockType.Count - 1);
  3247.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  3248.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3249.                     }
  3250.                    
  3251.                     GetNextToken();
  3252.                 }
  3253.             }
  3254.             finally {
  3255.                 // restore state
  3256.                 this.blockType = blockType;
  3257.                 this.labelTable = labelTable;
  3258.                 Globals.ScopeStack.Pop();
  3259.             }
  3260.            
  3261.             ParameterDeclaration[] fParameters = new ParameterDeclaration[formalParameters.Count];
  3262.             formalParameters.CopyTo(fParameters);
  3263.             AST func;
  3264.             if (inExpression)
  3265.                 func = new FunctionExpression(fncCtx, name, fParameters, returnType, body, fscope, visibilitySpec);
  3266.             else
  3267.                 func = new FunctionDeclaration(fncCtx, interfaceName, name, fParameters, returnType, body, fscope, visibilitySpec, isMethod, isGetter,
  3268.                 isSetter, isAbstract, isFinal, customAttributes);
  3269.            
  3270.             if (customAttributes != null)
  3271.                 customAttributes.SetTarget(func);
  3272.             return func;
  3273.            
  3274.         }
  3275.        
  3276.         //used by FunctionConstructor
  3277.         internal AST ParseFunctionExpression()
  3278.         {
  3279.             this.demandFullTrustOnFunctionCreation = true;
  3280.             GetNextToken();
  3281.             //skip over function keyword
  3282.             return ParseFunction((FieldAttributes)0, true, this.currentToken.Clone(), false, false, false, false, null);
  3283.         }
  3284.        
  3285.         //---------------------------------------------------------------------------------------
  3286.         // ParseNamedBreakpoint
  3287.         //
  3288.         // Used by the debugger to parsed a named breakpoint, that is a name of a function with
  3289.         // possible arguments and optionally followed by an il offset
  3290.         //---------------------------------------------------------------------------------------
  3291.         internal string[] ParseNamedBreakpoint(out int argNumber)
  3292.         {
  3293.             argNumber = 0;
  3294.            
  3295.             // parse the function name
  3296.             AST function = ParseQualifiedIdentifier(JSError.SyntaxError);
  3297.             if (function != null) {
  3298.                 string[] parsedFunction = new string[4];
  3299.                 parsedFunction[0] = function.ToString();
  3300.                
  3301.                 if (JSToken.LeftParen == this.currentToken.token) {
  3302.                     string id = null;
  3303.                     string typeString = null;
  3304.                     AST qualid = null;
  3305.                    
  3306.                     parsedFunction[1] = "";
  3307.                    
  3308.                     GetNextToken();
  3309.                     // parse the formal parameters
  3310.                     while (JSToken.RightParen != this.currentToken.token) {
  3311.                         id = null;
  3312.                         if (JSToken.Identifier != this.currentToken.token && (id = JSKeyword.CanBeIdentifier(this.currentToken.token)) == null) {
  3313.                             return null;
  3314.                         }
  3315.                         else {
  3316.                             if (null == id)
  3317.                                 id = this.scanner.GetIdentifier();
  3318.                             qualid = new Lookup(id, this.currentToken.Clone());
  3319.                             GetNextToken();
  3320.                             if (JSToken.AccessField == this.currentToken.token) {
  3321.                                 qualid = ParseScopeSequence(qualid, JSError.SyntaxError);
  3322.                                 typeString = qualid.ToString();
  3323.                                 while (JSToken.LeftBracket == this.currentToken.token) {
  3324.                                     GetNextToken();
  3325.                                     if (JSToken.RightBracket != this.currentToken.token)
  3326.                                         return null;
  3327.                                     typeString += "[]";
  3328.                                     GetNextToken();
  3329.                                 }
  3330.                             }
  3331.                             else if (JSToken.Colon == this.currentToken.token) {
  3332.                                 GetNextToken();
  3333.                                 if (JSToken.RightParen == this.currentToken.token)
  3334.                                     return null;
  3335.                                 continue;
  3336.                             }
  3337.                             else {
  3338.                                 typeString = qualid.ToString();
  3339.                             }
  3340.                             parsedFunction[1] += typeString + " ";
  3341.                         }
  3342.                         argNumber++;
  3343.                        
  3344.                         if (JSToken.Comma == this.currentToken.token) {
  3345.                             GetNextToken();
  3346.                             if (JSToken.RightParen == this.currentToken.token)
  3347.                                 return null;
  3348.                         }
  3349.                     }
  3350.                    
  3351.                     GetNextToken();
  3352.                    
  3353.                     // parse a return value if any
  3354.                     if (JSToken.Colon == this.currentToken.token) {
  3355.                         GetNextToken();
  3356.                         id = null;
  3357.                         if (JSToken.Identifier != this.currentToken.token && (id = JSKeyword.CanBeIdentifier(this.currentToken.token)) == null) {
  3358.                             return null;
  3359.                         }
  3360.                         else {
  3361.                             if (null == id)
  3362.                                 id = this.scanner.GetIdentifier();
  3363.                             qualid = new Lookup(id, this.currentToken.Clone());
  3364.                             GetNextToken();
  3365.                             if (JSToken.AccessField == this.currentToken.token) {
  3366.                                 qualid = ParseScopeSequence(qualid, JSError.SyntaxError);
  3367.                                 parsedFunction[2] = qualid.ToString();
  3368.                                 while (JSToken.LeftBracket == this.currentToken.token) {
  3369.                                     GetNextToken();
  3370.                                     if (JSToken.RightBracket != this.currentToken.token)
  3371.                                         return null;
  3372.                                     parsedFunction[2] += "[]";
  3373.                                     GetNextToken();
  3374.                                 }
  3375.                             }
  3376.                             else {
  3377.                                 parsedFunction[2] = qualid.ToString();
  3378.                             }
  3379.                         }
  3380.                     }
  3381.                    
  3382.                 }
  3383.                
  3384.                 if (JSToken.Plus == this.currentToken.token) {
  3385.                     GetNextToken();
  3386.                     if (JSToken.IntegerLiteral != this.currentToken.token)
  3387.                         return null;
  3388.                     parsedFunction[3] = this.currentToken.GetCode();
  3389.                     GetNextToken();
  3390.                 }
  3391.                
  3392.                 if (JSToken.EndOfFile != this.currentToken.token)
  3393.                     return null;
  3394.                 return parsedFunction;
  3395.             }
  3396.             return null;
  3397.         }
  3398.        
  3399.         //---------------------------------------------------------------------------------------
  3400.         // ParsePackage
  3401.         //
  3402.         // Package :
  3403.         // 'package' QualifiedIdentifier '{' ClassList '}'
  3404.         //
  3405.         // ClassList :
  3406.         // <empty> |
  3407.         // Class ClassList |
  3408.         // Attributes Class ClassList |
  3409.         // Attributes Enum ClassList
  3410.         //---------------------------------------------------------------------------------------
  3411.         // Because 'package' is not a reserved word in JS5 we have to deal with an ambiguity
  3412.         // in the grammar. A source sequence like the following
  3413.         // package
  3414.         // x
  3415.         // { }
  3416.         // can be legally parsed in two ways:
  3417.         // Identifier Identifier Block or
  3418.         // Package
  3419.         // we give Package priority in this situation.
  3420.         // Here is how we deal with some possible cases:
  3421.         // 1- ** package <no line break> QualifiedIdentifier ** is parsed unambiguously as a package production regardless of what comes after Identifier
  3422.         // 2- ** package <no line break> NotOneOf(Operator | '[' | '.' | '(' | Identifier) '{' ** is parsed as a package production with an error
  3423.         // 3- ** package <line break> '{' ** is parsed as a package (anonymous) with an error
  3424.         // 4- ** package <line break> Not(Identifier) ** is never parsed as a package
  3425.         private AST ParsePackage(Context packageContext)
  3426.         {
  3427.             GetNextToken();
  3428.             AST qualid = null;
  3429.             bool gotLineBreak = this.scanner.GotEndOfLine();
  3430.            
  3431.             // erroneous package production
  3432.             if (JSToken.Identifier != this.currentToken.token) {
  3433.                 if (JSScanner.CanParseAsExpression(this.currentToken.token)) {
  3434.                     // it's an expression. Report a warning. package and this.currentToken can be an expression (i.e. 'package +')
  3435.                     ReportError(JSError.KeywordUsedAsIdentifier, packageContext.Clone(), true);
  3436.                     qualid = new Lookup("package", packageContext);
  3437.                     // get the member expression
  3438.                     qualid = MemberExpression(qualid, null);
  3439.                     bool isLeftHandSide;
  3440.                     qualid = ParsePostfixExpression(qualid, out isLeftHandSide);
  3441.                     qualid = ParseExpression(qualid, false, isLeftHandSide, JSToken.None);
  3442.                     return new Expression(qualid.context.Clone(), qualid);
  3443.                 }
  3444.                 else if (!gotLineBreak) {
  3445.                     if (JSToken.Increment == this.currentToken.token || JSToken.Decrement == this.currentToken.token) {
  3446.                         // it's a postfix expression. Report a warning
  3447.                         ReportError(JSError.KeywordUsedAsIdentifier, packageContext.Clone(), true);
  3448.                         bool dummy;
  3449.                         qualid = new Lookup("package", packageContext);
  3450.                         qualid = ParsePostfixExpression(qualid, out dummy);
  3451.                         qualid = ParseExpression(qualid, false, false, JSToken.None);
  3452.                         return new Expression(qualid.context.Clone(), qualid);
  3453.                     }
  3454.                 }
  3455.                 else {
  3456.                     // it's an expression. Report a warning which, as a side effect, will make the current token be the next token fetched
  3457.                     ReportError(JSError.KeywordUsedAsIdentifier, packageContext.Clone(), true);
  3458.                     return new Lookup("package", packageContext);
  3459.                 }
  3460.             }
  3461.             else {
  3462.                 // it is an identifier, parse it as a qualified identifier
  3463.                 this.errorToken = this.currentToken;
  3464.                 // this will make GetNextToken() in ParseQualifiedIdentifier() return this.currentToken
  3465.                 qualid = ParseQualifiedIdentifier(JSError.NoIdentifier);
  3466.             }
  3467.            
  3468.             // if we are here we have:
  3469.             // ** package QualifiedIdentifier ** or
  3470.             // ** package SomeNonSenseToken **, that is a token that does not make an expression
  3471.            
  3472.             Context nonSenseToken = null;
  3473.             if (JSToken.LeftCurly != this.currentToken.token && qualid == null) {
  3474.                 // we want to peek and see whether the next token is a LeftCurly
  3475.                 nonSenseToken = this.currentToken.Clone();
  3476.                 GetNextToken();
  3477.             }
  3478.            
  3479.             if (JSToken.LeftCurly == this.currentToken.token) {
  3480.                 // sounds like a package, possibly with an error. If qualid is not null is actually a good package, otherwise we treat it
  3481.                 // as an anonymous package and keep going.
  3482.                 if (qualid == null) {
  3483.                     if (nonSenseToken == null)
  3484.                         nonSenseToken = this.currentToken.Clone();
  3485.                     ReportError(JSError.NoIdentifier, nonSenseToken, true);
  3486.                 }
  3487.             }
  3488.             else {
  3489.                 if (qualid == null) {
  3490.                     ReportError(JSError.SyntaxError, packageContext);
  3491.                     if (JSScanner.CanStartStatement(nonSenseToken.token)) {
  3492.                         // this is tricky we assign nonSenseToken to this.currentToken and call ParseStatement, because we know it is a statement start token.
  3493.                         // The parser should then call GetNextToken() which will return the this.currentToken that is assigned to this.errorToken
  3494.                         this.currentToken = nonSenseToken;
  3495.                         return ParseStatement();
  3496.                     }
  3497.                     else {
  3498.                         //ReportError(JSError.SyntaxError, nonSenseToken);
  3499.                         if (JSScanner.CanStartStatement(this.currentToken.token)) {
  3500.                             this.errorToken = null;
  3501.                             return ParseStatement();
  3502.                         }
  3503.                         else {
  3504.                             ReportError(JSError.SyntaxError);
  3505.                             SkipTokensAndThrow();
  3506.                         }
  3507.                     }
  3508.                 }
  3509.                 else {
  3510.                     if (gotLineBreak) {
  3511.                         // we are here with the following: 'package' <line break> QalifiedIdentifier' however we do not have a left curly.
  3512.                         // if the token in our hand can start an expression we go with two expressions, otherwise we accept it as a package
  3513.                         //if (JSScanner.CanParseAsExpression(this.currentToken.token)){
  3514.                         ReportError(JSError.KeywordUsedAsIdentifier, packageContext.Clone(), true);
  3515.                         Block block = new Block(packageContext.Clone());
  3516.                         block.Append(new Lookup("package", packageContext));
  3517.                         qualid = MemberExpression(qualid, null);
  3518.                         bool isLeftHandSide;
  3519.                         qualid = ParsePostfixExpression(qualid, out isLeftHandSide);
  3520.                         qualid = ParseExpression(qualid, false, true, JSToken.None);
  3521.                         block.Append(new Expression(qualid.context.Clone(), qualid));
  3522.                         block.context.UpdateWith(qualid.context);
  3523.                         return block;
  3524.                         //}
  3525.                     }
  3526.                     // the package production rule is entered regardless of the presence of a left curly.
  3527.                     ReportError(JSError.NoLeftCurly);
  3528.                 }
  3529.             }
  3530.            
  3531.             PackageScope pscope = new PackageScope(Globals.ScopeStack.Peek());
  3532.             Globals.ScopeStack.Push(pscope);
  3533.             //Give declarations a place to go while building AST
  3534.             try {
  3535.                 string name = (qualid != null) ? qualid.ToString() : "anonymous package";
  3536.                 pscope.name = name;
  3537.                 packageContext.UpdateWith(this.currentToken);
  3538.                 ASTList classList = new ASTList(packageContext);
  3539.                
  3540.                 GetNextToken();
  3541.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3542.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_PackageBodyNoSkipTokenSet);
  3543.                 try {
  3544.                     while (this.currentToken.token != JSToken.RightCurly) {
  3545.                         AST ast = null;
  3546.                         try {
  3547.                             switch (this.currentToken.token) {
  3548.                                 case JSToken.Interface:
  3549.                                 case JSToken.Class:
  3550.                                    
  3551.                                     classList.Append(ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null));
  3552.                                     break;
  3553.                                 case JSToken.Enum:
  3554.                                    
  3555.                                     classList.Append(ParseEnum((FieldAttributes)0, this.currentToken.Clone(), null));
  3556.                                     break;
  3557.                                 case JSToken.Internal:
  3558.                                 case JSToken.Public:
  3559.                                 case JSToken.Static:
  3560.                                 case JSToken.Private:
  3561.                                 case JSToken.Protected:
  3562.                                 case JSToken.Abstract:
  3563.                                 case JSToken.Final:
  3564.                                     bool parsedOK;
  3565.                                     ast = ParseAttributes(null, true, false, out parsedOK);
  3566.                                     if (parsedOK) {
  3567.                                         if (ast is Class) {
  3568.                                             classList.Append(ast);
  3569.                                             break;
  3570.                                         }
  3571.                                     }
  3572.                                     ReportError(JSError.OnlyClassesAllowed, ast.context.Clone(), true);
  3573.                                     SkipTokensAndThrow();
  3574.                                     break;
  3575.                                 case JSToken.Identifier:
  3576.                                    
  3577.                                     bool bAssign;
  3578.                                     bool canBeAttribute = true;
  3579.                                     ast = ParseUnaryExpression(out bAssign, ref canBeAttribute, false);
  3580.                                     if (canBeAttribute) {
  3581.                                         bool parsed;
  3582.                                         ast = ParseAttributes(ast, true, false, out parsed);
  3583.                                         if (parsed) {
  3584.                                             if (ast is Class) {
  3585.                                                 classList.Append(ast);
  3586.                                                 break;
  3587.                                             }
  3588.                                         }
  3589.                                     }
  3590.                                     ReportError(JSError.OnlyClassesAllowed, ast.context.Clone(), true);
  3591.                                     SkipTokensAndThrow();
  3592.                                     break;
  3593.                                 case JSToken.EndOfFile:
  3594.                                    
  3595.                                     EOFError(JSError.ErrEOF);
  3596.                                     throw new EndOfFile();
  3597.                                     break;
  3598.                                 case JSToken.Semicolon:
  3599.                                     // abort parsing, get back to the main parse routine
  3600.                                     // ignore any spurious semicolon
  3601.                                     GetNextToken();
  3602.                                     break;
  3603.                                 case JSToken.Import:
  3604.                                     // handle common error of using import in package
  3605.                                     ReportError(JSError.InvalidImport, true);
  3606.                                     try {
  3607.                                         ParseImportStatement();
  3608.                                     }
  3609.                                     catch (RecoveryTokenException) {
  3610.                                     }
  3611.                                     break;
  3612.                                 case JSToken.Package:
  3613.                                     // handle common error of using package in package
  3614.                                     Context nestedPackageContext = this.currentToken.Clone();
  3615.                                     AST statement = ParsePackage(nestedPackageContext);
  3616.                                     if (statement is Package)
  3617.                                         ReportError(JSError.PackageInWrongContext, nestedPackageContext, true);
  3618.                                     break;
  3619.                                 default:
  3620.                                     ReportError(JSError.OnlyClassesAllowed, (ast != null) ? ast.context.Clone() : CurrentPositionContext(), true);
  3621.                                     SkipTokensAndThrow();
  3622.                                     break;
  3623.                             }
  3624.                         }
  3625.                         catch (RecoveryTokenException exc) {
  3626.                             if (exc._partiallyComputedNode != null && exc._partiallyComputedNode is Class) {
  3627.                                 classList.Append((Class)exc._partiallyComputedNode);
  3628.                                 exc._partiallyComputedNode = null;
  3629.                             }
  3630.                             if (IndexOfToken(NoSkipTokenSet.s_PackageBodyNoSkipTokenSet, exc) == -1)
  3631.                                 throw exc;
  3632.                         }
  3633.                     }
  3634.                 }
  3635.                 catch (RecoveryTokenException exc) {
  3636.                     if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) {
  3637.                         ReportError(JSError.NoRightCurly, CurrentPositionContext());
  3638.                         exc._partiallyComputedNode = new Package(name, qualid, classList, packageContext);
  3639.                         throw exc;
  3640.                     }
  3641.                 }
  3642.                 finally {
  3643.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_PackageBodyNoSkipTokenSet);
  3644.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3645.                 }
  3646.                 GetNextToken();
  3647.                 return new Package(name, qualid, classList, packageContext);
  3648.             }
  3649.             finally {
  3650.                 Globals.ScopeStack.Pop();
  3651.             }
  3652.         }
  3653.        
  3654.         //---------------------------------------------------------------------------------------
  3655.         // ParseStaticInitializer
  3656.         //
  3657.         // StaticInitializer :
  3658.         // '{' FunctionBody '}'
  3659.         //---------------------------------------------------------------------------------------
  3660.         private AST ParseStaticInitializer(Context initContext)
  3661.         {
  3662.             if (this.demandFullTrustOnFunctionCreation)
  3663.                 (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Demand();
  3664.             Block body = null;
  3665.             FunctionScope scope = new FunctionScope(Globals.ScopeStack.Peek());
  3666.             scope.isStatic = true;
  3667.            
  3668.             // make a new state and save the old one
  3669.             ArrayList blockType = this.blockType;
  3670.             this.blockType = new ArrayList(16);
  3671.             SimpleHashtable labelTable = this.labelTable;
  3672.             this.labelTable = new SimpleHashtable(16);
  3673.            
  3674.             this.blockType.Add(BlockType.Block);
  3675.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3676.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  3677.             try {
  3678.                 Globals.ScopeStack.Push(scope);
  3679.                 //Give declarations a place to go while building AST
  3680.                 // parse the block locally to get the exact end of function
  3681.                 body = new Block(this.currentToken.Clone());
  3682.                 GetNextToken();
  3683.                
  3684.                 while (JSToken.RightCurly != this.currentToken.token) {
  3685.                     try {
  3686.                         body.Append(ParseStatement());
  3687.                     }
  3688.                     catch (RecoveryTokenException exc) {
  3689.                         if (exc._partiallyComputedNode != null)
  3690.                             body.Append(exc._partiallyComputedNode);
  3691.                         if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
  3692.                             throw exc;
  3693.                     }
  3694.                 }
  3695.             }
  3696.             catch (RecoveryTokenException exc) {
  3697.                 if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) {
  3698.                     exc._partiallyComputedNode = new StaticInitializer(initContext, body, scope);
  3699.                     throw exc;
  3700.                 }
  3701.             }
  3702.             finally {
  3703.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
  3704.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
  3705.                 this.blockType = blockType;
  3706.                 this.labelTable = labelTable;
  3707.                 Globals.ScopeStack.Pop();
  3708.             }
  3709.             body.context.UpdateWith(this.currentToken);
  3710.             initContext.UpdateWith(this.currentToken);
  3711.            
  3712.             GetNextToken();
  3713.             return new StaticInitializer(initContext, body, scope);
  3714.         }
  3715.        
  3716.         //---------------------------------------------------------------------------------------
  3717.         // ParseExpression
  3718.         //
  3719.         // Expression :
  3720.         // AssignmentExpressionList AssignmentExpression
  3721.         //
  3722.         // AssignmentExpressionList :
  3723.         // <empty> |
  3724.         // AssignmentExpression ',' AssignmentExpressionList
  3725.         //
  3726.         // AssignmentExpression :
  3727.         // ConditionalExpression |
  3728.         // LeftHandSideExpression AssignmentOperator AssignmentExpression
  3729.         //
  3730.         // ConditionalExpression :
  3731.         // LogicalORExpression OptionalConditionalExpression
  3732.         //
  3733.         // OptionalConditionalExpression :
  3734.         // <empty> |
  3735.         // '?' AssignmentExpression ':' AssignmentExpression
  3736.         //
  3737.         // LogicalORExpression :
  3738.         // LogicalANDExpression OptionalLogicalOrExpression
  3739.         //
  3740.         // OptionalLogicalOrExpression :
  3741.         // <empty> |
  3742.         // '||' LogicalANDExpression OptionalLogicalOrExpression
  3743.         //
  3744.         // LogicalANDExpression :
  3745.         // BitwiseORExpression OptionalLogicalANDExpression
  3746.         //
  3747.         // OptionalLogicalANDExpression :
  3748.         // <empty> |
  3749.         // '&&' BitwiseORExpression OptionalLogicalANDExpression
  3750.         //
  3751.         // BitwiseORExpression :
  3752.         // BitwiseXORExpression OptionalBitwiseORExpression
  3753.         //
  3754.         // OptionalBitwiseORExpression :
  3755.         // <empty> |
  3756.         // '|' BitwiseXORExpression OptionalBitwiseORExpression
  3757.         //
  3758.         // BitwiseXORExpression :
  3759.         // BitwiseANDExpression OptionalBitwiseXORExpression
  3760.         //
  3761.         // OptionalBitwiseXORExpression :
  3762.         // <empty> |
  3763.         // '^' BitwiseANDExpression OptionalBitwiseXORExpression
  3764.         //
  3765.         // BitwiseANDExpression :
  3766.         // EqualityExpression OptionalBitwiseANDExpression
  3767.         //
  3768.         // OptionalBitwiseANDExpression :
  3769.         // <empty> |
  3770.         // '&' EqualityExpression OptionalBitwiseANDExpression
  3771.         //
  3772.         // EqualityExpression :
  3773.         // RelationalExpression |
  3774.         // RelationalExpression '==' EqualityExpression |
  3775.         // RelationalExpression '!=' EqualityExpression |
  3776.         // RelationalExpression '===' EqualityExpression |
  3777.         // RelationalExpression '!==' EqualityExpression
  3778.         //
  3779.         // RelationalExpression :
  3780.         // ShiftExpression |
  3781.         // ShiftExpression '<' RelationalExpression |
  3782.         // ShiftExpression '>' RelationalExpression |
  3783.         // ShiftExpression '<=' RelationalExpression |
  3784.         // ShiftExpression '>=' RelationalExpression
  3785.         //
  3786.         // ShiftExpression :
  3787.         // AdditiveExpression |
  3788.         // AdditiveExpression '<<' ShiftExpression |
  3789.         // AdditiveExpression '>>' ShiftExpression |
  3790.         // AdditiveExpression '>>>' ShiftExpression
  3791.         //
  3792.         // AdditiveExpression :
  3793.         // MultiplicativeExpression |
  3794.         // MultiplicativeExpression '+' AdditiveExpression |
  3795.         // MultiplicativeExpression '-' AdditiveExpression
  3796.         //
  3797.         // MultiplicativeExpression :
  3798.         // UnaryExpression |
  3799.         // UnaryExpression '*' MultiplicativeExpression |
  3800.         // UnaryExpression '/' MultiplicativeExpression |
  3801.         // UnaryExpression '%' MultiplicativeExpression
  3802.         //---------------------------------------------------------------------------------------
  3803.         private AST ParseExpression()
  3804.         {
  3805.             bool bAssign;
  3806.             AST lhs = ParseUnaryExpression(out bAssign, false);
  3807.             return ParseExpression(lhs, false, bAssign, JSToken.None);
  3808.         }
  3809.        
  3810.         private AST ParseExpression(bool single)
  3811.         {
  3812.             bool bAssign;
  3813.             AST lhs = ParseUnaryExpression(out bAssign, false);
  3814.             return ParseExpression(lhs, single, bAssign, JSToken.None);
  3815.         }
  3816.        
  3817.         private AST ParseExpression(bool single, JSToken inToken)
  3818.         {
  3819.             bool bAssign;
  3820.             AST lhs = ParseUnaryExpression(out bAssign, false);
  3821.             return ParseExpression(lhs, single, bAssign, inToken);
  3822.         }
  3823.        
  3824.         private AST ParseExpression(AST leftHandSide, bool single, bool bCanAssign, JSToken inToken)
  3825.         {
  3826.             OpListItem opsStack = new OpListItem(JSToken.None, OpPrec.precNone, null);
  3827.             // dummy element
  3828.             AstListItem termStack = new AstListItem(leftHandSide, null);
  3829.            
  3830.             AST expr = null;
  3831.            
  3832.             try {
  3833.                 for (;;) {
  3834.                     if (JSScanner.IsProcessableOperator(this.currentToken.token) && inToken != this.currentToken.token) {
  3835.                        
  3836.                         OpPrec prec = JSScanner.GetOperatorPrecedence(this.currentToken.token);
  3837.                         bool rightAssoc = JSScanner.IsRightAssociativeOperator(this.currentToken.token);
  3838.                         // the current operator has lower precedence than the operator at the top of the stack
  3839.                         // or it has the same precedence and it is left associative (that is, no 'assign op' or 'conditional')
  3840.                         while (prec < opsStack._prec || prec == opsStack._prec && !rightAssoc) {
  3841.                             //Console.Out.WriteLine("lower prec or same and left assoc");
  3842.                             expr = CreateExpressionNode(opsStack._operator, termStack._prev._term, termStack._term);
  3843.                            
  3844.                             // pop the operator stack
  3845.                             opsStack = opsStack._prev;
  3846.                             // pop the term stack twice
  3847.                             termStack = termStack._prev._prev;
  3848.                             // push node onto the stack
  3849.                             termStack = new AstListItem(expr, termStack);
  3850.                         }
  3851.                        
  3852.                         // the current operator has higher precedence that every scanned operators on the stack, or
  3853.                         // it has the same precedence as the one at the top of the stack and it is right associative
  3854.                        
  3855.                         // push operator and next term
  3856.                        
  3857.                         // special case conditional '?:'
  3858.                         if (JSToken.ConditionalIf == this.currentToken.token) {
  3859.                             //Console.Out.WriteLine("Condition expression");
  3860.                            
  3861.                             AST condition = termStack._term;
  3862.                             // pop term stack
  3863.                             termStack = termStack._prev;
  3864.                            
  3865.                             GetNextToken();
  3866.                            
  3867.                             // get expr1 in logOrExpr ? expr1 : expr2
  3868.                             AST operand1 = ParseExpression(true);
  3869.                            
  3870.                             if (JSToken.Colon != this.currentToken.token)
  3871.                                 ReportError(JSError.NoColon);
  3872.                             GetNextToken();
  3873.                            
  3874.                             // get expr2 in logOrExpr ? expr1 : expr2
  3875.                             AST operand2 = ParseExpression(true, inToken);
  3876.                            
  3877.                             expr = new Conditional(condition.context.CombineWith(operand2.context), condition, operand1, operand2);
  3878.                             termStack = new AstListItem(expr, termStack);
  3879.                         }
  3880.                         else {
  3881.                             //Console.Out.WriteLine("higher prec or right assoc");
  3882.                            
  3883.                             if (JSScanner.IsAssignmentOperator(this.currentToken.token)) {
  3884.                                 if (!bCanAssign) {
  3885.                                     ReportError(JSError.IllegalAssignment);
  3886.                                     SkipTokensAndThrow();
  3887.                                 }
  3888.                             }
  3889.                             else
  3890.                                 bCanAssign = false;
  3891.                            
  3892.                             // push the operator onto the operators stack
  3893.                             opsStack = new OpListItem(this.currentToken.token, prec, opsStack);
  3894.                             // push new term
  3895.                             GetNextToken();
  3896.                             if (bCanAssign)
  3897.                                 termStack = new AstListItem(ParseUnaryExpression(out bCanAssign, false), termStack);
  3898.                             else {
  3899.                                 bool dummy;
  3900.                                 termStack = new AstListItem(ParseUnaryExpression(out dummy, false), termStack);
  3901.                                 dummy = dummy;
  3902.                             }
  3903.                         }
  3904.                     }
  3905.                     else
  3906.                         break;
  3907.                     // done, go and unwind the stack of expressions/operators
  3908.                 }
  3909.                
  3910.                 //Console.Out.WriteLine("unwinding stack");
  3911.                 // there are still operators to be processed
  3912.                 while (opsStack._operator != JSToken.None) {
  3913.                     // make the ast operator node
  3914.                     expr = CreateExpressionNode(opsStack._operator, termStack._prev._term, termStack._term);
  3915.                    
  3916.                     // pop the operator stack
  3917.                     opsStack = opsStack._prev;
  3918.                     // pop the term stack twice
  3919.                     termStack = termStack._prev._prev;
  3920.                    
  3921.                     // push node onto the stack
  3922.                     termStack = new AstListItem(expr, termStack);
  3923.                 }
  3924.                
  3925.                 // if we have a ',' and we are not looking for a single expression reenter
  3926.                 if (!single && JSToken.Comma == this.currentToken.token) {
  3927.                     //Console.Out.WriteLine("Next expr");
  3928.                     GetNextToken();
  3929.                     AST expr2 = ParseExpression(false, inToken);
  3930.                     termStack._term = new Comma(termStack._term.context.CombineWith(expr2.context), termStack._term, expr2);
  3931.                 }
  3932.                
  3933.                 Debug.Assert(termStack._prev == null);
  3934.                 return termStack._term;
  3935.             }
  3936.             catch (RecoveryTokenException exc) {
  3937.                 exc._partiallyComputedNode = leftHandSide;
  3938.                 throw exc;
  3939.             }
  3940.         }
  3941.        
  3942.         //---------------------------------------------------------------------------------------
  3943.         // ParseUnaryExpression
  3944.         //
  3945.         // UnaryExpression :
  3946.         // PostfixExpression |
  3947.         // 'delete' UnaryExpression |
  3948.         // 'void' UnaryExpression |
  3949.         // 'typeof' UnaryExpression |
  3950.         // '++' UnaryExpression |
  3951.         // '--' UnaryExpression |
  3952.         // '+' UnaryExpression |
  3953.         // '-' UnaryExpression |
  3954.         // '~' UnaryExpression |
  3955.         // '!' UnaryExpression
  3956.         //
  3957.         //---------------------------------------------------------------------------------------
  3958.         private AST ParseUnaryExpression(out bool isLeftHandSideExpr, bool isMinus)
  3959.         {
  3960.             bool canBeAttribute = false;
  3961.             return ParseUnaryExpression(out isLeftHandSideExpr, ref canBeAttribute, isMinus, false);
  3962.         }
  3963.        
  3964.         private AST ParseUnaryExpression(out bool isLeftHandSideExpr, ref bool canBeAttribute, bool isMinus)
  3965.         {
  3966.             return ParseUnaryExpression(out isLeftHandSideExpr, ref canBeAttribute, isMinus, true);
  3967.         }
  3968.        
  3969.         private AST ParseUnaryExpression(out bool isLeftHandSideExpr, ref bool canBeAttribute, bool isMinus, bool warnForKeyword)
  3970.         {
  3971.             AST ast = null;
  3972.             isLeftHandSideExpr = false;
  3973.             bool dummy = false;
  3974.             Context exprCtx = null;
  3975.             AST expr = null;
  3976.             switch (this.currentToken.token) {
  3977.                 case JSToken.Void:
  3978.                     exprCtx = this.currentToken.Clone();
  3979.                     GetNextToken();
  3980.                     canBeAttribute = false;
  3981.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  3982.                     exprCtx.UpdateWith(expr.context);
  3983.                     ast = new VoidOp(exprCtx, expr);
  3984.                     break;
  3985.                 case JSToken.Typeof:
  3986.                     exprCtx = this.currentToken.Clone();
  3987.                     GetNextToken();
  3988.                     canBeAttribute = false;
  3989.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  3990.                     exprCtx.UpdateWith(expr.context);
  3991.                     ast = new Typeof(exprCtx, expr);
  3992.                     break;
  3993.                 case JSToken.Plus:
  3994.                     exprCtx = this.currentToken.Clone();
  3995.                     GetNextToken();
  3996.                     canBeAttribute = false;
  3997.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  3998.                     exprCtx.UpdateWith(expr.context);
  3999.                     ast = new NumericUnary(exprCtx, expr, JSToken.Plus);
  4000.                     break;
  4001.                 case JSToken.Minus:
  4002.                     exprCtx = this.currentToken.Clone();
  4003.                     GetNextToken();
  4004.                     canBeAttribute = false;
  4005.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, true);
  4006.                     // deal with '-floatNumber' being parsed as a single entity (NumericLiteral) and not as a -NumericLiteral
  4007.                     if (expr.context.token == JSToken.NumericLiteral) {
  4008.                         exprCtx.UpdateWith(expr.context);
  4009.                         expr.context = exprCtx;
  4010.                         ast = expr;
  4011.                     }
  4012.                     else {
  4013.                         exprCtx.UpdateWith(expr.context);
  4014.                         ast = new NumericUnary(exprCtx, expr, JSToken.Minus);
  4015.                     }
  4016.                     break;
  4017.                 case JSToken.BitwiseNot:
  4018.                     exprCtx = this.currentToken.Clone();
  4019.                     GetNextToken();
  4020.                     canBeAttribute = false;
  4021.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  4022.                     exprCtx.UpdateWith(expr.context);
  4023.                     ast = new NumericUnary(exprCtx, expr, JSToken.BitwiseNot);
  4024.                     break;
  4025.                 case JSToken.LogicalNot:
  4026.                     exprCtx = this.currentToken.Clone();
  4027.                     GetNextToken();
  4028.                     canBeAttribute = false;
  4029.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  4030.                     exprCtx.UpdateWith(expr.context);
  4031.                     ast = new NumericUnary(exprCtx, expr, JSToken.LogicalNot);
  4032.                     break;
  4033.                 case JSToken.Delete:
  4034.                     exprCtx = this.currentToken.Clone();
  4035.                     GetNextToken();
  4036.                     canBeAttribute = false;
  4037.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  4038.                     exprCtx.UpdateWith(expr.context);
  4039.                     ast = new Delete(exprCtx, expr);
  4040.                     break;
  4041.                 case JSToken.Increment:
  4042.                     exprCtx = this.currentToken.Clone();
  4043.                     GetNextToken();
  4044.                     canBeAttribute = false;
  4045.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  4046.                     exprCtx.UpdateWith(expr.context);
  4047.                     ast = new PostOrPrefixOperator(exprCtx, expr, PostOrPrefix.PrefixIncrement);
  4048.                     break;
  4049.                 case JSToken.Decrement:
  4050.                     exprCtx = this.currentToken.Clone();
  4051.                     GetNextToken();
  4052.                     canBeAttribute = false;
  4053.                     expr = ParseUnaryExpression(out dummy, ref canBeAttribute, false);
  4054.                     exprCtx.UpdateWith(expr.context);
  4055.                     ast = new PostOrPrefixOperator(exprCtx, expr, PostOrPrefix.PrefixDecrement);
  4056.                     break;
  4057.                 default:
  4058.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_PostfixExpressionNoSkipTokenSet);
  4059.                     try {
  4060.                         ast = ParseLeftHandSideExpression(isMinus, ref canBeAttribute, warnForKeyword);
  4061.                     }
  4062.                     catch (RecoveryTokenException exc) {
  4063.                         if (IndexOfToken(NoSkipTokenSet.s_PostfixExpressionNoSkipTokenSet, exc) == -1) {
  4064.                             throw exc;
  4065.                         }
  4066.                         else {
  4067.                             if (exc._partiallyComputedNode == null)
  4068.                                 SkipTokensAndThrow();
  4069.                             else
  4070.                                 ast = exc._partiallyComputedNode;
  4071.                         }
  4072.                     }
  4073.                     finally {
  4074.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_PostfixExpressionNoSkipTokenSet);
  4075.                     }
  4076.                     ast = ParsePostfixExpression(ast, out isLeftHandSideExpr, ref canBeAttribute);
  4077.                     break;
  4078.             }
  4079.             dummy = dummy;
  4080.            
  4081.             return ast;
  4082.         }
  4083.        
  4084.         //---------------------------------------------------------------------------------------
  4085.         // ParsePostfixExpression
  4086.         //
  4087.         // PostfixExpression:
  4088.         // LeftHandSideExpression |
  4089.         // LeftHandSideExpression '++' |
  4090.         // LeftHandSideExpression '--'
  4091.         //
  4092.         //---------------------------------------------------------------------------------------
  4093.         private AST ParsePostfixExpression(AST ast, out bool isLeftHandSideExpr)
  4094.         {
  4095.             bool canBeAttribute = false;
  4096.             return ParsePostfixExpression(ast, out isLeftHandSideExpr, ref canBeAttribute);
  4097.         }
  4098.        
  4099.         private AST ParsePostfixExpression(AST ast, out bool isLeftHandSideExpr, ref bool canBeAttribute)
  4100.         {
  4101.             isLeftHandSideExpr = true;
  4102.             Context exprCtx = null;
  4103.             if (null != ast) {
  4104.                 if (!this.scanner.GotEndOfLine()) {
  4105.                     if (JSToken.Increment == this.currentToken.token) {
  4106.                         isLeftHandSideExpr = false;
  4107.                         exprCtx = ast.context.Clone();
  4108.                         exprCtx.UpdateWith(this.currentToken);
  4109.                         canBeAttribute = false;
  4110.                         ast = new PostOrPrefixOperator(exprCtx, ast, PostOrPrefix.PostfixIncrement);
  4111.                         GetNextToken();
  4112.                     }
  4113.                     else if (JSToken.Decrement == this.currentToken.token) {
  4114.                         isLeftHandSideExpr = false;
  4115.                         exprCtx = ast.context.Clone();
  4116.                         exprCtx.UpdateWith(this.currentToken);
  4117.                         canBeAttribute = false;
  4118.                         ast = new PostOrPrefixOperator(exprCtx, ast, PostOrPrefix.PostfixDecrement);
  4119.                         GetNextToken();
  4120.                     }
  4121.                 }
  4122.             }
  4123.             return ast;
  4124.         }
  4125.        
  4126.         //---------------------------------------------------------------------------------------
  4127.         // ParseLeftHandSideExpression
  4128.         //
  4129.         // LeftHandSideExpression :
  4130.         // PrimaryExpression Accessor |
  4131.         // 'new' LeftHandSideExpression |
  4132.         // FunctionExpression
  4133.         //
  4134.         // PrimaryExpression :
  4135.         // 'this' |
  4136.         // Identifier |
  4137.         // Literal |
  4138.         // '(' Expression ')'
  4139.         //
  4140.         // FunctionExpression :
  4141.         // 'function' OptionalFuncName '(' FormalParameterList ')' { FunctionBody }
  4142.         //
  4143.         // OptionalFuncName :
  4144.         // <empty> |
  4145.         // Identifier
  4146.         //---------------------------------------------------------------------------------------
  4147.         private AST ParseLeftHandSideExpression()
  4148.         {
  4149.             return ParseLeftHandSideExpression(false);
  4150.         }
  4151.        
  4152.         private AST ParseLeftHandSideExpression(bool isMinus)
  4153.         {
  4154.             bool canBeAttribute = false;
  4155.             return ParseLeftHandSideExpression(isMinus, ref canBeAttribute, false);
  4156.         }
  4157.        
  4158.         private AST ParseLeftHandSideExpression(bool isMinus, ref bool canBeAttribute, bool warnForKeyword)
  4159.         {
  4160.             AST ast = null;
  4161.             bool isFunction = false;
  4162.             ArrayList newContexts = null;
  4163.            
  4164.             // new expression
  4165.             while (JSToken.New == this.currentToken.token) {
  4166.                 if (null == newContexts)
  4167.                     newContexts = new ArrayList(4);
  4168.                 newContexts.Add(this.currentToken.Clone());
  4169.                 GetNextToken();
  4170.             }
  4171.            
  4172.             JSToken token = this.currentToken.token;
  4173.             switch (token) {
  4174.                 case JSToken.Identifier:
  4175.                     // primary expression
  4176.                     ast = new Lookup(this.scanner.GetIdentifier(), this.currentToken.Clone());
  4177.                     break;
  4178.                 case JSToken.This:
  4179.                    
  4180.                     canBeAttribute = false;
  4181.                     ast = new ThisLiteral(this.currentToken.Clone(), false);
  4182.                     break;
  4183.                 case JSToken.Super:
  4184.                    
  4185.                     canBeAttribute = false;
  4186.                     ast = new ThisLiteral(this.currentToken.Clone(), true);
  4187.                     break;
  4188.                 case JSToken.StringLiteral:
  4189.                    
  4190.                     canBeAttribute = false;
  4191.                     ast = new ConstantWrapper(this.scanner.GetStringLiteral(), this.currentToken.Clone());
  4192.                     break;
  4193.                 case JSToken.IntegerLiteral:
  4194.                    
  4195.                    
  4196.                     {
  4197.                         canBeAttribute = false;
  4198.                         string number = this.currentToken.GetCode();
  4199.                         object n = Convert.LiteralToNumber(number, this.currentToken);
  4200.                         if (n == null)
  4201.                             n = 0;
  4202.                         ast = new ConstantWrapper(n, this.currentToken.Clone());
  4203.                         ((ConstantWrapper)ast).isNumericLiteral = true;
  4204.                         break;
  4205.                     }
  4206.                     break;
  4207.                 case JSToken.NumericLiteral:
  4208.                    
  4209.                    
  4210.                     {
  4211.                         canBeAttribute = false;
  4212.                         string number = (isMinus) ? "-" + this.currentToken.GetCode() : this.currentToken.GetCode();
  4213.                         double d = Convert.ToNumber(number, false, false, Missing.Value);
  4214.                         ast = new ConstantWrapper(d, this.currentToken.Clone());
  4215.                         ((ConstantWrapper)ast).isNumericLiteral = true;
  4216.                         break;
  4217.                     }
  4218.                     break;
  4219.                 case JSToken.True:
  4220.                    
  4221.                     canBeAttribute = false;
  4222.                     ast = new ConstantWrapper(true, this.currentToken.Clone());
  4223.                     break;
  4224.                 case JSToken.False:
  4225.                    
  4226.                     canBeAttribute = false;
  4227.                     ast = new ConstantWrapper(false, this.currentToken.Clone());
  4228.                     break;
  4229.                 case JSToken.Null:
  4230.                    
  4231.                     canBeAttribute = false;
  4232.                     ast = new NullLiteral(this.currentToken.Clone());
  4233.                     break;
  4234.                 case JSToken.PreProcessorConstant:
  4235.                    
  4236.                     canBeAttribute = false;
  4237.                     ast = new ConstantWrapper(this.scanner.GetPreProcessorValue(), this.currentToken.Clone());
  4238.                     break;
  4239.                 case JSToken.Divide:
  4240.                    
  4241.                     canBeAttribute = false;
  4242.                     // could it be a regexp?
  4243.                     string source = this.scanner.ScanRegExp();
  4244.                     if (source != null) {
  4245.                         bool badRegExp = false;
  4246.                         try {
  4247.                             new Regex(source, RegexOptions.ECMAScript);
  4248.                         }
  4249.                         catch (System.ArgumentException) {
  4250.                             // Replace the invalid source with the trivial regular expression.
  4251.                             source = "";
  4252.                             badRegExp = true;
  4253.                         }
  4254.                         string flags = this.scanner.ScanRegExpFlags();
  4255.                         if (flags == null)
  4256.                             ast = new RegExpLiteral(source, null, this.currentToken.Clone());
  4257.                         else
  4258.                             try {
  4259.                                 ast = new RegExpLiteral(source, flags, this.currentToken.Clone());
  4260.                             }
  4261.                             catch (JScriptException) {
  4262.                                 // The flags are invalid, so use null instead.
  4263.                                 ast = new RegExpLiteral(source, null, this.currentToken.Clone());
  4264.                                 badRegExp = true;
  4265.                             }
  4266.                         if (badRegExp) {
  4267.                             ReportError(JSError.RegExpSyntax, true);
  4268.                         }
  4269.                         break;
  4270.                     }
  4271.                     goto default;
  4272.                     break;
  4273.                 case JSToken.LeftParen:
  4274.                    
  4275.                     // expression
  4276.                     canBeAttribute = false;
  4277.                     GetNextToken();
  4278.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
  4279.                     try {
  4280.                         ast = ParseExpression();
  4281.                         if (JSToken.RightParen != this.currentToken.token)
  4282.                             ReportError(JSError.NoRightParen);
  4283.                     }
  4284.                     catch (RecoveryTokenException exc) {
  4285.                         if (IndexOfToken(NoSkipTokenSet.s_ParenExpressionNoSkipToken, exc) == -1)
  4286.                             throw exc;
  4287.                         else
  4288.                             ast = exc._partiallyComputedNode;
  4289.                     }
  4290.                     finally {
  4291.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
  4292.                     }
  4293.                     if (ast == null)
  4294.                         //this can only happen when catching the exception and nothing was sent up by the caller
  4295.                         SkipTokensAndThrow();
  4296.                     break;
  4297.                 case JSToken.LeftBracket:
  4298.                    
  4299.                     // array initializer
  4300.                     canBeAttribute = false;
  4301.                     Context listCtx = this.currentToken.Clone();
  4302.                     ASTList list = new ASTList(this.currentToken.Clone());
  4303.                     GetNextToken();
  4304.                     if (this.currentToken.token == JSToken.Identifier && this.scanner.PeekToken() == JSToken.Colon) {
  4305.                         this.noSkipTokenSet.Add(NoSkipTokenSet.s_BracketToken);
  4306.                         try {
  4307.                             if (this.currentToken.GetCode() == "assembly") {
  4308.                                 GetNextToken();
  4309.                                 GetNextToken();
  4310.                                 return new AssemblyCustomAttributeList(this.ParseCustomAttributeList());
  4311.                             }
  4312.                             else {
  4313.                                 ReportError(JSError.ExpectedAssembly);
  4314.                                 SkipTokensAndThrow();
  4315.                             }
  4316.                         }
  4317.                         catch (RecoveryTokenException exc) {
  4318.                             exc._partiallyComputedNode = new Block(listCtx);
  4319.                             return exc._partiallyComputedNode;
  4320.                         }
  4321.                         finally {
  4322.                             if (this.currentToken.token == JSToken.RightBracket) {
  4323.                                 this.errorToken = null;
  4324.                                 GetNextToken();
  4325.                             }
  4326.                             this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BracketToken);
  4327.                         }
  4328.                     }
  4329.                     while (JSToken.RightBracket != this.currentToken.token) {
  4330.                         if (JSToken.Comma != this.currentToken.token) {
  4331.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
  4332.                             try {
  4333.                                 list.Append(ParseExpression(true));
  4334.                                 if (JSToken.Comma != this.currentToken.token) {
  4335.                                     if (JSToken.RightBracket != this.currentToken.token)
  4336.                                         ReportError(JSError.NoRightBracket);
  4337.                                     break;
  4338.                                 }
  4339.                             }
  4340.                             catch (RecoveryTokenException exc) {
  4341.                                 if (exc._partiallyComputedNode != null)
  4342.                                     list.Append(exc._partiallyComputedNode);
  4343.                                 if (IndexOfToken(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet, exc) == -1) {
  4344.                                     listCtx.UpdateWith(CurrentPositionContext());
  4345.                                     exc._partiallyComputedNode = new ArrayLiteral(listCtx, list);
  4346.                                     throw exc;
  4347.                                 }
  4348.                                 else {
  4349.                                     if (JSToken.RightBracket == this.currentToken.token)
  4350.                                         break;
  4351.                                 }
  4352.                             }
  4353.                             finally {
  4354.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
  4355.                             }
  4356.                         }
  4357.                         else {
  4358.                             list.Append(new ConstantWrapper(Missing.Value, this.currentToken.Clone()));
  4359.                         }
  4360.                         GetNextToken();
  4361.                     }
  4362.                     listCtx.UpdateWith(this.currentToken);
  4363.                     ast = new ArrayLiteral(listCtx, list);
  4364.                     break;
  4365.                 case JSToken.LeftCurly:
  4366.                    
  4367.                     // object initializer
  4368.                     canBeAttribute = false;
  4369.                     Context objCtx = this.currentToken.Clone();
  4370.                     GetNextToken();
  4371.                     ASTList fields = new ASTList(this.currentToken.Clone());
  4372.                     if (JSToken.RightCurly != this.currentToken.token) {
  4373.                         for (;;) {
  4374.                             AST field = null;
  4375.                             AST value = null;
  4376.                            
  4377.                             if (JSToken.Identifier == this.currentToken.token)
  4378.                                 field = new ConstantWrapper(this.scanner.GetIdentifier(), this.currentToken.Clone());
  4379.                             else if (JSToken.StringLiteral == this.currentToken.token)
  4380.                                 field = new ConstantWrapper(this.scanner.GetStringLiteral(), this.currentToken.Clone());
  4381.                             else if (JSToken.IntegerLiteral == this.currentToken.token || JSToken.NumericLiteral == this.currentToken.token) {
  4382.                                 string numberString = this.currentToken.GetCode();
  4383.                                 double dValue = Convert.ToNumber(numberString, true, true, Missing.Value);
  4384.                                 field = new ConstantWrapper(dValue, this.currentToken.Clone());
  4385.                                 ((ConstantWrapper)field).isNumericLiteral = true;
  4386.                             }
  4387.                             else {
  4388.                                 ReportError(JSError.NoMemberIdentifier);
  4389.                                 field = new IdentifierLiteral("_#Missing_Field#_" + s_cDummyName++, CurrentPositionContext());
  4390.                             }
  4391.                             ASTList pair = new ASTList(field.context.Clone());
  4392.                             GetNextToken();
  4393.                            
  4394.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
  4395.                             try {
  4396.                                 // get the value
  4397.                                 if (JSToken.Colon != this.currentToken.token) {
  4398.                                     ReportError(JSError.NoColon, true);
  4399.                                     value = ParseExpression(true);
  4400.                                 }
  4401.                                 else {
  4402.                                     GetNextToken();
  4403.                                     value = ParseExpression(true);
  4404.                                 }
  4405.                                
  4406.                                 // put the pair into the list of fields
  4407.                                 pair.Append(field);
  4408.                                 pair.Append(value);
  4409.                                 fields.Append(pair);
  4410.                                
  4411.                                 if (JSToken.RightCurly == this.currentToken.token)
  4412.                                     break;
  4413.                                 else {
  4414.                                     if (JSToken.Comma == this.currentToken.token)
  4415.                                         GetNextToken();
  4416.                                     else {
  4417.                                         if (this.scanner.GotEndOfLine()) {
  4418.                                             ReportError(JSError.NoRightCurly);
  4419.                                         }
  4420.                                         else
  4421.                                             ReportError(JSError.NoComma, true);
  4422.                                         SkipTokensAndThrow();
  4423.                                     }
  4424.                                 }
  4425.                             }
  4426.                             catch (RecoveryTokenException exc) {
  4427.                                 if (exc._partiallyComputedNode != null) {
  4428.                                     // the problem was in ParseExpression trying to determine value
  4429.                                     value = exc._partiallyComputedNode;
  4430.                                     pair.Append(field);
  4431.                                     pair.Append(value);
  4432.                                     fields.Append(pair);
  4433.                                 }
  4434.                                 if (IndexOfToken(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet, exc) == -1) {
  4435.                                     exc._partiallyComputedNode = new ObjectLiteral(objCtx, fields);
  4436.                                     throw exc;
  4437.                                 }
  4438.                                 else {
  4439.                                     if (JSToken.Comma == this.currentToken.token)
  4440.                                         GetNextToken();
  4441.                                     if (JSToken.RightCurly == this.currentToken.token)
  4442.                                         break;
  4443.                                 }
  4444.                             }
  4445.                             finally {
  4446.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
  4447.                             }
  4448.                         }
  4449.                     }
  4450.                     fields.context.UpdateWith(this.currentToken);
  4451.                     objCtx.UpdateWith(this.currentToken);
  4452.                     ast = new ObjectLiteral(objCtx, fields);
  4453.                     break;
  4454.                 case JSToken.Function:
  4455.                    
  4456.                     // function expression
  4457.                     canBeAttribute = false;
  4458.                     ast = ParseFunction((FieldAttributes)0, true, this.currentToken.Clone(), false, false, false, false, null);
  4459.                     isFunction = true;
  4460.                     break;
  4461.                 default:
  4462.                    
  4463.                     string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  4464.                     if (null != identifier) {
  4465.                         if (warnForKeyword) {
  4466.                             switch (this.currentToken.token) {
  4467.                                 case JSToken.Boolean:
  4468.                                 case JSToken.Byte:
  4469.                                 case JSToken.Char:
  4470.                                 case JSToken.Double:
  4471.                                 case JSToken.Float:
  4472.                                 case JSToken.Int:
  4473.                                 case JSToken.Long:
  4474.                                 case JSToken.Short:
  4475.                                 case JSToken.Void:
  4476.                                     break;
  4477.                                 default:
  4478.                                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  4479.                                     break;
  4480.                             }
  4481.                         }
  4482.                         canBeAttribute = false;
  4483.                         ast = new Lookup(identifier, this.currentToken.Clone());
  4484.                     }
  4485.                     else if (this.currentToken.token == JSToken.BitwiseAnd) {
  4486.                         //& expr used outside of a parameter list
  4487.                         ReportError(JSError.WrongUseOfAddressOf);
  4488.                         this.errorToken = null;
  4489.                         GetNextToken();
  4490.                         return this.ParseLeftHandSideExpression(isMinus, ref canBeAttribute, warnForKeyword);
  4491.                     }
  4492.                     else {
  4493.                         ReportError(JSError.ExpressionExpected);
  4494.                         SkipTokensAndThrow();
  4495.                     }
  4496.                     break;
  4497.             }
  4498.            
  4499.             // can be a CallExpression, that is, followed by '.' or '(' or '['
  4500.             if (!isFunction)
  4501.                 GetNextToken();
  4502.            
  4503.             return MemberExpression(ast, newContexts, ref canBeAttribute);
  4504.         }
  4505.        
  4506.         //-------------------------------------------------------------------------------------------
  4507.         // ParseConstructorCall
  4508.         //
  4509.         // ConstructorCall :
  4510.         // 'this' Arguments
  4511.         // 'super' Arguments
  4512.         //--------------------------------------------------------------------------------------------
  4513.         private AST ParseConstructorCall(Context superCtx)
  4514.         {
  4515.             bool isSuperConstructorCall = JSToken.Super == this.currentToken.token;
  4516.             GetNextToken();
  4517.             Context listCtx = this.currentToken.Clone();
  4518.             ASTList args = new ASTList(listCtx);
  4519.            
  4520.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  4521.             this.noSkipTokenSet.Add(NoSkipTokenSet.s_ParenToken);
  4522.             try {
  4523.                 args = ParseExpressionList(JSToken.RightParen);
  4524.                 GetNextToken();
  4525.                 //Skip the )
  4526.             }
  4527.             catch (RecoveryTokenException exc) {
  4528.                 if (exc._partiallyComputedNode != null)
  4529.                     args = (ASTList)exc._partiallyComputedNode;
  4530.                 if (IndexOfToken(NoSkipTokenSet.s_ParenToken, exc) == -1 && IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1) {
  4531.                     exc._partiallyComputedNode = new ConstructorCall(superCtx, args, isSuperConstructorCall);
  4532.                     throw exc;
  4533.                 }
  4534.                 else {
  4535.                     if (exc._token == JSToken.RightParen)
  4536.                         GetNextToken();
  4537.                 }
  4538.             }
  4539.             finally {
  4540.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenToken);
  4541.                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
  4542.             }
  4543.            
  4544.             superCtx.UpdateWith(listCtx);
  4545.             return new ConstructorCall(superCtx, args, isSuperConstructorCall);
  4546.         }
  4547.        
  4548.         private CustomAttributeList ParseCustomAttributeList()
  4549.         {
  4550.             CustomAttributeList result = new CustomAttributeList(this.currentToken.Clone());
  4551.             do {
  4552.                 Context attrStart = currentToken.Clone();
  4553.                 bool bAssign;
  4554.                 bool canBeAttribute = true;
  4555.                 AST statement = ParseUnaryExpression(out bAssign, ref canBeAttribute, false, false);
  4556.                 if (canBeAttribute) {
  4557.                     if (statement is Lookup || statement is Member)
  4558.                         result.Append(new CustomAttribute(statement.context, statement, new ASTList(null)));
  4559.                     else
  4560.                         result.Append(((Call)statement).ToCustomAttribute());
  4561.                 }
  4562.                 else if (this.tokensSkipped == 0)
  4563.                     ReportError(JSError.SyntaxError, attrStart);
  4564.                 if (this.currentToken.token == JSToken.RightBracket)
  4565.                     return result;
  4566.                 else if (this.currentToken.token == JSToken.Comma)
  4567.                     this.GetNextToken();
  4568.                 else {
  4569.                     ReportError(JSError.NoRightBracketOrComma);
  4570.                     SkipTokensAndThrow();
  4571.                 }
  4572.             }
  4573.             while (true);
  4574.         }
  4575.        
  4576.         //---------------------------------------------------------------------------------------
  4577.         // MemberExpression
  4578.         //
  4579.         // Accessor :
  4580.         // <empty> |
  4581.         // Arguments Accessor
  4582.         // '[' Expression ']' Accessor |
  4583.         // '.' Identifier Accessor |
  4584.         //
  4585.         // Don't have this function throwing an exception without checking all the calling sites.
  4586.         // There is state in instance variable that is saved on the calling stack in some function
  4587.         // (i.e ParseFunction and ParseClass) and you don't want to blow up the stack
  4588.         //---------------------------------------------------------------------------------------
  4589.         private AST MemberExpression(AST expression, ArrayList newContexts)
  4590.         {
  4591.             bool canBeAttribute = false;
  4592.             return MemberExpression(expression, newContexts, ref canBeAttribute);
  4593.         }
  4594.        
  4595.         private AST MemberExpression(AST expression, ArrayList newContexts, ref bool canBeAttribute)
  4596.         {
  4597.             bool canBeQualid;
  4598.             return MemberExpression(expression, newContexts, out canBeQualid, ref canBeAttribute);
  4599.         }
  4600.        
  4601.         private AST MemberExpression(AST expression, ArrayList newContexts, out bool canBeQualid, ref bool canBeAttribute)
  4602.         {
  4603.             bool noMoreForAttr = false;
  4604.             canBeQualid = true;
  4605.             for (;;) {
  4606.                 this.noSkipTokenSet.Add(NoSkipTokenSet.s_MemberExprNoSkipTokenSet);
  4607.                 try {
  4608.                     switch (this.currentToken.token) {
  4609.                         case JSToken.LeftParen:
  4610.                             if (noMoreForAttr)
  4611.                                 canBeAttribute = false;
  4612.                             else
  4613.                                 noMoreForAttr = true;
  4614.                             canBeQualid = false;
  4615.                            
  4616.                             ASTList args = null;
  4617.                             RecoveryTokenException callError = null;
  4618.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_ParenToken);
  4619.                             try {
  4620.                                 args = ParseExpressionList(JSToken.RightParen);
  4621.                             }
  4622.                             catch (RecoveryTokenException exc) {
  4623.                                 args = (ASTList)exc._partiallyComputedNode;
  4624.                                 if (IndexOfToken(NoSkipTokenSet.s_ParenToken, exc) == -1)
  4625.                                     callError = exc;
  4626.                                 // thrown later on
  4627.                             }
  4628.                             finally {
  4629.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenToken);
  4630.                             }
  4631.                            
  4632.                             //treat eval and print specially
  4633.                             if (expression is Lookup) {
  4634.                                 string name = expression.ToString();
  4635.                                 if (name.Equals("eval")) {
  4636.                                     expression.context.UpdateWith(args.context);
  4637.                                     if (args.count == 1)
  4638.                                         expression = new Eval(expression.context, args[0], null);
  4639.                                     else if (args.count > 1)
  4640.                                         expression = new Eval(expression.context, args[0], args[1]);
  4641.                                     else
  4642.                                         expression = new Eval(expression.context, new ConstantWrapper("", CurrentPositionContext()), null);
  4643.                                     canBeAttribute = false;
  4644.                                 }
  4645.                                 else if (this.Globals.engine.doPrint && name.Equals("print")) {
  4646.                                     expression.context.UpdateWith(args.context);
  4647.                                     expression = new Print(expression.context, args);
  4648.                                     canBeAttribute = false;
  4649.                                 }
  4650.                                 else {
  4651.                                     expression = new Call(expression.context.CombineWith(args.context), expression, args, false);
  4652.                                 }
  4653.                             }
  4654.                             else
  4655.                                 expression = new Call(expression.context.CombineWith(args.context), expression, args, false);
  4656.                            
  4657.                             if (null != newContexts && newContexts.Count > 0) {
  4658.                                 ((Context)newContexts[newContexts.Count - 1]).UpdateWith(expression.context);
  4659.                                 if (!(expression is Call))
  4660.                                     expression = new Call((Context)newContexts[newContexts.Count - 1], expression, new ASTList(CurrentPositionContext()), false);
  4661.                                 else
  4662.                                     expression.context = (Context)newContexts[newContexts.Count - 1];
  4663.                                 ((Call)expression).isConstructor = true;
  4664.                                 newContexts.RemoveAt(newContexts.Count - 1);
  4665.                             }
  4666.                            
  4667.                             if (callError != null) {
  4668.                                 callError._partiallyComputedNode = expression;
  4669.                                 throw callError;
  4670.                             }
  4671.                            
  4672.                             GetNextToken();
  4673.                             break;
  4674.                         case JSToken.LeftBracket:
  4675.                            
  4676.                             canBeQualid = false;
  4677.                             canBeAttribute = false;
  4678.                             this.noSkipTokenSet.Add(NoSkipTokenSet.s_BracketToken);
  4679.                             try {
  4680.                                 args = ParseExpressionList(JSToken.RightBracket);
  4681.                             }
  4682.                             catch (RecoveryTokenException exc) {
  4683.                                 if (IndexOfToken(NoSkipTokenSet.s_BracketToken, exc) == -1) {
  4684.                                     if (exc._partiallyComputedNode != null) {
  4685.                                         exc._partiallyComputedNode = new Call(expression.context.CombineWith(this.currentToken.Clone()), expression, (ASTList)exc._partiallyComputedNode, true);
  4686.                                     }
  4687.                                     else {
  4688.                                         exc._partiallyComputedNode = expression;
  4689.                                     }
  4690.                                     throw exc;
  4691.                                 }
  4692.                                 else
  4693.                                     args = (ASTList)exc._partiallyComputedNode;
  4694.                             }
  4695.                             finally {
  4696.                                 this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BracketToken);
  4697.                             }
  4698.                             expression = new Call(expression.context.CombineWith(this.currentToken.Clone()), expression, args, true);
  4699.                            
  4700.                             if (null != newContexts && newContexts.Count > 0) {
  4701.                                 ((Context)newContexts[newContexts.Count - 1]).UpdateWith(expression.context);
  4702.                                 expression.context = (Context)newContexts[newContexts.Count - 1];
  4703.                                 ((Call)expression).isConstructor = true;
  4704.                                 newContexts.RemoveAt(newContexts.Count - 1);
  4705.                             }
  4706.                             GetNextToken();
  4707.                             break;
  4708.                         case JSToken.AccessField:
  4709.                            
  4710.                             if (noMoreForAttr)
  4711.                                 canBeAttribute = false;
  4712.                             ConstantWrapper id = null;
  4713.                             GetNextToken();
  4714.                             if (JSToken.Identifier != this.currentToken.token) {
  4715.                                 string identifier = JSKeyword.CanBeIdentifier(this.currentToken.token);
  4716.                                 if (null != identifier) {
  4717.                                     ForceReportInfo(JSError.KeywordUsedAsIdentifier);
  4718.                                     id = new ConstantWrapper(identifier, this.currentToken.Clone());
  4719.                                 }
  4720.                                 else {
  4721.                                     ReportError(JSError.NoIdentifier);
  4722.                                     SkipTokensAndThrow(expression);
  4723.                                 }
  4724.                             }
  4725.                             else
  4726.                                 id = new ConstantWrapper(this.scanner.GetIdentifier(), this.currentToken.Clone());
  4727.                             GetNextToken();
  4728.                             expression = new Member(expression.context.CombineWith(id.context), expression, id);
  4729.                             break;
  4730.                         default:
  4731.                             if (null != newContexts) {
  4732.                                 while (newContexts.Count > 0) {
  4733.                                     ((Context)newContexts[newContexts.Count - 1]).UpdateWith(expression.context);
  4734.                                     expression = new Call((Context)newContexts[newContexts.Count - 1], expression, new ASTList(CurrentPositionContext()), false);
  4735.                                     ((Call)expression).isConstructor = true;
  4736.                                     newContexts.RemoveAt(newContexts.Count - 1);
  4737.                                 }
  4738.                             }
  4739.                             return expression;
  4740.                     }
  4741.                 }
  4742.                 catch (RecoveryTokenException exc) {
  4743.                     if (IndexOfToken(NoSkipTokenSet.s_MemberExprNoSkipTokenSet, exc) != -1)
  4744.                         expression = exc._partiallyComputedNode;
  4745.                     else {
  4746.                         Debug.Assert(exc._partiallyComputedNode == expression);
  4747.                         throw exc;
  4748.                     }
  4749.                 }
  4750.                 finally {
  4751.                     this.noSkipTokenSet.Remove(NoSkipTokenSet.s_MemberExprNoSkipTokenSet);
  4752.                 }
  4753.             }
  4754.         }
  4755.        
  4756.         //---------------------------------------------------------------------------------------
  4757.         // ParseExpressionList
  4758.         //
  4759.         // Given a starting this.currentToken '(' or '[', parse a list of expression separated by
  4760.         // ',' until matching ')' or ']'
  4761.         //---------------------------------------------------------------------------------------
  4762.         private ASTList ParseExpressionList(JSToken terminator)
  4763.         {
  4764.             Context listCtx = this.currentToken.Clone();
  4765.             int line = this.scanner.GetCurrentLine();
  4766.             GetNextToken();
  4767.             ASTList list = new ASTList(listCtx);
  4768.             if (terminator != this.currentToken.token) {
  4769.                 for (;;) {
  4770.                     this.noSkipTokenSet.Add(NoSkipTokenSet.s_ExpressionListNoSkipTokenSet);
  4771.                     try {
  4772.                         if (JSToken.BitwiseAnd == this.currentToken.token) {
  4773.                             // address of operator
  4774.                             Context addressOfCtx = this.currentToken.Clone();
  4775.                             GetNextToken();
  4776.                             AST lhexpr = ParseLeftHandSideExpression();
  4777.                             if (lhexpr is Member || lhexpr is Lookup) {
  4778.                                 addressOfCtx.UpdateWith(lhexpr.context);
  4779.                                 list.Append(new AddressOf(addressOfCtx, lhexpr));
  4780.                             }
  4781.                             else {
  4782.                                 ReportError(JSError.DoesNotHaveAnAddress, addressOfCtx.Clone());
  4783.                                 list.Append(lhexpr);
  4784.                             }
  4785.                         }
  4786.                         else if (JSToken.Comma == this.currentToken.token) {
  4787.                             list.Append(new ConstantWrapper(System.Reflection.Missing.Value, this.currentToken.Clone()));
  4788.                         }
  4789.                         else if (terminator == this.currentToken.token) {
  4790.                             break;
  4791.                         }
  4792.                         else
  4793.                             list.Append(ParseExpression(true));
  4794.                        
  4795.                         if (terminator == this.currentToken.token)
  4796.                             break;
  4797.                         else {
  4798.                             if (JSToken.Comma != this.currentToken.token) {
  4799.                                 if (terminator == JSToken.RightParen) {
  4800.                                     // in ASP+ it's easy to write a semicolon at the end of an expression
  4801.                                     // not realizing it is going to go inside a function call
  4802.                                     // (ie. Response.Write()), so make a special check here
  4803.                                     if (JSToken.Semicolon == this.currentToken.token) {
  4804.                                         if (JSToken.RightParen == this.scanner.PeekToken()) {
  4805.                                             ReportError(JSError.UnexpectedSemicolon, true);
  4806.                                             GetNextToken();
  4807.                                             break;
  4808.                                         }
  4809.                                     }
  4810.                                     ReportError(JSError.NoRightParenOrComma);
  4811.                                 }
  4812.                                 else
  4813.                                     ReportError(JSError.NoRightBracketOrComma);
  4814.                                 SkipTokensAndThrow();
  4815.                             }
  4816.                         }
  4817.                     }
  4818.                     catch (RecoveryTokenException exc) {
  4819.                         if (exc._partiallyComputedNode != null)
  4820.                             list.Append(exc._partiallyComputedNode);
  4821.                         if (IndexOfToken(NoSkipTokenSet.s_ExpressionListNoSkipTokenSet, exc) == -1) {
  4822.                             exc._partiallyComputedNode = list;
  4823.                             throw exc;
  4824.                         }
  4825.                     }
  4826.                     finally {
  4827.                         this.noSkipTokenSet.Remove(NoSkipTokenSet.s_ExpressionListNoSkipTokenSet);
  4828.                     }
  4829.                     GetNextToken();
  4830.                 }
  4831.             }
  4832.             listCtx.UpdateWith(this.currentToken);
  4833.             return list;
  4834.         }
  4835.        
  4836.         //---------------------------------------------------------------------------------------
  4837.         // CreateExpressionNode
  4838.         //
  4839.         // Create the proper AST object according to operator
  4840.         //---------------------------------------------------------------------------------------
  4841.         private AST CreateExpressionNode(JSToken op, AST operand1, AST operand2)
  4842.         {
  4843.             Context context = operand1.context.CombineWith(operand2.context);
  4844.             switch (op) {
  4845.                 case JSToken.Assign:
  4846.                     return new Assign(context, operand1, operand2);
  4847.                 case JSToken.BitwiseAnd:
  4848.                     return new BitwiseBinary(context, operand1, operand2, JSToken.BitwiseAnd);
  4849.                 case JSToken.BitwiseAndAssign:
  4850.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.BitwiseAnd);
  4851.                 case JSToken.BitwiseOr:
  4852.                     return new BitwiseBinary(context, operand1, operand2, JSToken.BitwiseOr);
  4853.                 case JSToken.BitwiseOrAssign:
  4854.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.BitwiseOr);
  4855.                 case JSToken.BitwiseXor:
  4856.                     return new BitwiseBinary(context, operand1, operand2, JSToken.BitwiseXor);
  4857.                 case JSToken.BitwiseXorAssign:
  4858.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.BitwiseXor);
  4859.                 case JSToken.Comma:
  4860.                     return new Comma(context, operand1, operand2);
  4861.                 case JSToken.Divide:
  4862.                     return new NumericBinary(context, operand1, operand2, JSToken.Divide);
  4863.                 case JSToken.DivideAssign:
  4864.                     return new NumericBinaryAssign(context, operand1, operand2, JSToken.Divide);
  4865.                 case JSToken.Equal:
  4866.                     return new Equality(context, operand1, operand2, JSToken.Equal);
  4867.                 case JSToken.GreaterThan:
  4868.                     return new Relational(context, operand1, operand2, JSToken.GreaterThan);
  4869.                 case JSToken.GreaterThanEqual:
  4870.                     return new Relational(context, operand1, operand2, JSToken.GreaterThanEqual);
  4871.                 case JSToken.In:
  4872.                     return new In(context, operand1, operand2);
  4873.                 case JSToken.Instanceof:
  4874.                     return new Instanceof(context, operand1, operand2);
  4875.                 case JSToken.LeftShift:
  4876.                     return new BitwiseBinary(context, operand1, operand2, JSToken.LeftShift);
  4877.                 case JSToken.LeftShiftAssign:
  4878.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.LeftShift);
  4879.                 case JSToken.LessThan:
  4880.                     return new Relational(context, operand1, operand2, JSToken.LessThan);
  4881.                 case JSToken.LessThanEqual:
  4882.                     return new Relational(context, operand1, operand2, JSToken.LessThanEqual);
  4883.                 case JSToken.LogicalAnd:
  4884.                     return new Logical_and(context, operand1, operand2);
  4885.                 case JSToken.LogicalOr:
  4886.                     return new Logical_or(context, operand1, operand2);
  4887.                 case JSToken.Minus:
  4888.                     return new NumericBinary(context, operand1, operand2, JSToken.Minus);
  4889.                 case JSToken.MinusAssign:
  4890.                     return new NumericBinaryAssign(context, operand1, operand2, JSToken.Minus);
  4891.                 case JSToken.Modulo:
  4892.                     return new NumericBinary(context, operand1, operand2, JSToken.Modulo);
  4893.                 case JSToken.ModuloAssign:
  4894.                     return new NumericBinaryAssign(context, operand1, operand2, JSToken.Modulo);
  4895.                 case JSToken.Multiply:
  4896.                     return new NumericBinary(context, operand1, operand2, JSToken.Multiply);
  4897.                 case JSToken.MultiplyAssign:
  4898.                     return new NumericBinaryAssign(context, operand1, operand2, JSToken.Multiply);
  4899.                 case JSToken.NotEqual:
  4900.                     return new Equality(context, operand1, operand2, JSToken.NotEqual);
  4901.                 case JSToken.Plus:
  4902.                     return new Plus(context, operand1, operand2);
  4903.                 case JSToken.PlusAssign:
  4904.                     return new PlusAssign(context, operand1, operand2);
  4905.                 case JSToken.RightShift:
  4906.                     return new BitwiseBinary(context, operand1, operand2, JSToken.RightShift);
  4907.                 case JSToken.RightShiftAssign:
  4908.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.RightShift);
  4909.                 case JSToken.StrictEqual:
  4910.                     return new StrictEquality(context, operand1, operand2, JSToken.StrictEqual);
  4911.                 case JSToken.StrictNotEqual:
  4912.                     return new StrictEquality(context, operand1, operand2, JSToken.StrictNotEqual);
  4913.                 case JSToken.UnsignedRightShift:
  4914.                     return new BitwiseBinary(context, operand1, operand2, JSToken.UnsignedRightShift);
  4915.                 case JSToken.UnsignedRightShiftAssign:
  4916.                     return new BitwiseBinaryAssign(context, operand1, operand2, JSToken.UnsignedRightShift);
  4917.                 default:
  4918.                     Debug.Assert(false);
  4919.                     return null;
  4920.             }
  4921.         }
  4922.        
  4923.         //---------------------------------------------------------------------------------------
  4924.         // GetNextToken
  4925.         //
  4926.         // Return the next token or peeked token if this.errorToken is not null.
  4927.         // Usually this.errorToken is set by AddError even though any code can look ahead
  4928.         // by assigning this.errorToken.
  4929.         // At this point the context is not saved so if position information is needed
  4930.         // they have to be saved explicitely
  4931.         //---------------------------------------------------------------------------------------
  4932.         private void GetNextToken()
  4933.         {
  4934.             if (null != this.errorToken) {
  4935.                 if (this.breakRecursion > 10) {
  4936.                     #if DEBUG
  4937.                     JSParser.WriteToFile(this.errorToken);
  4938.                     #endif
  4939.                     this.errorToken = null;
  4940.                     this.scanner.GetNextToken();
  4941.                     return;
  4942.                 }
  4943.                 this.breakRecursion++;
  4944.                 this.currentToken = this.errorToken;
  4945.                 this.errorToken = null;
  4946.             }
  4947.             else {
  4948.                 this.goodTokensProcessed++;
  4949.                 this.breakRecursion = 0;
  4950.                 // the scanner shares this.currentToken with the parser
  4951.                 this.scanner.GetNextToken();
  4952.             }
  4953.         }
  4954.        
  4955.         #if DEBUG
  4956.         private static void WriteToFile(Context context)
  4957.         {
  4958.             string filename = "error_" + (s_filenameSuffix++).ToString(CultureInfo.InvariantCulture) + ".js";
  4959.             ScriptStream.WriteLine("possible infinite recursion in parser recovery code...");
  4960.             ScriptStream.WriteLine("Please send the file " + filename + " to hermanv");
  4961.            
  4962.             using (System.IO.TextWriter stream = new System.IO.StreamWriter(System.IO.File.Create(filename))) {
  4963.                 string code = context.source_string.Substring(0, context.EndPosition);
  4964.                 stream.Write(code.ToCharArray());
  4965.                 stream.Flush();
  4966.             }
  4967.         }
  4968.         #endif
  4969.        
  4970.         private Context CurrentPositionContext()
  4971.         {
  4972.             Context context = this.currentToken.Clone();
  4973.             context.endPos = (context.startPos < context.source_string.Length) ? context.startPos + 1 : context.startPos;
  4974.             return context;
  4975.         }
  4976.        
  4977.         //---------------------------------------------------------------------------------------
  4978.         // ReportError
  4979.         //
  4980.         // Generate a parser error.
  4981.         // When no context is provided the token is missing so the context is the current position
  4982.         //---------------------------------------------------------------------------------------
  4983.         private void ReportError(JSError errorId)
  4984.         {
  4985.             ReportError(errorId, false);
  4986.         }
  4987.        
  4988.         //---------------------------------------------------------------------------------------
  4989.         // ReportError
  4990.         //
  4991.         // Generate a parser error.
  4992.         // When no context is provided the token is missing so the context is the current position
  4993.         // The function is told whether or not next call to GetToken() should return the same
  4994.         // token or not
  4995.         //---------------------------------------------------------------------------------------
  4996.         private void ReportError(JSError errorId, bool skipToken)
  4997.         {
  4998.             // get the current position token
  4999.             Context context = this.currentToken.Clone();
  5000.             context.endPos = context.startPos + 1;
  5001.             ReportError(errorId, context, skipToken);
  5002.         }
  5003.        
  5004.         //---------------------------------------------------------------------------------------
  5005.         // ReportError
  5006.         //
  5007.         // Generate a parser error.
  5008.         // This is usually generated when a bad token is found, the context identifies the
  5009.         // bad token
  5010.         //---------------------------------------------------------------------------------------
  5011.         private void ReportError(JSError errorId, Context context)
  5012.         {
  5013.             ReportError(errorId, context, false);
  5014.         }
  5015.        
  5016.         //---------------------------------------------------------------------------------------
  5017.         // ReportError
  5018.         //
  5019.         // Generate a parser error.
  5020.         // The function is told whether or not next call to GetToken() should return the same
  5021.         // token or not
  5022.         //---------------------------------------------------------------------------------------
  5023.         private void ReportError(JSError errorId, Context context, bool skipToken)
  5024.         {
  5025.             Debug.Assert(context != null);
  5026.             int previousSeverity = this.Severity;
  5027.             this.Severity = (new JScriptException(errorId)).Severity;
  5028.             // EOF error is special and it's the last error we can possibly get
  5029.             if (JSToken.EndOfFile == context.token)
  5030.                 EOFError(errorId);
  5031.             // EOF context is special
  5032.             else {
  5033.                 // report the error if not in error condition and the
  5034.                 // error for this token is not worse than the one for the
  5035.                 // previous token
  5036.                 if (this.goodTokensProcessed > 0 || this.Severity < previousSeverity)
  5037.                     context.HandleError(errorId);
  5038.                
  5039.                 // reset proper info
  5040.                 if (skipToken)
  5041.                     this.goodTokensProcessed = -1;
  5042.                 else {
  5043.                     this.errorToken = this.currentToken;
  5044.                     this.goodTokensProcessed = 0;
  5045.                 }
  5046.             }
  5047.         }
  5048.        
  5049.         //---------------------------------------------------------------------------------------
  5050.         // ForceReportInfo
  5051.         //
  5052.         // Generate a parser error (info), does not change the error state in the parse
  5053.         //---------------------------------------------------------------------------------------
  5054.         private void ForceReportInfo(JSError errorId)
  5055.         {
  5056.             ForceReportInfo(this.currentToken.Clone(), errorId);
  5057.         }
  5058.        
  5059.         //---------------------------------------------------------------------------------------
  5060.         // ForceReportInfo
  5061.         //
  5062.         // Generate a parser error (info), does not change the error state in the parse
  5063.         //---------------------------------------------------------------------------------------
  5064.         private void ForceReportInfo(Context context, JSError errorId)
  5065.         {
  5066.             Debug.Assert(context != null);
  5067.             context.HandleError(errorId);
  5068.         }
  5069.        
  5070.         //---------------------------------------------------------------------------------------
  5071.         // ForceReportInfo
  5072.         //
  5073.         // Generate a parser error (info), does not change the error state in the parse
  5074.         //---------------------------------------------------------------------------------------
  5075.         private void ForceReportInfo(JSError errorId, bool treatAsError)
  5076.         {
  5077.             this.currentToken.Clone().HandleError(errorId, treatAsError);
  5078.         }
  5079.        
  5080.         //---------------------------------------------------------------------------------------
  5081.         // EOFError
  5082.         //
  5083.         // Create a context for EOF error. The created context points to the end of the source
  5084.         // code. Assume the the scanner actually reached the end of file
  5085.         //---------------------------------------------------------------------------------------
  5086.         private void EOFError(JSError errorId)
  5087.         {
  5088.             Context eofCtx = this.sourceContext.Clone();
  5089.             eofCtx.lineNumber = this.scanner.GetCurrentLine();
  5090.             eofCtx.endLineNumber = eofCtx.lineNumber;
  5091.             eofCtx.startLinePos = this.scanner.GetStartLinePosition();
  5092.             eofCtx.endLinePos = eofCtx.startLinePos;
  5093.             eofCtx.startPos = this.sourceContext.endPos;
  5094.             eofCtx.endPos++;
  5095.             eofCtx.HandleError(errorId);
  5096.         }
  5097.        
  5098.         //---------------------------------------------------------------------------------------
  5099.         // SkipTokensAndThrow
  5100.         //
  5101.         // Skip tokens until one in the no skip set is found.
  5102.         // A call to this function always ends in a throw statement that will be caught by the
  5103.         // proper rule
  5104.         //---------------------------------------------------------------------------------------
  5105.         private void SkipTokensAndThrow()
  5106.         {
  5107.             SkipTokensAndThrow(null);
  5108.         }
  5109.        
  5110.         private void SkipTokensAndThrow(AST partialAST)
  5111.         {
  5112.             this.errorToken = null;
  5113.             // make sure we go to the next token
  5114.             bool checkForEndOfLine = this.noSkipTokenSet.HasToken(JSToken.EndOfLine);
  5115.             while (!this.noSkipTokenSet.HasToken(this.currentToken.token)) {
  5116.                 if (checkForEndOfLine) {
  5117.                     if (this.scanner.GotEndOfLine()) {
  5118.                         this.errorToken = this.currentToken;
  5119.                         throw new RecoveryTokenException(JSToken.EndOfLine, partialAST);
  5120.                     }
  5121.                 }
  5122.                 GetNextToken();
  5123.                 if (++this.tokensSkipped > c_MaxSkippedTokenNumber) {
  5124.                     ForceReportInfo(JSError.TooManyTokensSkipped);
  5125.                     throw new EndOfFile();
  5126.                 }
  5127.                 if (JSToken.EndOfFile == this.currentToken.token)
  5128.                     throw new EndOfFile();
  5129.             }
  5130.             this.errorToken = this.currentToken;
  5131.             // got a token in the no skip set, throw
  5132.             throw new RecoveryTokenException(this.currentToken.token, partialAST);
  5133.         }
  5134.        
  5135.         //---------------------------------------------------------------------------------------
  5136.         // IndexOfToken
  5137.         //
  5138.         // check whether the recovery token is a good one for the caller
  5139.         //---------------------------------------------------------------------------------------
  5140.         private int IndexOfToken(JSToken[] tokens, RecoveryTokenException exc)
  5141.         {
  5142.             return IndexOfToken(tokens, exc._token);
  5143.         }
  5144.        
  5145.         private int IndexOfToken(JSToken[] tokens, JSToken token)
  5146.         {
  5147.             int i;
  5148.             int c;
  5149.             for (i = 0,c = tokens.Length; i < c; i++)
  5150.                 if (tokens[i] == token)
  5151.                     break;
  5152.             if (i >= c)
  5153.                 i = -1;
  5154.             else {
  5155.                 // assume that the caller will deal with the token so move the state back to normal
  5156.                 this.errorToken = null;
  5157.             }
  5158.             return i;
  5159.         }
  5160.        
  5161.         private bool TokenInList(JSToken[] tokens, JSToken token)
  5162.         {
  5163.             return (-1 != IndexOfToken(tokens, token));
  5164.         }
  5165.        
  5166.         private bool TokenInList(JSToken[] tokens, RecoveryTokenException exc)
  5167.         {
  5168.             return (-1 != IndexOfToken(tokens, exc._token));
  5169.         }
  5170.        
  5171.         //---------------------------------------------------------------------------------------
  5172.         // FromASTListToCustomAttributeList
  5173.         //
  5174.         // Utility function that takes a list of AST nodes (Call and Lookup nodes) and makes
  5175.         // a CustomAttributeList. It is invoked once a list of calls and lookups is unambiguosly
  5176.         // parsed as a custom attribute list
  5177.         //---------------------------------------------------------------------------------------
  5178.         private CustomAttributeList FromASTListToCustomAttributeList(ArrayList attributes)
  5179.         {
  5180.             CustomAttributeList customAttributes = null;
  5181.             if (attributes != null && attributes.Count > 0)
  5182.                 customAttributes = new CustomAttributeList(((AST)attributes[0]).context);
  5183.             for (int i = 0int n = attributes.Count; i < n; i++) {
  5184.                 ASTList args = new ASTList(null);
  5185.                 if (attributes[i] is Lookup || attributes[i] is Member)
  5186.                     customAttributes.Append(new CustomAttribute(((AST)attributes[i]).context, (AST)attributes[i], args));
  5187.                 else
  5188.                     customAttributes.Append(((Call)attributes[i]).ToCustomAttribute());
  5189.             }
  5190.            
  5191.             return customAttributes;
  5192.         }
  5193.        
  5194.         internal bool HasAborted {
  5195.             get { return this.tokensSkipped > c_MaxSkippedTokenNumber; }
  5196.         }
  5197.     }
  5198.    
  5199.     // helper classes
  5200.     //***************************************************************************************
  5201.     //
  5202.     //***************************************************************************************
  5203.     internal class AstListItem
  5204.     {
  5205.         internal AstListItem _prev;
  5206.         internal AST _term;
  5207.        
  5208.         internal AstListItem(AST term, AstListItem prev)
  5209.         {
  5210.             _prev = prev;
  5211.             _term = term;
  5212.         }
  5213.        
  5214.     }
  5215.    
  5216.     //***************************************************************************************
  5217.     //
  5218.     //***************************************************************************************
  5219.     internal class OpListItem
  5220.     {
  5221.         internal OpListItem _prev;
  5222.         internal JSToken _operator;
  5223.         internal OpPrec _prec;
  5224.         //internal OpAssoc _assoc;
  5225.        
  5226.             /*OpAssoc assoc,*/        internal OpListItem(JSToken op, OpPrec prec, OpListItem prev)
  5227.         {
  5228.             _prev = prev;
  5229.             _operator = op;
  5230.             _prec = prec;
  5231.             //_assoc = assoc;
  5232.         }
  5233.     }
  5234.    
  5235.     //***************************************************************************************
  5236.     //
  5237.     //***************************************************************************************
  5238.     [Serializable()]
  5239.     public class ParserException : Exception
  5240.     {
  5241.         internal ParserException() : base(JScriptException.Localize("Parser Exception", CultureInfo.CurrentUICulture))
  5242.         {
  5243.         }
  5244.     }
  5245.    
  5246.    
  5247.     internal class RecoveryTokenException : ParserException
  5248.     {
  5249.         internal JSToken _token;
  5250.         internal AST _partiallyComputedNode;
  5251.        
  5252.         internal RecoveryTokenException(JSToken token, AST partialAST) : base()
  5253.         {
  5254.             _token = token;
  5255.             _partiallyComputedNode = partialAST;
  5256.         }
  5257.     }
  5258.    
  5259.     [Serializable()]
  5260.     public class EndOfFile : ParserException
  5261.     {
  5262.         internal EndOfFile() : base()
  5263.         {
  5264.         }
  5265.     }
  5266.    
  5267.     //***************************************************************************************
  5268.     // NoSkipTokenSet
  5269.     //
  5270.     // This class is a possible implementation of the no skip token set. It relies on the
  5271.     // fact that the array passed in are static. Should you change it, this implementation
  5272.     // should change as well.
  5273.     // It keeps a linked list of token arrays that are passed in during parsing, on error
  5274.     // condition the list is traversed looking for a matching token. If a match is found
  5275.     // the token should not be skipped and an exception is thrown to let the proper
  5276.     // rule deal with the token
  5277.     //***************************************************************************************
  5278.     internal class NoSkipTokenSet
  5279.     {
  5280.         TokenSetListItem _tokenSet;
  5281.        
  5282.         internal NoSkipTokenSet()
  5283.         {
  5284.             _tokenSet = null;
  5285.         }
  5286.        
  5287.         internal void Add(JSToken[] tokens)
  5288.         {
  5289.             _tokenSet = new TokenSetListItem(tokens, _tokenSet);
  5290.         }
  5291.        
  5292.         internal void Remove(JSToken[] tokens)
  5293.         {
  5294.             TokenSetListItem curr = _tokenSet;
  5295.             TokenSetListItem prev = null;
  5296.             while (curr != null) {
  5297.                 if (curr._tokens == tokens) {
  5298.                     if (prev == null) {
  5299.                         Debug.Assert(_tokenSet == curr);
  5300.                         _tokenSet = _tokenSet._next;
  5301.                     }
  5302.                     else {
  5303.                         prev._next = curr._next;
  5304.                     }
  5305.                     return;
  5306.                 }
  5307.                 prev = curr;
  5308.                 curr = curr._next;
  5309.             }
  5310.             Debug.Assert(false, "Token set not in no skip token");
  5311.         }
  5312.        
  5313.         internal bool HasToken(JSToken token)
  5314.         {
  5315.             TokenSetListItem curr = _tokenSet;
  5316.             while (curr != null) {
  5317.                 for (int i = 0int c = curr._tokens.Length; i < c; i++) {
  5318.                     if (curr._tokens[i] == token)
  5319.                         return true;
  5320.                 }
  5321.                 curr = curr._next;
  5322.             }
  5323.             return false;
  5324.         }
  5325.        
  5326.         // list of static no skip token set for specifc rules
  5327.         static internal readonly JSToken[] s_ArrayInitNoSkipTokenSet = new JSToken[] {JSToken.RightBracket, JSToken.Comma};
  5328.         static internal readonly JSToken[] s_BlockConditionNoSkipTokenSet = new JSToken[] {JSToken.RightParen, JSToken.LeftCurly, JSToken.EndOfLine};
  5329.         static internal readonly JSToken[] s_BlockNoSkipTokenSet = new JSToken[] {JSToken.RightCurly};
  5330.         static internal readonly JSToken[] s_BracketToken = new JSToken[] {JSToken.RightBracket};
  5331.         static internal readonly JSToken[] s_CaseNoSkipTokenSet = new JSToken[] {JSToken.Case, JSToken.Default, JSToken.Colon, JSToken.EndOfLine};
  5332.         static internal readonly JSToken[] s_ClassBodyNoSkipTokenSet = new JSToken[] {JSToken.Class, JSToken.Interface, JSToken.Enum, JSToken.Function, JSToken.Var, JSToken.Const, JSToken.Static, JSToken.Public, JSToken.Private, JSToken.Protected
  5333.         };
  5334.         static internal readonly JSToken[] s_InterfaceBodyNoSkipTokenSet = new JSToken[] {JSToken.Enum, JSToken.Function, JSToken.Public, JSToken.EndOfLine, JSToken.Semicolon};
  5335.         static internal readonly JSToken[] s_ClassExtendsNoSkipTokenSet = new JSToken[] {JSToken.LeftCurly, JSToken.Implements};
  5336.         static internal readonly JSToken[] s_ClassImplementsNoSkipTokenSet = new JSToken[] {JSToken.LeftCurly, JSToken.Comma};
  5337.         static internal readonly JSToken[] s_DoWhileBodyNoSkipTokenSet = new JSToken[] {JSToken.While};
  5338.         static internal readonly JSToken[] s_EndOfLineToken = new JSToken[] {JSToken.EndOfLine};
  5339.         static internal readonly JSToken[] s_EndOfStatementNoSkipTokenSet = new JSToken[] {JSToken.Semicolon, JSToken.EndOfLine};
  5340.         static internal readonly JSToken[] s_EnumBaseTypeNoSkipTokenSet = new JSToken[] {JSToken.LeftCurly};
  5341.         static internal readonly JSToken[] s_EnumBodyNoSkipTokenSet = new JSToken[] {JSToken.Identifier};
  5342.         static internal readonly JSToken[] s_ExpressionListNoSkipTokenSet = new JSToken[] {JSToken.Comma};
  5343.         static internal readonly JSToken[] s_FunctionDeclNoSkipTokenSet = new JSToken[] {JSToken.RightParen, JSToken.LeftCurly, JSToken.Comma};
  5344.         static internal readonly JSToken[] s_IfBodyNoSkipTokenSet = new JSToken[] {JSToken.Else};
  5345.         static internal readonly JSToken[] s_MemberExprNoSkipTokenSet = new JSToken[] {JSToken.LeftBracket, JSToken.LeftParen, JSToken.AccessField};
  5346.         static internal readonly JSToken[] s_NoTrySkipTokenSet = new JSToken[] {JSToken.Catch, JSToken.Finally};
  5347.         static internal readonly JSToken[] s_ObjectInitNoSkipTokenSet = new JSToken[] {JSToken.RightCurly, JSToken.Comma};
  5348.         static internal readonly JSToken[] s_PackageBodyNoSkipTokenSet = new JSToken[] {JSToken.Class, JSToken.Interface, JSToken.Enum};
  5349.         static internal readonly JSToken[] s_ParenExpressionNoSkipToken = new JSToken[] {JSToken.RightParen};
  5350.         static internal readonly JSToken[] s_ParenToken = new JSToken[] {JSToken.RightParen};
  5351.         static internal readonly JSToken[] s_PostfixExpressionNoSkipTokenSet = new JSToken[] {JSToken.Increment, JSToken.Decrement};
  5352.         static internal readonly JSToken[] s_StartBlockNoSkipTokenSet = new JSToken[] {JSToken.LeftCurly};
  5353.         static internal readonly JSToken[] s_StartStatementNoSkipTokenSet = new JSToken[] {JSToken.LeftCurly, JSToken.Var, JSToken.Const, JSToken.If, JSToken.For, JSToken.Do, JSToken.While, JSToken.With, JSToken.Switch, JSToken.Try
  5354.         };
  5355.         static internal readonly JSToken[] s_SwitchNoSkipTokenSet = new JSToken[] {JSToken.Case, JSToken.Default};
  5356.         static internal readonly JSToken[] s_TopLevelNoSkipTokenSet = new JSToken[] {JSToken.Package, JSToken.Class, JSToken.Interface, JSToken.Enum, JSToken.Function, JSToken.Import};
  5357.         static internal readonly JSToken[] s_VariableDeclNoSkipTokenSet = new JSToken[] {JSToken.Comma, JSToken.Semicolon};
  5358.        
  5359.         private class TokenSetListItem
  5360.         {
  5361.             internal TokenSetListItem _next;
  5362.             internal JSToken[] _tokens;
  5363.            
  5364.             internal TokenSetListItem(JSToken[] tokens, TokenSetListItem next)
  5365.             {
  5366.                 _next = next;
  5367.                 _tokens = tokens;
  5368.             }
  5369.            
  5370.         }
  5371.     }
  5372.    
  5373. }

Developer Fusion