Exemplo n.º 1
0
 public virtual void Visit(JsAspNetBlockNode node)
 {
     // no children
 }
 public void Visit(JsAspNetBlockNode node)
 {
     // invalid! ignore
     IsValid = false;
 }
Exemplo n.º 3
0
 public virtual void Visit(JsAspNetBlockNode node)
 {
     // no children
 }
 public void Visit(JsAspNetBlockNode node)
 {
     // nothing to do
 }
 public void Visit(JsAspNetBlockNode node)
 {
     // don't bother recursing, but let's wrap in parens, just in case
     // (since we don't know what will be inserted here)
     m_needsParens = true;
 }
Exemplo n.º 6
0
        private JsAstNode ParseStatement(bool fSourceElement, bool skipImportantComment = false)
        {
            JsAstNode statement = null;

            // if we want to skip important comments, now is a good time to clear anything we may
            // have picked up already.
            if (skipImportantComment)
            {
                m_importantComments.Clear();
            }

            if (m_importantComments.Count > 0
                && m_settings.PreserveImportantComments
                && m_settings.IsModificationAllowed(JsTreeModifications.PreserveImportantComments))
            {
                // we have at least one important comment before the upcoming statement.
                // pop the first important comment off the queue, return that node instead.
                // don't advance the token -- we'll probably be coming back again for the next one (if any)
                statement = new JsImportantComment(m_importantComments[0], this);
                m_importantComments.RemoveAt(0);
            }
            else
            {
                String id = null;
                var isNewModule = m_newModule;

                switch (m_currentToken.Token)
                {
                    case JsToken.EndOfFile:
                        EOFError(JsError.ErrorEndOfFile);
                        throw new EndOfStreamException(); // abort parsing, get back to the main parse routine
                    case JsToken.Semicolon:
                        // make an empty statement
                        statement = new JsEmptyStatement(m_currentToken.Clone(), this);
                        GetNextToken();
                        return statement;
                    case JsToken.RightCurly:
                        ReportError(JsError.SyntaxError);
                        SkipTokensAndThrow();
                        break;
                    case JsToken.LeftCurly:
                        return ParseBlock();
                    case JsToken.Debugger:
                        return ParseDebuggerStatement();
                    case JsToken.Var:
                    case JsToken.Const:
                    case JsToken.Let:
                        return ParseVariableStatement();
                    case JsToken.If:
                        return ParseIfStatement();
                    case JsToken.For:
                        return ParseForStatement();
                    case JsToken.Do:
                        return ParseDoStatement();
                    case JsToken.While:
                        return ParseWhileStatement();
                    case JsToken.Continue:
                        statement = ParseContinueStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.Break:
                        statement = ParseBreakStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.Return:
                        statement = ParseReturnStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.With:
                        return ParseWithStatement();
                    case JsToken.Switch:
                        return ParseSwitchStatement();
                    case JsToken.Throw:
                        statement = ParseThrowStatement();
                        if (statement == null)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            break;
                    case JsToken.Try:
                        return ParseTryStatement();
                    case JsToken.Function:
                        // parse a function declaration
                        JsFunctionObject function = ParseFunction(JsFunctionType.Declaration, m_currentToken.Clone());
                        function.IsSourceElement = fSourceElement;
                        return function;
                    case JsToken.Else:
                        ReportError(JsError.InvalidElse);
                        SkipTokensAndThrow();
                        break;
                    case JsToken.ConditionalCommentStart:
                        return ParseStatementLevelConditionalComment(fSourceElement);
                    case JsToken.ConditionalCompilationOn:
                        {
                            JsConditionalCompilationOn ccOn = new JsConditionalCompilationOn(m_currentToken.Clone(), this);
                            GetNextToken();
                            return ccOn;
                        }
                    case JsToken.ConditionalCompilationSet:
                        return ParseConditionalCompilationSet();
                    case JsToken.ConditionalCompilationIf:
                        return ParseConditionalCompilationIf(false);
                    case JsToken.ConditionalCompilationElseIf:
                        return ParseConditionalCompilationIf(true);
                    case JsToken.ConditionalCompilationElse:
                        {
                            JsConditionalCompilationElse elseStatement = new JsConditionalCompilationElse(m_currentToken.Clone(), this);
                            GetNextToken();
                            return elseStatement;
                        }
                    case JsToken.ConditionalCompilationEnd:
                        {
                            JsConditionalCompilationEnd endStatement = new JsConditionalCompilationEnd(m_currentToken.Clone(), this);
                            GetNextToken();
                            return endStatement;
                        }

                    default:
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                        bool exprError = false;
                        try
                        {
                            bool bAssign;
                            statement = ParseUnaryExpression(out bAssign, false);

                            // look for labels
                            if (statement is JsLookup && JsToken.Colon == m_currentToken.Token)
                            {
                                // can be a label
                                id = statement.ToString();
                                if (m_labelTable.ContainsKey(id))
                                {
                                    // there is already a label with that name. Ignore the current label
                                    ReportError(JsError.BadLabel, statement.Context.Clone(), true);
                                    id = null;
                                    GetNextToken(); // skip over ':'
                                    return new JsBlock(CurrentPositionContext(), this);
                                }
                                else
                                {
                                    var colonContext = m_currentToken.Clone();
                                    GetNextToken();
                                    int labelNestCount = m_labelTable.Count + 1;
                                    m_labelTable.Add(id, new LabelInfo(m_blockType.Count, labelNestCount));
                                    if (JsToken.EndOfFile != m_currentToken.Token)
                                    {
                                        // ignore any important comments between the label and its statement
                                        // because important comments are treated like statements, and we want
                                        // to make sure the label is attached to the right REAL statement.
                                        statement = new JsLabeledStatement(statement.Context.Clone(), this)
                                            {
                                                Label = id,
                                                ColonContext = colonContext,
                                                NestCount = labelNestCount,
                                                Statement = ParseStatement(fSourceElement, true)
                                            };
                                    }
                                    else
                                    {
                                        // end of the file!
                                        //just pass null for the labeled statement
                                        statement = new JsLabeledStatement(statement.Context.Clone(), this)
                                            {
                                                Label = id,
                                                ColonContext = colonContext,
                                                NestCount = labelNestCount
                                            };
                                    }
                                    m_labelTable.Remove(id);
                                    return statement;
                                }
                            }
                            statement = ParseExpression(statement, false, bAssign, JsToken.None);

                            // if we just started a new module and this statement happens to be an expression statement...
                            if (isNewModule && statement.IsExpression)
                            {
                                // see if it's a constant wrapper
                                var constantWrapper = statement as JsConstantWrapper;
                                if (constantWrapper != null && constantWrapper.PrimitiveType == JsPrimitiveType.String)
                                {
                                    // we found a string constant expression statement right after the start of a new
                                    // module. Let's make it a DirectivePrologue if it isn't already
                                    if (!(statement is JsDirectivePrologue))
                                    {
                                        statement = new JsDirectivePrologue(constantWrapper.Value.ToString(), constantWrapper.Context, this)
                                            {
                                                MayHaveIssues = constantWrapper.MayHaveIssues
                                            };
                                    }
                                }
                            }

                            var binaryOp = statement as JsBinaryOperator;
                            if (binaryOp != null
                                && (binaryOp.OperatorToken == JsToken.Equal || binaryOp.OperatorToken == JsToken.StrictEqual))
                            {
                                // an expression statement with equality operator? Doesn't really do anything.
                                // Did the developer intend this to be an assignment operator instead? Low-pri warning.
                                binaryOp.OperatorContext.IfNotNull(c => c.HandleError(JsError.SuspectEquality, false));
                            }

                            var lookup = statement as JsLookup;
                            if (lookup != null
                                && lookup.Name.StartsWith("<%=", StringComparison.Ordinal) && lookup.Name.EndsWith("%>", StringComparison.Ordinal))
                            {
                                // single lookup, but it's actually one or more ASP.NET blocks.
                                // convert back to an asp.net block node
                                statement = new JsAspNetBlockNode(statement.Context, this)
                                {
                                    AspNetBlockText = lookup.Name
                                };
                            }

                            var aspNetBlock = statement as JsAspNetBlockNode;
                            if (aspNetBlock != null && JsToken.Semicolon == m_currentToken.Token)
                            {
                                aspNetBlock.IsTerminatedByExplicitSemicolon = true;
                                statement.IfNotNull(s => s.TerminatingContext = m_currentToken.Clone());
                                GetNextToken();
                            }

                            // we just parsed an expression statement. Now see if we have an appropriate
                            // semicolon to terminate it.
                            if (JsToken.Semicolon == m_currentToken.Token)
                            {
                                statement.IfNotNull(s => s.TerminatingContext = m_currentToken.Clone());
                                GetNextToken();
                            }
                            else if (m_foundEndOfLine || JsToken.RightCurly == m_currentToken.Token || JsToken.EndOfFile == m_currentToken.Token)
                            {
                                // semicolon insertion rules
                                // (if there was no statement parsed, then don't fire a warning)
                                // a right-curly or an end of line is something we don't WANT to throw a warning for.
                                // Just too common and doesn't really warrant a warning (in my opinion)
                                if (statement != null
                                    && JsToken.RightCurly != m_currentToken.Token && JsToken.EndOfFile != m_currentToken.Token)
                                {
                                    ReportError(JsError.SemicolonInsertion, statement.Context.IfNotNull(c => c.FlattenToEnd()), true);
                                }
                            }
                            else
                            {
                                ReportError(JsError.NoSemicolon, true);
                            }
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (exc._partiallyComputedNode != null)
                                statement = exc._partiallyComputedNode;

                            if (statement == null)
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                                exprError = true;
                                SkipTokensAndThrow();
                            }

                            if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1)
                            {
                                exc._partiallyComputedNode = statement;
                                throw;
                            }
                        }
                        finally
                        {
                            if (!exprError)
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                        }
                        break;
                }
            }

            return statement;
        }
