protected AcceptedCharacters AcceptDottedExpression(bool isWithinCode, bool expectIdentifierFirst, params char[] allowedBrackets) { if (!expectIdentifierFirst || ParserHelpers.IsIdentifierStart(CurrentCharacter)) { do { // Parse Parentheses or Brackets if we see them do { if (!allowedBrackets.Any(c => CurrentCharacter == c)) { break; } // Dev10 884975 - Incorrect Error Messaging SourceLocation bracketStart = CurrentLocation; char bracket = CurrentCharacter; if (!BalanceBrackets(allowTransition: true, spanFactory: CreateImplicitExpressionSpanFactory(isWithinCode))) { // Balancing terminated because of EOF char terminator = _bracketPairs[bracket]; Context.AcceptCurrent(); TryRecover(RecoveryModes.Any); OnError(bracketStart, RazorResources.ParseError_Expected_CloseBracket_Before_EOF, bracket, terminator); return(AcceptedCharacters.Any); } } while (!EndOfFile); // If the next character is a dot, followed by an identifier start, keep on parsing using (Context.StartTemporaryBuffer()) { if (CurrentCharacter != '.') { break; } Context.AcceptCurrent(); if (!ParserHelpers.IsIdentifierStart(CurrentCharacter)) { if (isWithinCode) { Context.AcceptTemporaryBuffer(); } break; } Context.AcceptTemporaryBuffer(); // Put the dot in the primary buffer } // Parse an identifier Context.AcceptIdentifier(); } while (!EndOfFile); } return(AcceptedCharacters.NonWhiteSpace); }
protected virtual void AcceptWhiteSpaceByLines() { Debug.Assert(InTemporaryBuffer); // Eat whitespace until a non-whitespace character, while (Char.IsWhiteSpace(CurrentCharacter)) { Context.AcceptWhiteSpace(includeNewLines: false); // Stopped because of a newline, so accept the newline, then accept the temporary buffer and start it again if (Char.IsWhiteSpace(CurrentCharacter)) { Context.AcceptLine(includeNewLineSequence: true); Context.AcceptTemporaryBuffer(); Context.StartTemporaryBuffer(); } } }
protected bool TryParseComment(SpanFactory previousSpanFactory) { // Check for comment using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); if (Context.Peek(RazorParser.StartCommentSequence, caseSensitive: true)) { Context.AcceptTemporaryBuffer(); End(previousSpanFactory); } else { return(false); } } ParseComment(); return(true); }
/// <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 ParseModelStatement(CodeBlockInfo block) { using (StartBlock(BlockType.Directive)) { block.ResumeSpans(Context); 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, ModelTypeKeyword)); } _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, ModelTypeKeyword)); } CheckForInheritsAndModelStatements(); End(new ModelSpan(Context, typeName)); } return(false); }
/// <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 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); }
private bool ParseStartPsuedoTag(Stack <TagInfo> tags, TagInfo tag) { Debug.Assert(!tag.IsEndTag, "ParseStartPsuedoTag requires a start tag"); // Output what we've seen so far, since the "<text>" is not a markup token, it's a transition token if (HaveContent) { End(MarkupSpan.Create); } // Accept the "<text>" Context.Expect("<"); Context.AcceptWhiteSpace(includeNewLines: true); Context.Expect("text"); bool isValid = false; using (Context.StartTemporaryBuffer()) { Context.AcceptWhiteSpace(includeNewLines: true); if (CurrentCharacter == '/' || CurrentCharacter == '>') { isValid = true; Context.AcceptTemporaryBuffer(); } } bool transitionComplete = false; bool isEmpty = false; if (!isValid) { OnError(tag.Start, RazorResources.ParseError_TextTagCannotContainAttributes); } else { isEmpty = CurrentCharacter == '/'; Context.AcceptCurrent(); if (isEmpty) { if (CurrentCharacter != '>') { OnError(CurrentLocation, RazorResources.ParseError_SlashInEmptyTagMustBeFollowedByCloseAngle); } else { transitionComplete = true; Context.AcceptCurrent(); } } else { transitionComplete = true; } } // Output the transition End(TransitionSpan.Create(Context, hidden: false, acceptedCharacters: transitionComplete ? AcceptedCharacters.None : AcceptedCharacters.Any)); // Push it on to the stack and continue if (!isEmpty) { tags.Push(tag); } return(isEmpty); }
protected virtual bool BalanceBrackets(bool allowTransition, SpanFactory spanFactory, bool appendOuter, char?bracket, bool useTemporaryBuffer) { spanFactory = spanFactory ?? CodeSpan.Create; if (useTemporaryBuffer) { Context.StartTemporaryBuffer(); } int nesting = 0; // Nesting level bool callerReadBracket = true; if (bracket == null) { callerReadBracket = false; bracket = CurrentCharacter; } else { // The caller already read the bracket, so start at nesting level 1, and also, don't append the outer bracket nesting = 1; } char terminator = _bracketPairs[bracket.Value]; do { // Gather whitespace Context.StartTemporaryBuffer(); AcceptWhiteSpaceByLines(); if (CurrentCharacter == RazorParser.TransitionCharacter) { if (Context.Peek(RazorParser.StartCommentSequence, caseSensitive: true)) { Context.AcceptTemporaryBuffer(); if (useTemporaryBuffer) { Context.AcceptTemporaryBuffer(); } End(spanFactory); ParseComment(); if (useTemporaryBuffer) { Context.StartTemporaryBuffer(); } } else if (allowTransition) { Context.RejectTemporaryBuffer(); if (!HandleTransition(spanFactory)) { Context.AcceptWhiteSpace(includeNewLines: true); if (!TryAcceptStringOrComment()) { Context.AssertCurrent(RazorParser.TransitionCharacter); Context.AcceptCurrent(); } } else if (useTemporaryBuffer) { // Start a new outer temporary buffer Context.StartTemporaryBuffer(); } } else { Context.AcceptTemporaryBuffer(); if (!TryAcceptStringOrComment()) { Context.AcceptCurrent(); } } } else { Context.AcceptTemporaryBuffer(); } AcceptUntilUnquoted(c => Char.IsWhiteSpace(c) || c == bracket || c == terminator || c == RazorParser.TransitionCharacter); if (CurrentCharacter == terminator) { // If the nesting level is 1 and no bracket was specified, don't read the terminator, but we are done if (nesting == 1 && callerReadBracket) { nesting--; } else { AcceptOrSkipCurrent(appendOuter, --nesting); } } else if (CurrentCharacter == bracket) { AcceptOrSkipCurrent(appendOuter, nesting++); } } while (!EndOfFile && nesting > 0); if (useTemporaryBuffer) { if (nesting > 0) { Context.RejectTemporaryBuffer(); } else { Context.AcceptTemporaryBuffer(); } } Debug.Assert(!InTemporaryBuffer); return(nesting == 0); // Return a boolean indicating if we exited because of EOF or because of the end bracket }