protected override bool ParseInheritsStatement(CodeBlockInfo block) { _endInheritsLocation = CurrentLocation; bool result = base.ParseInheritsStatement(block); CheckForInheritsAndModelStatements(); return result; }
protected CodeBlockInfo ParseBlockStart(bool isTopLevel, bool captureTransition) { // Capture the transition token, if any, into a span Span transitionSpan = null; if (HaveContent && captureTransition) { transitionSpan = TransitionSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None); Context.ResetBuffers(); } SourceLocation start = CurrentLocation; string identifier = Context.AcceptIdentifier(); Span initialSpan = null; if (isTopLevel) { initialSpan = CodeSpan.Create(Context); Context.ResetBuffers(); } CodeBlockInfo block = new CodeBlockInfo(identifier, start, isTopLevel, transitionSpan, initialSpan); return(block); }
/// <summary> /// Parses the model statement. /// </summary> /// <param name="block">The code block.</param> private bool ParseModelStatement(CodeBlockInfo block) { var location = CurrentLocation; bool readWhiteSpace = RequireSingleWhiteSpace(); End(MetaCodeSpan.Create(Context, false, readWhiteSpace ? AcceptedCharacters.None : AcceptedCharacters.Any)); if (_modelOrInheritsStatementFound) OnError(location, "The model or inherits keywords can only appear once."); _modelOrInheritsStatementFound = true; Context.AcceptWhiteSpace(false); string typeName = null; if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { using (Context.StartTemporaryBuffer()) { Context.AcceptUntil(ParserHelpers.IsNewLine); typeName = Context.ContentBuffer.ToString(); Context.AcceptTemporaryBuffer(); } Context.AcceptNewLine(); } else { OnError(location, "Expected model identifier."); } End(new ModelSpan(Context, typeName)); return false; }
private bool ParseModelStatement(CodeBlockInfo block) { SourceLocation endModelLocation = CurrentLocation; bool readWhitespace = RequireSingleWhiteSpace(); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: readWhitespace ? AcceptedCharacters.None : AcceptedCharacters.Any)); if (_modelStatementFound) { OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture, MvcResources.MvcRazorCodeParser_OnlyOneModelStatementIsAllowed, ModelKeyword)); } _modelStatementFound = true; // Accept Whitespace up to the new line or non-whitespace character Context.AcceptWhiteSpace(includeNewLines: false); string typeName = null; if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { using (Context.StartTemporaryBuffer()) { Context.AcceptUntil(c => ParserHelpers.IsNewLine(c)); typeName = Context.ContentBuffer.ToString(); Context.AcceptTemporaryBuffer(); } Context.AcceptNewLine(); } else { OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture, MvcResources.MvcRazorCodeParser_ModelKeywordMustBeFollowedByTypeName, ModelKeyword)); } CheckForInheritsAndModelStatements(); End(new ModelSpan(Context, typeName)); return false; }
private bool ParseModelStatement(CodeBlockInfo block) { var currentLocation = this.CurrentLocation; var acceptedCharacters = this.RequireSingleWhiteSpace() ? AcceptedCharacters.None : AcceptedCharacters.Any; this.End(MetaCodeSpan.Create(this.Context, false, acceptedCharacters)); if (this.modelStatementFound) this.OnError(currentLocation, string.Format(CultureInfo.CurrentCulture, "Only one @model statement is allowed.")); this.modelStatementFound = true; this.Context.AcceptWhiteSpace(false); string modelTypeName = null; if (ParserHelpers.IsIdentifierStart(this.CurrentCharacter)) { using (this.Context.StartTemporaryBuffer()) { this.Context.AcceptUntil(c => ParserHelpers.IsNewLine(c)); modelTypeName = this.Context.ContentBuffer.ToString(); this.Context.AcceptTemporaryBuffer(); } this.Context.AcceptNewLine(); } else { this.OnError(currentLocation, string.Format(CultureInfo.CurrentCulture, "@model must be followed by a type name.")); } this.CheckForInheritsAndModelStatements(); this.End(new ModelSpan(this.Context, modelTypeName)); return false; }
protected override bool ParseInheritsStatement(CodeBlockInfo block) { this.endInheritsLocation = this.CurrentLocation; var result = this.ParseInheritsStatement(block); this.CheckForInheritsAndModelStatements(); return result; }
private bool ParseResourceStatement(CodeBlockInfo block) { End(MetaCodeSpan.Create); SourceLocation endModelLocation = CurrentLocation; if (_modelStatementFound) { OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture, "Only one '{0}' statement is allowed in a file.", ResourceKeyword)); } _modelStatementFound = true; // Accept Whitespace up to the new line or non-whitespace character Context.AcceptWhiteSpace(false); string typeName = null; if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { using (Context.StartTemporaryBuffer()) { // Accept a dotted-identifier, but allow <> AcceptTypeName(); typeName = Context.ContentBuffer.ToString(); Context.AcceptTemporaryBuffer(); } } else { OnError(endModelLocation, String.Format(CultureInfo.CurrentCulture, "The '{0}' keyword must be followed by a type name on the same line.", ResourceKeyword)); } CheckForInheritsAndResourceStatements(); End(ResourceSpan.Create(Context, typeName)); return false; }
/// <summary> /// Parses the inherits statement. /// </summary> /// <param name="block">The code block.</param> protected override bool ParseInheritsStatement(CodeBlockInfo block) { var location = CurrentLocation; if (_modelOrInheritsStatementFound) OnError(location, "The model or inherits keywords can only appear once."); _modelOrInheritsStatementFound = true; return base.ParseInheritsStatement(block); }
/// <summary> /// Parses the modeltype statement. /// </summary> /// <param name="block">The code block.</param> public bool ParseModelTypeStatement(CodeBlockInfo block) { //Contract.Requires(block != null); using (StartBlock(BlockType.Directive)) { block.ResumeSpans(Context); SourceLocation location = CurrentLocation; bool readWhitespace = RequireSingleWhiteSpace(); End(MetaCodeSpan.Create(Context, false, readWhitespace ? AcceptedCharacters.None : AcceptedCharacters.Any)); if (_modelOrInheritsStatementFound) OnError(location, "The modeltype or inherits keywords can only appear once."); _modelOrInheritsStatementFound = true; // Accept Whitespace up to the new line or non-whitespace character Context.AcceptWhiteSpace(false); string typeName = null; if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { using (Context.StartTemporaryBuffer()) { Context.AcceptUntil(ParserHelpers.IsNewLine); typeName = Context.ContentBuffer.ToString(); Context.AcceptTemporaryBuffer(); } Context.AcceptNewLine(); } else { OnError(location, "Expected model identifier."); } End(new ModelSpan(Context, typeName)); } return false; }
private bool ParseUsingStatement(CodeBlockInfo block) { if (block.IsTopLevel) { Context.ResumeSpan(block.InitialSpan); } using (Context.StartTemporaryBuffer()) { // Skip whitespace by lines Context.AcceptWhiteSpace(includeNewLines: false); if (CurrentCharacter == '(') { Context.AcceptTemporaryBuffer(); // Parse like a regular control flow statement if (block.IsTopLevel) { block.InitialSpan = CodeSpan.Create(Context); Context.ResetBuffers(); StartBlock(BlockType.Statement); block.ResumeSpans(Context); } return ParseConditionalBlockStatement(block); } else if (!block.IsTopLevel) { Context.RejectTemporaryBuffer(); // Not the right kind of using for this block. We're not in a top-level block and we saw a namespace import or type alias OnError(block.Start, RazorResources.ParseError_NamespaceImportAndTypeAlias_Cannot_Exist_Within_CodeBlock); } else if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { Context.RejectTemporaryBuffer(); // Parse a namespace import block.InitialSpan = CodeSpan.Create(Context); Context.ResetBuffers(); StartBlock(BlockType.Directive); block.ResumeSpans(Context); ParseNamespaceImport(); return true; } else { if (block.IsTopLevel) { Context.AcceptTemporaryBuffer(); block.InitialSpan = CodeSpan.Create(Context); Context.ResetBuffers(); StartBlock(BlockType.Statement); block.ResumeSpans(Context); } } } return false; }
protected internal virtual bool ParseIfStatement(CodeBlockInfo block) { SourceLocation errorLocation = CurrentLocation; // Parse the body ParseConditionalBlockStatement(block); // Parse the attached branches do { // Start a temporary buffer just in case we don't see the branch we expected Context.StartTemporaryBuffer(); AcceptWhiteSpaceAndComments(); errorLocation = CurrentLocation; // If the first character after the whitespace isn't an identifier, or comment we're done // If the first character is an identifier but isn't "else", we're also done if (!ParserHelpers.IsIdentifierStart(CurrentCharacter) || !String.Equals("else", Context.AcceptIdentifier(), StringComparison.Ordinal)) { Context.RejectTemporaryBuffer(); break; } else { Context.AcceptTemporaryBuffer(); } bool isElseIf = false; using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); // Now, we need to check for "else if" if (ParserHelpers.IsIdentifierStart(CurrentCharacter) && String.Equals("if", Context.AcceptIdentifier(), StringComparison.Ordinal)) { isElseIf = true; // It's an else if branch, parse a condition AND a body Context.AcceptTemporaryBuffer(); Context.AcceptWhiteSpace(includeNewLines: true); ParseConditionalBlockStatement(new CodeBlockInfo("else if", errorLocation, false)); } else if (CurrentCharacter == '{') { // It's a valid else Context.AcceptTemporaryBuffer(); } else { // Brace-less else OnError(CurrentLocation, RazorResources.ParseError_SingleLine_ControlFlowStatements_Not_Allowed, "{", CurrentCharacter); } } // Have to do this because the using() {} block can't overlap with the if and we want the temporary buffer cleared up before this point if (!isElseIf) { // It's an else branch, just parse a body CodeBlockInfo elseBlock = new CodeBlockInfo("else", errorLocation, false); if (CurrentCharacter == '{') { return ParseCodeBlock(elseBlock, bracesAreMetacode: false); } else { ParseStatement(elseBlock); return false; } } } while (!EndOfFile); return false; }
protected internal virtual bool ParseCaseBlock(CodeBlockInfo block) { // TODO: Only allow case and default statements directly within switch statement // Parse until the ':' Context.AcceptUntilInclusive(':'); while (!EndOfFile) { using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); string identifier = Context.AcceptIdentifier(); if (String.Equals(identifier, "case", StringComparison.OrdinalIgnoreCase) || String.Equals(identifier, "default", StringComparison.OrdinalIgnoreCase)) { // Reached the next case block break; } else if (CurrentCharacter == '}') { // Reached the end of the switch, but we don't handle the '}' break; } } ParseStatement(block); } return false; }
protected internal virtual bool ParseTryStatement(CodeBlockInfo block) { // Parse the body ParseControlFlowBody(block); // Check for additional clauses bool allowAdditionalClauses = false; do { allowAdditionalClauses = false; Context.StartTemporaryBuffer(); AcceptWhiteSpaceAndComments(); if (!ParserHelpers.IsIdentifierStart(CurrentCharacter)) { Context.RejectTemporaryBuffer(); } else { SourceLocation blockStart = CurrentLocation; string identifier = Context.AcceptIdentifier(); if (String.Equals(identifier, "catch")) { Context.AcceptTemporaryBuffer(); ParseConditionalBlockStatement(new CodeBlockInfo("catch", blockStart, false)); allowAdditionalClauses = true; } else if (String.Equals(identifier, "finally")) { Context.AcceptTemporaryBuffer(); // After the "finally" we know we're done, but only if it's complete return ParseControlFlowBody(new CodeBlockInfo("finally", blockStart, false)); } else { Context.RejectTemporaryBuffer(); } } } while (allowAdditionalClauses); return false; }
protected internal virtual bool ParseDoStatement(CodeBlockInfo block) { // Parse the body bool bodyComplete = ParseControlFlowBody(block); // Check for a while clause and return if it's not there (C# requires it, but there's no real reason we need to, C# can report the error if it's missing) Context.StartTemporaryBuffer(); AcceptWhiteSpaceAndComments(); if (!Context.Peek("while", caseSensitive: true)) { Context.RejectTemporaryBuffer(); return false; } Context.AcceptTemporaryBuffer(); // Parse the while clause string whileKeyword = Context.AcceptIdentifier(); Debug.Assert(whileKeyword == "while"); Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter == '(') { SourceLocation errorLocation = CurrentLocation; if (!BalanceBrackets()) { Context.AcceptLine(includeNewLineSequence: false); OnError(errorLocation, RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"); } } if (CurrentCharacter == ';') { Context.AcceptCurrent(); return bodyComplete; // The while clause is complete } return false; }
private bool ParseFunctionsBlock(CodeBlockInfo block) { Debug.Assert(block.IsTopLevel, "Class blocks are only allowed at the top level"); Context.ResumeSpan(block.InitialSpan); using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter == '{') { Context.AcceptWhiteSpace(includeNewLines: true); } else { Context.RejectTemporaryBuffer(); block.InitialSpan = CodeSpan.Create(Context); Context.ResetBuffers(); StartBlock(BlockType.Expression); block.ResumeSpans(Context); ParseImplicitExpression(block); return false; } } block.InitialSpan = MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None); Context.ResetBuffers(); StartBlock(BlockType.Functions); block.ResumeSpans(Context); return ParseDelimitedBlock(block, useErrorRecovery: false, autoCompleteString: "}"); }
private bool ParseImplicitExpression(CodeBlockInfo block) { return ParseImplicitExpression(block, acceptTrailingDot: false); }
private bool ParseImportsStatement(CodeBlockInfo block) { using (StartBlock(BlockType.Directive)) { string ns = String.Empty; block.ResumeSpans(Context); using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: false); if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { Context.AcceptIdentifier(); if (CurrentCharacter == '.') { // Definitely a namespace import Context.AcceptCurrent(); AcceptTypeName(allowGenerics: false); } else { // Could be an alias, need to check what's after whitespace using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: false); if (CurrentCharacter == '=') { Context.AcceptTemporaryBuffer(); Context.AcceptCurrent(); Context.AcceptWhiteSpace(includeNewLines: false); if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { AcceptTypeName(); } else { OnError(CurrentLocation, RazorResources.ParseError_NamespaceOrTypeAliasExpected); } } } } // Capture the content of the temporary buffer as the namespace ns = Context.ContentBuffer.ToString(); } else { OnError(CurrentLocation, RazorResources.ParseError_NamespaceOrTypeAliasExpected); } Context.AcceptTemporaryBuffer(); // Capture trailing whitespace to the end of the line Context.AcceptWhiteSpace(includeNewLines: false); if (ParserHelpers.IsNewLine(Context.CurrentCharacter)) { Context.AcceptNewLine(); } } End(NamespaceImportSpan.Create(Context, acceptedCharacters: AcceptedCharacters.Any, kind: SpanKind.MetaCode, ns: ns, namespaceKeywordLength: ImportsKeywordLength)); } return true; }
// Example statements: // foreach(var f in Foo) [statement] // { [statement-list] } // <tag>[markup]</tag> protected internal virtual void ParseStatement(CodeBlockInfo block) { // Check for markup, because that will change the whitespace handling // Dev10 Bug 884969 - Emit space between markup and code // Whitespace ownership rules: // * If there's no markup on a line, all the whitespace (including the trailing newline) belongs to code // * Markup owns all markup from its start character back to, but excluding, the preceding newline (or the start of code) // * Markup owns all markup from its end character up to, and including, the trailing newline (or the start of code) Context.StartTemporaryBuffer(); // Eat whitespace until a non-whitespace character, AcceptWhiteSpaceByLines(); // Error Detection: Check for @<p>Foo</p> and display an error if (CurrentCharacter == RazorParser.TransitionCharacter && Context.MarkupParser.NextIsTransition(allowImplicit: true, allowExplicit: false)) { Context.AcceptTemporaryBufferInDesignTimeMode(); ParseInvalidMarkupSwitch(); return; } // It's markup, so the whitespace belongs to the markup at runtime else if (Context.MarkupParser.IsAtImplicitTransition() || (CurrentCharacter == RazorParser.TransitionCharacter && Context.MarkupParser.NextIsTransition(allowImplicit: false, allowExplicit: true))) { Context.AcceptTemporaryBufferInDesignTimeMode(); ParseBlockWithOtherParser(previousSpanFactory: CodeSpan.Create); return; } // No markup on this line, so it's whitespace belongs to code. Context.AcceptTemporaryBuffer(); // Ok, not markup at this point, so check for C# statements and other statements if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { CodeBlockInfo subBlock = ParseBlockStart(isTopLevel: false, captureTransition: false); BlockParser parser = GetBlockParser(subBlock, null); if (parser != null) { // Block type is always the same as the current one since Plan9 Keywords aren't allowed here, so merge it into the current block parser(subBlock); } else { AcceptStatementToSemicolon(); } } // Use the first character to determine if it's something we need to handle specially else if (CurrentCharacter == RazorParser.TransitionCharacter) { if (!TryParseComment(previousSpanFactory: CodeSpan.Create)) { // "@[expr]" ==> Shorthand for Write([expr]); ParseEmbeddedExpression(); } } else if (CurrentCharacter == '{') { // "{ [statement-list] }" ==> Start of a code block ParseCodeBlock(block, bracesAreMetacode: false); } else if (IsCommentStart()) { AcceptComment(); } else if (CurrentCharacter != '}') { // Nothing interesting, so just read to the ';' AcceptStatementToSemicolon(); } }
protected internal virtual bool ParseInheritsStatement(CodeBlockInfo block) { SourceLocation endInheritsLocation = Context.CurrentLocation; bool readWhitespace = RequireSingleWhiteSpace(); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: readWhitespace ? AcceptedCharacters.None : AcceptedCharacters.Any)); // Accept Whitespace up to the new line or non-whitespace character Context.AcceptWhiteSpace(includeNewLines: false); string typeName = null; if (ParserHelpers.IsIdentifierStart(CurrentCharacter)) { using (Context.StartTemporaryBuffer()) { // Accept a dotted-identifier, but allow <> Context.AcceptLine(includeNewLineSequence: false); typeName = Context.ContentBuffer.ToString(); Context.AcceptTemporaryBuffer(); } Context.AcceptNewLine(); } else { OnError(endInheritsLocation, RazorResources.ParseError_InheritsKeyword_Must_Be_Followed_By_TypeName); } if (HaveContent || readWhitespace) { End(InheritsSpan.Create(Context, typeName)); } return false; }
private bool ParseCodeBlock(CodeBlockInfo block, bool bracesAreMetacode, bool acceptBraces = true) { bool success = false; if (acceptBraces) { Context.AcceptCurrent(); // "{" } Span openBraceSpan = null; if (bracesAreMetacode) { openBraceSpan = MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None); End(openBraceSpan); } while (!EndOfFile && CurrentCharacter != '}') { ParseStatement(block); } if (bracesAreMetacode) { if (!Context.PreviousSpanCanGrow || HaveContent) { End(CodeSpan.Create(Context)); } } Context.FlushNextOutputSpan(); if (CurrentCharacter == '}') { success = true; if (acceptBraces) { Context.AcceptCurrent(); if (bracesAreMetacode) { End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None)); } } } else { if (openBraceSpan != null && openBraceSpan.Next != null && openBraceSpan.Next is CodeSpan) { openBraceSpan.Next.AutoCompleteString = "}"; } OnError(block.Start, RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, block.Name, '}', '{'); } return success; }
protected bool HandleReservedWord(CodeBlockInfo block) { StartBlock(BlockType.Directive); block.ResumeSpans(Context); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None)); OnError(block.Start, String.Format(CultureInfo.CurrentCulture, RazorResources.ParseError_ReservedWord, block.Name)); return true; }
private BlockParser GetBlockParser(CodeBlockInfo block, BlockParser fallbackParser, out bool isStatementBlock) { BlockParser parser = null; isStatementBlock = true; if (block.Name == null || !_identifierHandlers.TryGetValue(block.Name, out parser)) { isStatementBlock = false; if (block.Name == null || !block.IsTopLevel || !RazorKeywords.TryGetValue(block.Name, out parser)) { parser = fallbackParser; } } return parser; }
private BlockParser GetBlockParser(CodeBlockInfo block, BlockParser fallbackParser) { bool _ = false; // Don't care in this case return GetBlockParser(block, fallbackParser, out _); }
private bool ParseHelperBlock(CodeBlockInfo block) { SourceLocation errorLocation = CurrentLocation; bool readWhitespace = RequireSingleWhiteSpace(); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: readWhitespace ? AcceptedCharacters.None : AcceptedCharacters.Any)); // Accept whitespace Context.AcceptWhiteSpace(includeNewLines: false); // Check for an identifier bool seenError = String.IsNullOrEmpty( Context.ExpectIdentifier(RazorResources.ParseError_Unexpected_Character_At_Helper_Name_Start, allowPrecedingWhiteSpace: true, errorLocation: errorLocation)); // Check for parameter list errorLocation = CurrentLocation; Context.AcceptWhiteSpace(includeNewLines: false); bool seenOpenBracket = Context.Expect('(', outputError: !seenError, errorMessage: RazorResources.ParseError_MissingCharAfterHelperName, caseSensitive: true, errorLocation: errorLocation); seenError |= !seenOpenBracket; errorLocation = CurrentLocation; if (seenOpenBracket) { if (BalanceBrackets(allowTransition: false, spanFactory: null, appendOuter: true, bracket: '(', useTemporaryBuffer: false)) { Context.Expect(')', outputError: !seenError); } else if (!seenError) { seenError = true; OnError(errorLocation, RazorResources.ParseError_UnterminatedHelperParameterList); } } bool outputtedHeader = false; Span headerSpan = null; using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); errorLocation = CurrentLocation; if (Context.Expect('{', outputError: !seenError, errorMessage: RazorResources.ParseError_MissingCharAfterHelperParameters)) { Context.AcceptTemporaryBuffer(); if (HaveContent) { outputtedHeader = true; // Can't grow at the end since we saw "{" headerSpan = HelperHeaderSpan.Create(Context, !seenError, AcceptedCharacters.Any); End(headerSpan); Context.FlushNextOutputSpan(); } using (Context.StartBlock(BlockType.Statement, outputCurrentBufferAsTransition: false)) { ParseCodeBlock(block, bracesAreMetacode: false, acceptBraces: false); End(CodeSpan.Create); Context.FlushNextOutputSpan(); } if (CurrentCharacter != '}') { if (headerSpan != null) { headerSpan.AutoCompleteString = "}"; } } else { headerSpan.AcceptedCharacters = AcceptedCharacters.None; Context.AcceptCurrent(); End(HelperFooterSpan.Create); return true; // Helper block can't grow any more } } else { seenError = true; Context.RejectTemporaryBuffer(); Context.AcceptWhiteSpace(includeNewLines: false); } } if (!outputtedHeader && readWhitespace) { // In an error case, we need to classify whatever we did capture as HelperHeader End(HelperHeaderSpan.Create(Context, !seenError)); } return false; }
protected internal virtual bool ParseConditionalBlockStatement(CodeBlockInfo block) { Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter == '(') { SourceLocation errorLocation = CurrentLocation; // Balance parens if (!BalanceBrackets()) { Context.AcceptLine(includeNewLineSequence: false); OnError(errorLocation, RazorResources.ParseError_Expected_CloseBracket_Before_EOF, "(", ")"); return false; } } return ParseControlFlowBody(block); }
private bool ParseSectionBlock(CodeBlockInfo block) { RequireSingleWhiteSpace(); Context.AcceptWhiteSpace(includeNewLines: false); bool complete = false; string sectionName = Context.ExpectIdentifier(RazorResources.ParseError_Unexpected_Character_At_Section_Name_Start); if (sectionName == null) { End(SectionHeaderSpan.Create(Context, sectionName: String.Empty, acceptedCharacters: AcceptedCharacters.Any)); } else { Context.AcceptWhiteSpace(includeNewLines: false); using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter != '{') { Context.RejectTemporaryBuffer(); OnError(CurrentLocation, RazorResources.ParseError_MissingOpenBraceAfterSection); End(SectionHeaderSpan.Create(Context, sectionName, acceptedCharacters: AcceptedCharacters.Any)); return false; } else { Context.AcceptTemporaryBuffer(); } } Context.AcceptCurrent(); // { SectionHeaderSpan headerSpan = SectionHeaderSpan.Create(Context, sectionName, acceptedCharacters: AcceptedCharacters.Any); End(headerSpan); Context.SwitchActiveParser(); Context.MarkupParser.ParseSection(Tuple.Create("{", "}"), caseSensitive: true); Context.SwitchActiveParser(); if (Context.CurrentCharacter == '}') { complete = true; Context.AcceptCurrent(); // } End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None)); } else { headerSpan.AutoCompleteString = "}"; } } return complete; }
protected internal virtual bool ParseControlFlowBody(CodeBlockInfo block) { bool success = true; using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter != '{') { success = false; OnError(CurrentLocation, RazorResources.ParseError_SingleLine_ControlFlowStatements_Not_Allowed, "{", CurrentCharacter); } else { Context.AcceptTemporaryBuffer(); } } if (success) { // We know for sure it's a code block return ParseCodeBlock(block, bracesAreMetacode: false); } else { // Error recovery, let's just accept a statement ParseStatement(block); return false; // Not complete yet though } }
private bool ParseDelimitedBlock(CodeBlockInfo block, bool allowTransition = true, bool useErrorRecovery = true, string autoCompleteString = null) { Context.AcceptWhiteSpace(includeNewLines: true); // Append the open bracket as a metacode token char bracket = CurrentCharacter; if (!_bracketPairs.ContainsKey(bracket)) { throw new InvalidOperationException(RazorResources.ParseDelimitedBlock_Requires_Bracket); } char terminator = _bracketPairs[bracket]; Context.AcceptCurrent(); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None)); // Append the terminator as a metacode token bool complete = BalanceBrackets(allowTransition: allowTransition, spanFactory: null, appendOuter: false, bracket: bracket, useTemporaryBuffer: useErrorRecovery); if (!complete) { if (useErrorRecovery) { // Try to recover TryRecover(RecoveryModes.Markup | RecoveryModes.Transition); } End(CodeSpan.Create(Context, autoCompleteString)); OnError(block.Start, RazorResources.ParseError_Expected_EndOfBlock_Before_EOF, block.Name, terminator, bracket); } else { End(CodeSpan.Create); Context.AcceptCurrent(); End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None)); } return complete; }
private bool ParseImplicitExpression(CodeBlockInfo block, bool acceptTrailingDot) { bool expectIdentifierFirst = block.Name == null; block.Name = RazorResources.BlockName_ImplicitExpression; using (StartBlock(BlockType.Expression)) { block.ResumeSpans(Context); AcceptedCharacters accepted = AcceptDottedExpression(acceptTrailingDot, expectIdentifierFirst, '('); End(ImplicitExpressionSpan.Create(Context, TopLevelKeywords, acceptTrailingDot, accepted)); return true; } }
// @[not a block statement keyword] protected internal virtual bool ParseImplicitExpression(CodeBlockInfo block) { return ParseImplicitExpression(block, isWithinCode: false, expectIdentifierFirst: false); }
protected internal virtual bool ParseImplicitExpression(CodeBlockInfo block, bool isWithinCode, bool expectIdentifierFirst) { // TODO: Refactor this into better block creation logic block.Name = RazorResources.BlockName_ImplicitExpression; AcceptedCharacters accepted = AcceptDottedExpression(isWithinCode, expectIdentifierFirst, '(', '['); End(ImplicitExpressionSpan.Create(Context, TopLevelKeywords, isWithinCode, accepted)); return true; // Return value doesn't matter since we're creating the span here. }