public void Visit(JsImportantComment node) { // comment, so we need to keep going }
public void Visit(JsImportantComment node) { // invalid! ignore IsValid = false; }
public void Visit(JsImportantComment node) { // not applicable; terminate }
public void Visit(JsImportantComment node) { // don't recurse }
public void Visit(JsImportantComment node) { // nothing to do }
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; }
public void Visit(JsImportantComment node) { if (node != null) { var symbol = StartSymbol(node); // make sure we force the important comments to start on a new line, regardless // of whether or not we are in multi- or single-line mode, and the statement after // should also be on a new line. BreakLine(true); node.Context.OutputLine = m_lineCount; // the output method assumes any text we send it's way doesn't contain any line feed // characters. The important comment, however, may contain some. We don't want to count // the entire comment as a single line, AND we want to normalize the line-feed characters, // so lets process the comment line-by-line var lineFeedChars = new[] { '\n', '\r', '\u2028', '\u2029' }; var startIndex = 0; var firstLF = node.Comment.IndexOfAny(lineFeedChars, startIndex); if (firstLF < 0) { // no line-breaks at all! Output(node.Comment); } else { // output the first segment -- from start to first line break Output(node.Comment.Substring(0, firstLF)); while (true) { // advance the next segment pointer if (node.Comment[firstLF] == '\r' && firstLF < node.Comment.Length - 1 && node.Comment[firstLF + 1] == '\n') { startIndex = firstLF + 2; } else { startIndex = firstLF + 1; } // force the line-break in the output BreakLine(true); // look for the next line break firstLF = node.Comment.IndexOfAny(lineFeedChars, startIndex); if (firstLF > startIndex) { // only output something if there was something before the next line break Output(node.Comment.Substring(startIndex, firstLF - startIndex)); } else if (firstLF < 0) { // no more line-breaks -- output the last segment and break out of the loop Output(node.Comment.Substring(startIndex)); break; } } } // force a line-break AFTER teh important comment as well BreakLine(true); EndSymbol(symbol); } }