Exemplo n.º 7
0
        private JsAstNode ParseLeftHandSideExpression(bool isMinus)
        {
            JsAstNode ast = null;
            bool skipToken = true;
            List<JsContext> newContexts = null;

            TryItAgain:

            // new expression
            while (JsToken.New == m_currentToken.Token)
            {
                if (null == newContexts)
                    newContexts = new List<JsContext>(4);
                newContexts.Add(m_currentToken.Clone());
                GetNextToken();
            }
            JsToken token = m_currentToken.Token;
            switch (token)
            {
                // primary expression
                case JsToken.Identifier:
                    ast = new JsLookup(m_currentToken.Clone(), this)
                        {
                            Name = m_scanner.Identifier
                        };
                    break;

                case JsToken.ConditionalCommentStart:
                    // skip past the start to the next token
                    GetNextToken();
                    if (m_currentToken.Token == JsToken.ConditionalCompilationVariable)
                    {
                        // we have /*@id
                        ast = new JsConstantWrapperPP(m_currentToken.Clone(), this)
                            {
                                VarName = m_currentToken.Code,
                                ForceComments = true
                            };

                        GetNextToken();

                        if (m_currentToken.Token == JsToken.ConditionalCommentEnd)
                        {
                            // skip past the closing comment
                            GetNextToken();
                        }
                        else
                        {
                            // we ONLY support /*@id@*/ in expressions right now. If there's not
                            // a closing comment after the ID, then we don't support it.
                            // throw an error, skip to the end of the comment, then ignore it and start
                            // looking for the next token.
                            CCTooComplicated(null);
                            goto TryItAgain;
                        }
                    }
                    else if (m_currentToken.Token == JsToken.ConditionalCommentEnd)
                    {
                        // empty conditional comment! Ignore.
                        GetNextToken();
                        goto TryItAgain;
                    }
                    else
                    {
                        // we DON'T have "/*@IDENT". We only support "/*@IDENT @*/", so since this isn't
                        // and id, throw the error, skip to the end of the comment, and ignore it
                        // by looping back and looking for the NEXT token.
                        m_currentToken.HandleError(JsError.ConditionalCompilationTooComplex);

                        // skip to end of conditional comment
                        while (m_currentToken.Token != JsToken.EndOfFile && m_currentToken.Token != JsToken.ConditionalCommentEnd)
                        {
                            GetNextToken();
                        }
                        GetNextToken();
                        goto TryItAgain;
                    }
                    break;

                case JsToken.This:
                    ast = new JsThisLiteral(m_currentToken.Clone(), this);
                    break;

                case JsToken.StringLiteral:
                    ast = new JsConstantWrapper(m_scanner.StringLiteralValue, JsPrimitiveType.String, m_currentToken.Clone(), this)
                        {
                            MayHaveIssues = m_scanner.LiteralHasIssues
                        };
                    break;

                case JsToken.IntegerLiteral:
                case JsToken.NumericLiteral:
                    {
                        JsContext numericContext = m_currentToken.Clone();
                        double doubleValue;
                        if (ConvertNumericLiteralToDouble(m_currentToken.Code, (token == JsToken.IntegerLiteral), out doubleValue))
                        {
                            // conversion worked fine
                            // check for some boundary conditions
                            var mayHaveIssues = m_scanner.LiteralHasIssues;
                            if (doubleValue == double.MaxValue)
                            {
                                ReportError(JsError.NumericMaximum, numericContext, true);
                            }
                            else if (isMinus && -doubleValue == double.MinValue)
                            {
                                ReportError(JsError.NumericMinimum, numericContext, true);
                            }

                            // create the constant wrapper from the value
                            ast = new JsConstantWrapper(doubleValue, JsPrimitiveType.Number, numericContext, this)
                                {
                                    MayHaveIssues = mayHaveIssues
                                };
                        }
                        else
                        {
                            // if we went overflow or are not a number, then we will use the "Other"
                            // primitive type so we don't try doing any numeric calcs with it.
                            if (double.IsInfinity(doubleValue))
                            {
                                // overflow
                                // and if we ARE an overflow, report it
                                ReportError(JsError.NumericOverflow, numericContext, true);
                            }

                            // regardless, we're going to create a special constant wrapper
                            // that simply echos the input as-is
                            ast = new JsConstantWrapper(m_currentToken.Code, JsPrimitiveType.Other, numericContext, this)
                            {
                                MayHaveIssues = true
                            };
                        }
                        break;
                    }

                case JsToken.True:
                    ast = new JsConstantWrapper(true, JsPrimitiveType.Boolean, m_currentToken.Clone(), this);
                    break;

                case JsToken.False:
                    ast = new JsConstantWrapper(false, JsPrimitiveType.Boolean, m_currentToken.Clone(), this);
                    break;

                case JsToken.Null:
                    ast = new JsConstantWrapper(null, JsPrimitiveType.Null, m_currentToken.Clone(), this);
                    break;

                case JsToken.ConditionalCompilationVariable:
                    ast = new JsConstantWrapperPP(m_currentToken.Clone(), this)
                        {
                            VarName = m_currentToken.Code,
                            ForceComments = false
                        };
                    break;

                case JsToken.DivideAssign:
                // normally this token is not allowed on the left-hand side of an expression.
                // BUT, this might be the start of a regular expression that begins with an equals sign!
                // we need to test to see if we can parse a regular expression, and if not, THEN
                // we can fail the parse.

                case JsToken.Divide:
                    // could it be a regexp?
                    ast = ScanRegularExpression();
                    if (ast != null)
                    {
                        // yup -- we're done here
                        break;
                    }

                    // nope -- go to the default branch
                    goto default;

                // expression
                case JsToken.LeftParenthesis:
                    {
                        var groupingOp = new JsGroupingOperator(m_currentToken.Clone(), this);
                        ast = groupingOp;
                        GetNextToken();
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
                        try
                        {
                            // parse an expression
                            groupingOp.Operand = ParseExpression();
                            if (JsToken.RightParenthesis != m_currentToken.Token)
                            {
                                ReportError(JsError.NoRightParenthesis);
                            }
                            else
                            {
                                // add the closing paren to the expression context
                                ast.Context.UpdateWith(m_currentToken);
                            }
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (IndexOfToken(NoSkipTokenSet.s_ParenExpressionNoSkipToken, exc) == -1)
                                throw;
                            else
                                groupingOp.Operand = exc._partiallyComputedNode;
                        }
                        finally
                        {
                            m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
                        }
                    }
                    break;

                // array initializer
                case JsToken.LeftBracket:
                    JsContext listCtx = m_currentToken.Clone();
                    GetNextToken();
                    JsAstNodeList list = new JsAstNodeList(CurrentPositionContext(), this);
                    var hasTrailingCommas = false;
                    while (JsToken.RightBracket != m_currentToken.Token)
                    {
                        if (JsToken.Comma != m_currentToken.Token)
                        {
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
                            try
                            {
                                var expression = ParseExpression(true);
                                list.Append(expression);
                                if (JsToken.Comma != m_currentToken.Token)
                                {
                                    if (JsToken.RightBracket != m_currentToken.Token)
                                    {
                                        ReportError(JsError.NoRightBracket);
                                    }

                                    break;
                                }
                                else
                                {
                                    // we have a comma -- skip it after adding it as a terminator
                                    // on the previous expression
                                    var commaContext = m_currentToken.Clone();
                                    expression.IfNotNull(e => e.TerminatingContext = commaContext);
                                    GetNextToken();

                                    // if the next token is the closing brackets, then we need to
                                    // add a missing value to the array because we end in a comma and
                                    // we need to keep it for cross-platform compat.
                                    // TECHNICALLY, that puts an extra item into the array for most modern browsers, but not ALL.
                                    if (m_currentToken.Token == JsToken.RightBracket)
                                    {
                                        hasTrailingCommas = true;
                                        list.Append(new JsConstantWrapper(JsMissing.Value, JsPrimitiveType.Other, m_currentToken.Clone(), this));

                                        // throw a cross-browser warning about trailing commas
                                        commaContext.HandleError(JsError.ArrayLiteralTrailingComma);
                                        break;
                                    }
                                }
                            }
                            catch (RecoveryTokenException exc)
                            {
                                if (exc._partiallyComputedNode != null)
                                    list.Append(exc._partiallyComputedNode);
                                if (IndexOfToken(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet, exc) == -1)
                                {
                                    listCtx.UpdateWith(CurrentPositionContext());
                                    exc._partiallyComputedNode = new JsArrayLiteral(listCtx, this)
                                        {
                                            Elements = list,
                                            MayHaveIssues = true
                                        };
                                    throw;
                                }
                                else
                                {
                                    if (JsToken.RightBracket == m_currentToken.Token)
                                        break;
                                }
                            }
                            finally
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
                            }
                        }
                        else
                        {
                            // comma -- missing array item in the list
                            var commaContext = m_currentToken.Clone();
                            list.Append(new JsConstantWrapper(JsMissing.Value, JsPrimitiveType.Other, m_currentToken.Clone(), this)
                                {
                                    TerminatingContext = commaContext
                                });

                            // skip over the comma
                            GetNextToken();

                            // if the next token is the closing brace, then we end with a comma -- and we need to
                            // add ANOTHER missing value to make sure this last comma doesn't get left off.
                            // TECHNICALLY, that puts an extra item into the array for most modern browsers, but not ALL.
                            if (m_currentToken.Token == JsToken.RightBracket)
                            {
                                hasTrailingCommas = true;
                                list.Append(new JsConstantWrapper(JsMissing.Value, JsPrimitiveType.Other, m_currentToken.Clone(), this));

                                // throw a cross-browser warning about trailing commas
                                commaContext.HandleError(JsError.ArrayLiteralTrailingComma);
                                break;
                            }
                        }
                    }

                    listCtx.UpdateWith(m_currentToken);
                    ast = new JsArrayLiteral(listCtx, this)
                        {
                            Elements = list,
                            MayHaveIssues = hasTrailingCommas
                        };
                    break;

                // object initializer
                case JsToken.LeftCurly:
                    JsContext objCtx = m_currentToken.Clone();
                    GetNextToken();

                    var propertyList = new JsAstNodeList(CurrentPositionContext(), this);

                    if (JsToken.RightCurly != m_currentToken.Token)
                    {
                        for (; ; )
                        {
                            JsObjectLiteralField field = null;
                            JsAstNode value = null;
                            bool getterSetter = false;
                            string ident;

                            switch (m_currentToken.Token)
                            {
                                case JsToken.Identifier:
                                    field = new JsObjectLiteralField(m_scanner.Identifier, JsPrimitiveType.String, m_currentToken.Clone(), this);
                                    break;

                                case JsToken.StringLiteral:
                                    field = new JsObjectLiteralField(m_scanner.StringLiteralValue, JsPrimitiveType.String, m_currentToken.Clone(), this)
                                        {
                                            MayHaveIssues = m_scanner.LiteralHasIssues
                                        };
                                    break;

                                case JsToken.IntegerLiteral:
                                case JsToken.NumericLiteral:
                                    {
                                        double doubleValue;
                                        if (ConvertNumericLiteralToDouble(m_currentToken.Code, (m_currentToken.Token == JsToken.IntegerLiteral), out doubleValue))
                                        {
                                            // conversion worked fine
                                            field = new JsObjectLiteralField(
                                              doubleValue,
                                              JsPrimitiveType.Number,
                                              m_currentToken.Clone(),
                                              this
                                              );
                                        }
                                        else
                                        {
                                            // something went wrong and we're not sure the string representation in the source is
                                            // going to convert to a numeric value well
                                            if (double.IsInfinity(doubleValue))
                                            {
                                                ReportError(JsError.NumericOverflow, m_currentToken.Clone(), true);
                                            }

                                            // use the source as the field name, not the numeric value
                                            field = new JsObjectLiteralField(
                                                m_currentToken.Code,
                                                JsPrimitiveType.Other,
                                                m_currentToken.Clone(),
                                                this);
                                        }
                                        break;
                                    }

                                case JsToken.Get:
                                case JsToken.Set:
                                    if (PeekToken() == JsToken.Colon)
                                    {
                                        // the field is either "get" or "set" and isn't the special Mozilla getter/setter
                                        field = new JsObjectLiteralField(m_currentToken.Code, JsPrimitiveType.String, m_currentToken.Clone(), this);
                                    }
                                    else
                                    {
                                        // ecma-script get/set property construct
                                        getterSetter = true;
                                        bool isGet = (m_currentToken.Token == JsToken.Get);
                                        value = ParseFunction(
                                          (JsToken.Get == m_currentToken.Token ? JsFunctionType.Getter : JsFunctionType.Setter),
                                          m_currentToken.Clone()
                                          );
                                        JsFunctionObject funcExpr = value as JsFunctionObject;
                                        if (funcExpr != null)
                                        {
                                            // getter/setter is just the literal name with a get/set flag
                                            field = new JsGetterSetter(
                                              funcExpr.Name,
                                              isGet,
                                              funcExpr.IdContext.Clone(),
                                              this
                                              );
                                        }
                                        else
                                        {
                                            ReportError(JsError.FunctionExpressionExpected);
                                        }
                                    }
                                    break;

                                default:
                                    // NOT: identifier token, string, number, or getter/setter.
                                    // see if it's a token that COULD be an identifierName.
                                    ident = m_scanner.Identifier;
                                    if (JsScanner.IsValidIdentifier(ident))
                                    {
                                        // BY THE SPEC, if it's a valid identifierName -- which includes reserved words -- then it's
                                        // okay for object literal syntax. However, reserved words here won't work in all browsers,
                                        // so if it is a reserved word, let's throw a low-sev cross-browser warning on the code.
                                        if (JsKeyword.CanBeIdentifier(m_currentToken.Token) == null)
                                        {
                                            ReportError(JsError.ObjectLiteralKeyword, m_currentToken.Clone(), true);
                                        }

                                        field = new JsObjectLiteralField(ident, JsPrimitiveType.String, m_currentToken.Clone(), this);
                                    }
                                    else
                                    {
                                        // throw an error but use it anyway, since that's what the developer has going on
                                        ReportError(JsError.NoMemberIdentifier, m_currentToken.Clone(), true);
                                        field = new JsObjectLiteralField(m_currentToken.Code, JsPrimitiveType.String, m_currentToken.Clone(), this);
                                    }
                                    break;
                            }

                            if (field != null)
                            {
                                if (!getterSetter)
                                {
                                    GetNextToken();
                                }

                                m_noSkipTokenSet.Add(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
                                try
                                {
                                    if (!getterSetter)
                                    {
                                        // get the value
                                        if (JsToken.Colon != m_currentToken.Token)
                                        {
                                            ReportError(JsError.NoColon, true);
                                            value = ParseExpression(true);
                                        }
                                        else
                                        {
                                            field.ColonContext = m_currentToken.Clone();
                                            GetNextToken();
                                            value = ParseExpression(true);
                                        }
                                    }

                                    // put the pair into the list of fields
                                    var propCtx = field.Context.Clone().CombineWith(value.IfNotNull(v => v.Context));
                                    var property = new JsObjectLiteralProperty(propCtx, this)
                                        {
                                            Name = field,
                                            Value = value
                                        };

                                    propertyList.Append(property);

                                    if (JsToken.RightCurly == m_currentToken.Token)
                                    {
                                        break;
                                    }
                                    else
                                    {
                                        if (JsToken.Comma == m_currentToken.Token)
                                        {
                                            // skip the comma after adding it to the property as a terminating context
                                            property.IfNotNull(p => p.TerminatingContext = m_currentToken.Clone());
                                            GetNextToken();

                                            // if the next token is the right-curly brace, then we ended
                                            // the list with a comma, which is perfectly fine
                                            if (m_currentToken.Token == JsToken.RightCurly)
                                            {
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            if (m_foundEndOfLine)
                                            {
                                                ReportError(JsError.NoRightCurly);
                                            }
                                            else
                                                ReportError(JsError.NoComma, true);
                                            SkipTokensAndThrow();
                                        }
                                    }
                                }
                                catch (RecoveryTokenException exc)
                                {
                                    if (exc._partiallyComputedNode != null)
                                    {
                                        // the problem was in ParseExpression trying to determine value
                                        value = exc._partiallyComputedNode;

                                        var propCtx = field.Context.Clone().CombineWith(value.IfNotNull(v => v.Context));
                                        var property = new JsObjectLiteralProperty(propCtx, this)
                                        {
                                            Name = field,
                                            Value = value
                                        };

                                        propertyList.Append(property);
                                    }

                                    if (IndexOfToken(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet, exc) == -1)
                                    {
                                        exc._partiallyComputedNode = new JsObjectLiteral(objCtx, this)
                                            {
                                                Properties = propertyList
                                            };
                                        throw;
                                    }
                                    else
                                    {
                                        if (JsToken.Comma == m_currentToken.Token)
                                            GetNextToken();
                                        if (JsToken.RightCurly == m_currentToken.Token)
                                            break;
                                    }
                                }
                                finally
                                {
                                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
                                }
                            }
                        }
                    }
                    objCtx.UpdateWith(m_currentToken);
                    ast = new JsObjectLiteral(objCtx, this)
                        {
                            Properties = propertyList
                        };
                    break;

                // function expression
                case JsToken.Function:
                    ast = ParseFunction(JsFunctionType.Expression, m_currentToken.Clone());
                    skipToken = false;
                    break;

                case JsToken.AspNetBlock:
                    ast = new JsAspNetBlockNode(m_currentToken.Clone(), this)
                        {
                            AspNetBlockText = m_currentToken.Code
                        };
                    break;

                default:
                    string identifier = JsKeyword.CanBeIdentifier(m_currentToken.Token);
                    if (null != identifier)
                    {
                        ast = new JsLookup(m_currentToken.Clone(), this)
                            {
                                Name = identifier
                            };
                    }
                    else
                    {
                        ReportError(JsError.ExpressionExpected);
                        SkipTokensAndThrow();
                    }
                    break;
            }

            // can be a CallExpression, that is, followed by '.' or '(' or '['
            if (skipToken)
                GetNextToken();

            return MemberExpression(ast, newContexts);
        }
 public void Visit(JsAspNetBlockNode node)
 {
     // not applicable; terminate
 }
        public void Visit(JsAspNetBlockNode node)
        {
            if (node != null)
            {
                Output(node.AspNetBlockText);
                MarkSegment(node, null, node.Context);
                SetContextOutputPosition(node.Context);

                m_startOfStatement = false;
            }
        }