private ScriptRawStatement ParseRawStatement() { ScriptRawStatement scriptStatement = Open <ScriptRawStatement>(); // We keep span End here to update it with the raw span TextPosition spanEnd = Current.End; // If we have an escape, we can fetch the escape count if (Current.Type == TokenType.Escape) { NextToken(); // Skip escape if (Current.Type < TokenType.EscapeCount1 && Current.Type > TokenType.EscapeCount9) { LogError(Current, string.Format(RS.ExpectEscapeCount, GetAsText(Current))); } else { scriptStatement.EscapeCount = (Current.Type - TokenType.EscapeCount1) + 1; } } scriptStatement.Text = _lexer.Text; NextToken(); // Skip raw or escape count Close(scriptStatement); // Because the previous will update the ScriptStatement with the wrong Span End for escape (escapecount1+) // We make sure that we use the span end of the Raw token scriptStatement.Span.End = spanEnd; return(scriptStatement); }
public TemplateRewriterContext Write(ScriptNode node) { if (node != null) { bool pushedWhileLoop = false; if (node is ScriptLoopStatementBase) { _isWhileLoop.Push(node is ScriptWhileStatement); pushedWhileLoop = true; } try { WriteBegin(node); node.Write(this); WriteEnd(node); } finally { if (pushedWhileLoop) { _isWhileLoop.Pop(); } if (!IsBlockOrPage(node)) { _previousRawStatement = node as ScriptRawStatement; } } } return(this); }
private bool TryParseStatement(ScriptStatement parent, out ScriptStatement statement, out bool hasEnd) { hasEnd = false; bool nextStatement = true; statement = null; continueParsing: if (_hasFatalError) { return(false); } if (_pendingStatements.Count > 0) { statement = _pendingStatements.Dequeue(); return(true); } switch (Current.Type) { case TokenType.Eof: // Early exit nextStatement = false; break; case TokenType.Raw: case TokenType.Escape: statement = ParseRawStatement(); if (parent is ScriptCaseStatement) { // In case we have a raw statement within directly a case // we don't keep it statement = null; goto continueParsing; } break; case TokenType.CodeEnter: case TokenType.LiquidTagEnter: if (_inCodeSection) { LogError(RS.UnexpectedTokenInCodeBlock); } _isLiquidTagSection = Current.Type == TokenType.LiquidTagEnter; _inCodeSection = true; // If we have any pending trivias before processing this code enter and we want to keep trivia // we need to generate a RawStatement to store these trivias if (_isKeepTrivia && (_trivias.Count > 0 || Previous.Type == TokenType.CodeEnter)) { ScriptRawStatement rawStatement = Open <ScriptRawStatement>(); Close(rawStatement); if (_trivias.Count > 0) { rawStatement.Trivias.After.AddRange(rawStatement.Trivias.Before); rawStatement.Trivias.Before.Clear(); SourceSpan firstTriviaSpan = rawStatement.Trivias.After[0].Span; SourceSpan lastTriviaSpan = rawStatement.Trivias.After[rawStatement.Trivias.After.Count - 1].Span; rawStatement.Span = new SourceSpan(firstTriviaSpan.FileName, firstTriviaSpan.Start, lastTriviaSpan.End); } else { // Else Add an empty trivia rawStatement.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Empty, null), false); } statement = rawStatement; } NextToken(); if (Current.Type == TokenType.CodeExit) { ScriptNopStatement nopStatement = Open <ScriptNopStatement>(); Close(nopStatement); if (statement == null) { statement = nopStatement; } else { _pendingStatements.Enqueue(nopStatement); } } // If we have a ScriptRawStatement previously defined, we need to break out of the loop to record it if (statement == null) { goto continueParsing; } break; case TokenType.FrontMatterMarker: if (_inFrontMatter) { _inFrontMatter = false; _inCodeSection = false; // When we expect to parse only the front matter, don't try to tokenize the following text // Keep the current token as the code exit of the front matter if (CurrentParsingMode != ScriptMode.FrontMatterOnly) { NextToken(); } if (CurrentParsingMode == ScriptMode.FrontMatterAndContent || CurrentParsingMode == ScriptMode.FrontMatterOnly) { // Once the FrontMatter has been parsed, we can switch to default parsing mode. CurrentParsingMode = ScriptMode.Default; nextStatement = false; } } else { LogError(string.Format(RS.UnexpectedFrontMatterMarker, _lexer.Options.FrontMatterMarker)); NextToken(); } break; case TokenType.CodeExit: case TokenType.LiquidTagExit: if (!_inCodeSection) { LogError(RS.OrphanCodeBlockExitError); } else if (CurrentParsingMode == ScriptMode.ScriptOnly) { LogError(RS.CodeBlockNotAllowedInScriptMode); } _isLiquidTagSection = false; _inCodeSection = false; // We clear any trivia that might not have been takend by a node // so that they don't end up after this token if (_isKeepTrivia) { _trivias.Clear(); } NextToken(); // If next token is directly a code enter or an eof but we want to keep trivia // and with have trivias // we need to generate a RawStatement to store these trivias if (_isKeepTrivia && (Current.Type == TokenType.CodeEnter || Current.Type == TokenType.Eof)) { ScriptRawStatement rawStatement = Open <ScriptRawStatement>(); Close(rawStatement); if (_trivias.Count > 0) { SourceSpan firstTriviaSpan = rawStatement.Trivias.Before[0].Span; SourceSpan lastTriviaSpan = rawStatement.Trivias.Before[rawStatement.Trivias.Before.Count - 1].Span; rawStatement.Span = new SourceSpan(firstTriviaSpan.FileName, firstTriviaSpan.Start, lastTriviaSpan.End); } else { // Else Add an empty trivia rawStatement.AddTrivia(new ScriptTrivia(CurrentSpan, ScriptTriviaType.Empty, null), false); } statement = rawStatement; } else { goto continueParsing; } break; default: if (_inCodeSection) { switch (Current.Type) { case TokenType.NewLine: case TokenType.SemiColon: PushTokenToTrivia(); NextToken(); goto continueParsing; case TokenType.Identifier: case TokenType.IdentifierSpecial: string identifier = GetAsText(Current); if (_isLiquid) { ParseLiquidStatement(identifier, parent, ref statement, ref hasEnd, ref nextStatement); } else { ParseTextScriptStatement(identifier, parent, ref statement, ref hasEnd, ref nextStatement); } break; default: if (StartAsExpression()) { statement = ParseExpressionStatement(); } else { nextStatement = false; LogError(string.Format(RS.UnexpectedToken, Current.Type)); } break; } } else { nextStatement = false; LogError(string.Format(RS.UnexpectedTokenOutsideCodeBlock, Current.Type)); // LOG an ERROR. Don't expect any other tokens outside a code section } break; } return(nextStatement); }