Exemplo n.º 1
0
        private bool ParseSingleLineBlock()
        {
            Context.UpdateSeenValidEmailPrefix();

            // Output the ":" as a transition token
            Context.AcceptCurrent();
            End(MetaCodeSpan.Create);

            while (!EndOfFile)
            {
                if (!TryStartCodeParser(isSingleLineMarkup: true))
                {
                    if (ParserHelpers.IsNewLine(CurrentCharacter))
                    {
                        Context.AcceptNewLine();
                        return(false);
                    }
                    else
                    {
                        Context.UpdateSeenValidEmailPrefix();
                        Context.AcceptCurrent();
                    }
                }
            }
            return(true);
        }
Exemplo n.º 2
0
        private bool ParseEndTag(Stack <TagInfo> tags, TagInfo tag, bool acceptUnmatchedEndTag)
        {
            Debug.Assert(tag.IsEndTag, "ParseEndTag requires an end tag");

            // Read the tag (no attributes allowed in an end tag)
            AppendUntilAndParseCode(c => c == '>' || c == '<');

            // Make sure we're actually in a valid tag
            if (CurrentCharacter == '>')
            {
                //OnTagFinished(new TagFinishedEventArgs(context, tagName, true, false, tagStartLocation));
                Context.AcceptCurrent(); // '>'

                // Verify the tag
                if (tags.Count == 0 && !acceptUnmatchedEndTag)
                {
                    // Started with an end tag
                    OnError(tag.Start, RazorResources.ParseError_UnexpectedEndTag, tag.Name);
                }
                else
                {
                    UpdateTagStack(tags, tag, !acceptUnmatchedEndTag);
                }

                // Successfully terminated
                return(false);
            }

            // Not terminated, return true to indicate unterminated
            return(true);
        }
Exemplo n.º 3
0
        protected void ParseBlockWithOtherParser(SpanFactory previousSpanFactory, bool collectTransitionToken)
        {
            // Capture the current span if we have one
            if (TryParseComment(previousSpanFactory))
            {
                return;
            }

            Span prev = null;

            if (HaveContent)
            {
                prev = previousSpanFactory(Context);
                Context.ResetBuffers();
            }

            // Skip over the switch token if requested
            if (collectTransitionToken)
            {
                Context.AcceptCurrent();
            }

            if (collectTransitionToken && CurrentCharacter == RazorParser.TransitionCharacter)
            {
                // We were told to handle the transition token and found another transition character ==> Escape sequence

                // Output the previous content and a hidden token so that the first at of the escape sequence doesn't get rendered
                if (prev != null)
                {
                    Output(prev);
                }
                Span span = previousSpanFactory(Context);
                Context.ResetBuffers();
                span.Hidden = true;
                Output(span);

                // Now accept the current transition token so it doesn't get treated as a transition and return to the current context
                Context.AcceptCurrent();
            }
            else
            {
                if (prev != null)
                {
                    Output(prev);
                }

                // Switch to the other parser
                Context.SwitchActiveParser();

                // Have the other parser parse a block starting with the character after the '@'
                Context.ActiveParser.ParseBlock();

                // Switch back
                Context.SwitchActiveParser();

                // Once we're done, start a new span
                Context.ResetBuffers();
            }
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
 public virtual bool NextIsTransition(bool allowImplicit, bool allowExplicit)
 {
     using (Context.StartTemporaryBuffer()) {
         Context.AcceptCurrent();
         return((allowExplicit && IsAtExplicitTransition()) ||
                (allowImplicit && IsAtImplicitTransition()));
     }
 }
Exemplo n.º 6
0
 private void AcceptOrSkipCurrent(bool appendOuter, int nesting)
 {
     if (nesting > 0 || appendOuter)
     {
         Context.AcceptCurrent();
     }
     else
     {
         Context.SkipCurrent();
     }
 }
Exemplo n.º 7
0
        protected bool TryRecover(RecoveryModes mode,
                                  Predicate <char> condition,
                                  bool allowTransition,
                                  SpanFactory previousSpanFactory)
        {
            bool anyNewLines = false;

            while (!EndOfFile && !condition(CurrentCharacter))
            {
                // Eat whitespace
                Context.AcceptWhiteSpace(false);

                if (mode.HasFlag(RecoveryModes.Markup))
                {
                    // If we see new lines before a '<' then assume it's markup.
                    // This isn't 100% correct but it is the 80/90% case when typing razor code
                    if (anyNewLines && Context.MarkupParser.IsStartTag())
                    {
                        return(true);
                    }

                    // End tags are mostly unambiguous
                    // REVIEW: Does this make sense?
                    if (Context.MarkupParser.IsEndTag())
                    {
                        return(true);
                    }
                }

                if (mode.HasFlag(RecoveryModes.Code))
                {
                    if (TryRecover(allowTransition, previousSpanFactory))
                    {
                        return(true);
                    }
                }

                if (mode.HasFlag(RecoveryModes.Transition))
                {
                    if (CurrentCharacter == RazorParser.TransitionCharacter)
                    {
                        return(true);
                    }
                }

                anyNewLines = ParserHelpers.IsNewLine(CurrentCharacter);

                Context.AcceptCurrent();
            }
            return(false);
        }
Exemplo n.º 8
0
 protected virtual void AcceptUntilUnquoted(Predicate <char> condition)
 {
     while (!EndOfFile)
     {
         if (!TryAcceptStringOrComment())
         {
             if (condition(CurrentCharacter))
             {
                 return;
             }
             Context.AcceptCurrent();
         }
     }
 }
Exemplo n.º 9
0
 protected void AcceptTypeName(bool allowGenerics)
 {
     do
     {
         if (CurrentCharacter == '.')
         {
             Context.AcceptCurrent();
         }
         Context.AcceptIdentifier();
         if (allowGenerics)
         {
             AcceptGenericArgument();
         }
     } while (CurrentCharacter == '.');
 }
Exemplo n.º 10
0
        private void AppendUntilAndParseCode(Func <char, bool> terminator)
        {
            while (!EndOfFile && !terminator(CurrentCharacter))
            {
                if (!TryStartCodeParser())
                {
                    Context.UpdateSeenValidEmailPrefix();
                    Context.AcceptCurrent();
                }
            }

            // The terminator may or may not be a valid prefix/suffix character, and since the else block above was skipped if we reached the terminator
            // we should check it
            Context.UpdateSeenValidEmailPrefix();
        }
Exemplo n.º 11
0
 protected bool RequireSingleWhiteSpace()
 {
     if (Char.IsWhiteSpace(CurrentCharacter))
     {
         if (ParserHelpers.IsNewLine(CurrentCharacter))
         {
             Context.AcceptNewLine();
         }
         else
         {
             Context.AcceptCurrent();
         }
         return(true);
     }
     return(false);
 }
Exemplo n.º 12
0
        private void ParseEndPsuedoTag(Stack <TagInfo> tags, TagInfo tag, bool inDocument)
        {
            Debug.Assert(tag.IsEndTag, "ParseEndPsuedoTag requires an end tag");

            // Collect what we've seen so far, since the "</text>" is not a markup span, it's a transition span
            Span prev = null;

            if (HaveContent)
            {
                prev = MarkupSpan.Create(Context);
                Context.ResetBuffers();
            }

            // Accept the "</text>"
            Context.Expect("<");
            Context.AcceptWhiteSpace(includeNewLines: true);
            Context.Expect("/text");

            bool complete = CurrentCharacter == '>';

            if (!complete)
            {
                OnError(tag.Start, RazorResources.ParseError_TextTagCannotContainAttributes);
            }
            else
            {
                Context.AcceptCurrent();
            }

            // Remove the tag
            UpdateTagStack(tags, tag, !inDocument);

            if (tags.Count == 0)
            {
                // That was the top-level tag, output the markup then a transition span for the </text>
                if (prev != null)
                {
                    Output(prev);
                }
                End(TransitionSpan.Create(Context, hidden: false, acceptedCharacters: complete ? AcceptedCharacters.None : AcceptedCharacters.Any));
            }
            else
            {
                // Wasn't top-level, so resume the original span
                Context.ResumeSpan(prev);
            }
        }
Exemplo n.º 13
0
        private bool ParseSgmlDeclaration()
        {
            // Just parse until the '>'
            AppendUntilAndParseCode(c => c == '>' || c == '<');

            // Make sure we're actually in a valid tag
            if (EndOfFile)
            {
                return(true);
            }

            if (CurrentCharacter == '>')
            {
                Context.AcceptCurrent();
            }
            return(false);
        }
Exemplo n.º 14
0
        private TagInfo ParseStartOfTag()
        {
            bool           isEndTag = false;
            SourceLocation tagStart = CurrentLocation;

            using (Context.StartTemporaryBuffer()) {
                Context.AcceptCurrent(); // Accept the "<"

                // Is this an end tag?
                if (CurrentCharacter == '/')
                {
                    Context.AcceptCurrent(); // Skip the "/"
                    isEndTag = true;
                }

                // Parse the tag name
                return(new TagInfo(AcceptTagName(), tagStart, isEndTag));
            }
        }
Exemplo n.º 15
0
        private bool ParseHtmlComment()
        {
            // Parse until the '-->'
            while (!EndOfFile)
            {
                AppendUntilAndParseCode(c => c == '-');
                if (CurrentCharacter == '-')
                {
                    Context.AcceptCurrent();

                    // Peek only needs to check for "->" because we've already seen the first '-'
                    if (Context.Peek("->", caseSensitive: true))
                    {
                        // End of the Comment
                        Context.AcceptUntilInclusive('>');
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemplo n.º 16
0
        private bool ParseCData()
        {
            // Parse until the ']]>'
            while (!EndOfFile)
            {
                AppendUntilAndParseCode(c => c == ']');
                if (CurrentCharacter == ']')
                {
                    Context.AcceptCurrent();
                    if (Context.Peek("]>", caseSensitive: true))
                    {
                        // End of the CData section
                        Context.AcceptUntilInclusive('>');

                        // Done parsing the CData
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemplo n.º 17
0
        private bool ParseProcessingInstruction()
        {
            // Parse until '?>'
            while (!EndOfFile)
            {
                AppendUntilAndParseCode(c => c == '?');
                if (CurrentCharacter == '?')
                {
                    Context.AcceptCurrent();
                    if (CurrentCharacter == '>')
                    {
                        // End of the PI
                        Context.AcceptCurrent();

                        // Done parsing the PI
                        return(false);
                    }
                }
            }
            return(true);
        }
Exemplo n.º 18
0
        private void AppendToEndOfTag(TagInfo tag)
        {
            char?balancingQuote = null;

            do
            {
                // Read until a quoted literal or the end of the tag (and handle code we find in between)
                AppendUntilAndParseCode(c => c == '\"' || c == '\'' || c == '/' || c == '>' || c == '<');

                if (balancingQuote != null)
                {
                    if (balancingQuote.Value == CurrentCharacter)
                    {
                        balancingQuote = null;
                    }
                    Context.AcceptCurrent();
                }
                else if (CurrentCharacter == '\"' || CurrentCharacter == '\'')
                {
                    balancingQuote = CurrentCharacter;
                    Context.AcceptCurrent();
                }
                else if (CurrentCharacter == '/')
                {
                    using (Context.Source.BeginLookahead()) {
                        Context.SkipCurrent();
                        if (CurrentCharacter == '>')
                        {
                            return;
                        }
                    }
                    Context.AcceptCurrent(); // "/"
                }
            } while (!EndOfFile && (balancingQuote != null || (CurrentCharacter != '>' && CurrentCharacter != '<')));

            if (CurrentCharacter != '>' && CurrentCharacter != '<')
            {
                OnError(tag.Start, RazorResources.ParseError_UnfinishedTag, tag.Name);
            }
        }
Exemplo n.º 19
0
        private void ParseRootBlock(Tuple <string, string> nestingSequences, bool caseSensitive = true)
        {
            // We're only document level there are no nesting sequences
            bool documentLevel = nestingSequences == null;

            // Start a markup block
            using (StartBlock(BlockType.Markup)) {
                int nesting = 1;
                do
                {
                    if (nestingSequences != null && nestingSequences.Item1 != null && Context.Peek(nestingSequences.Item1, caseSensitive: caseSensitive))
                    {
                        nesting++;
                        Context.Expect(nestingSequences.Item1, outputError: true, errorMessage: null, caseSensitive: caseSensitive);
                    }
                    else if (nestingSequences != null && Context.Peek(nestingSequences.Item2, caseSensitive: caseSensitive))
                    {
                        nesting--;
                        if (nesting > 0)
                        {
                            Context.Expect(nestingSequences.Item2, outputError: true, errorMessage: null, caseSensitive: caseSensitive);
                        }
                    }
                    else if (!TryStartCodeParser(documentLevel: documentLevel))
                    {
                        Context.UpdateSeenValidEmailPrefix();
                        Context.AcceptCurrent();
                    }
                } while (!EndOfFile && (nestingSequences == null || nesting > 0));

                if (!Context.PreviousSpanCanGrow || HaveContent)
                {
                    var span = MarkupSpan.Create(Context);
                    span.DocumentLevel = documentLevel;
                    End(span);
                }
            }
        }
Exemplo n.º 20
0
        protected void ParseComment()
        {
            using (StartBlock(BlockType.Comment)) {
                SourceLocation startLocation = CurrentLocation;
                Context.Expect(RazorParser.StartCommentSequence[0]);
                End(TransitionSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None));

                Context.Expect(RazorParser.StartCommentSequence[1]);
                End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None));

                bool inComment = true;
                while (inComment && !EndOfFile)
                {
                    Context.AcceptUntil(RazorParser.EndCommentSequence[0]);
                    if (Context.Peek(RazorParser.EndCommentSequence, caseSensitive: true))
                    {
                        inComment = false;
                    }
                    else
                    {
                        Context.AcceptCurrent();
                    }
                }
                End(CommentSpan.Create);
                if (EndOfFile)
                {
                    OnError(startLocation, RazorResources.ParseError_RazorComment_Not_Terminated);
                }
                else
                {
                    Context.Expect(RazorParser.EndCommentSequence[0]);
                    End(MetaCodeSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None));
                    Context.Expect(RazorParser.EndCommentSequence[1]);
                    End(TransitionSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None));
                }
            }
        }
Exemplo n.º 21
0
        private bool ParseStartTag(Stack <TagInfo> tags, TagInfo tag)
        {
            Debug.Assert(!tag.IsEndTag, "ParseStartTag requires a start tag");

            // Append Until the end of the tag
            AppendToEndOfTag(tag);

            // Make sure we're actually in a valid tag
            bool unterminated = false;

            switch (CurrentCharacter)
            {
            case '>':
                //OnTagFinished(new TagFinishedEventArgs(context, tagName, false, false, tagStartLocation));
                Context.AcceptCurrent();

                // Start tag, push it on the stack
                tags.Push(tag);
                break;

            case '/':
                Context.AcceptCurrent();     // Accept the "/"

                //OnTagFinished(new TagFinishedEventArgs(context, tagName, false, true, tagStartLocation));

                // We know that it's followed immediately by '>' because that's what AppendToEndOfTag expects, so accept that
                Context.AcceptCurrent();

                // An empty tag has no content, so don't push anything onto the stack (no need to set the "End" property on the tag either, since it's going away)
                break;

            default:
                unterminated = true;
                break;
            }
            return(unterminated);
        }
Exemplo n.º 22
0
        public override void ParseBlock()
        {
            if (Context == null)
            {
                throw new InvalidOperationException(RazorResources.Parser_Context_Not_Set);
            }

            using (StartBlock(BlockType.Markup)) {
                // An HTML block starts with a start tag and ends with the matching end tag. For example, each of the following lines are HTML blocks:
                //  <li>foo</li>
                //  <li>foo<b>bar</b></li>
                //  <text>This block uses the <pre>&lt;text&gt;</pre> pseudo-tag which is not emitted, but is used for balancing tags</text>
                // Or, if it starts with a ":", then it is part of the "@:" single-line markup construct.  The ":" is discarded and the rest of the line is markup
                // For example, each of the following lines are HTML blocks:
                //  :this is all markup, except for the initial ':'
                //  :you <b>can</b> put tags in here <em>and</em> they don't have to be <img src="foo.jpg"> balanced!

                SpanFactory spanFactory = MarkupSpan.Create;

                Context.AcceptWhiteSpace(includeNewLines: true);
                if (CurrentCharacter == RazorParser.TransitionCharacter)
                {
                    if (HaveContent)
                    {
                        End(MarkupSpan.Create);
                    }
                    Context.AcceptCurrent();
                    Debug.Assert(HaveContent);
                    End(TransitionSpan.Create(Context, hidden: false, acceptedCharacters: AcceptedCharacters.None));
                    if (CurrentCharacter == RazorParser.TransitionCharacter)
                    {
                        // Second "@" is for VB
                        // TODO: Refactor!!!
                        Context.AcceptCurrent();
                        End(MetaCodeSpan.Create);
                    }
                }

                bool complete = false;
                if (CurrentCharacter == ':')
                {
                    // Parse a single line of markup
                    spanFactory = SingleLineMarkupSpan.Create;
                    Context.WhiteSpaceIsImportantToAncestorBlock = true;
                    complete = !ParseSingleLineBlock();
                    Context.WhiteSpaceIsImportantToAncestorBlock = false;
                }
                else if (CurrentCharacter == '<')
                {
                    complete = !ParseTagBlock(false);
                }
                else
                {
                    // First non-whitespace character in a block must be a start tag or ':'
                    OnError(CurrentLocation, RazorResources.ParseError_MarkupBlock_Must_Start_With_Tag);
                    return;
                }

                // Output anything that's left over
                // If we have content ==> Output
                // If the previous span can't grow ==> Output UNLESS we're "complete"
                if ((!complete && !Context.PreviousSpanCanGrow) || HaveContent)
                {
                    Span span = spanFactory(Context);
                    span.AcceptedCharacters = complete ? AcceptedCharacters.None : AcceptedCharacters.Any;
                    End(span);
                }
            }
        }
Exemplo n.º 23
0
        private bool ParseTagBlock(bool inDocument)
        {
            // For tracking end tags
            Stack <TagInfo> tags = new Stack <TagInfo>();
            bool            startedByPseudoTag = false;

            bool?canGrow = null;

            do
            {
                // Append until the next tag, processing code as we find it
                AppendUntilAndParseCode(c => c == '<');

                // Read the tag name in lookahead since we might not actually want to accept it
                TagInfo tag = ParseStartOfTag();

                // Special case for "<text>" tag as the first tag we've seen
                if (IsPsuedoTagValidHere(inDocument, tags, startedByPseudoTag, tag))
                {
                    if (!tag.IsEndTag)
                    {
                        startedByPseudoTag = true; // Set a flag to indicate that a </text> is a valid end tag
                        if (ParseStartPsuedoTag(tags, tag))
                        {
                            // Can't just do "canGrow = !ParseStartPsuedoTag(...)" because we can't canGrow to
                            // stay null if we get false from ParseStartPsuedoTag
                            canGrow = false;
                        }
                    }
                    else
                    {
                        ParseEndPsuedoTag(tags, tag, inDocument);
                        canGrow = false;
                    }
                }
                // It wasn't a "<text>" OR it was but it was within a block, so we don't do anything special
                else
                {
                    // We're at the '<'
                    Context.AcceptCurrent(); // "<"

                    if (tag.IsEndTag)
                    {
                        Context.AcceptCurrent();               // "/"
                    }
                    Context.AcceptCharacters(tag.Name.Length); // tag name

                    // Invalid tag name? Not a real tag
                    if (!String.IsNullOrEmpty(tag.Name))
                    {
                        // What kind of tag is it
                        bool?unterminated = null;
                        switch (tag.Name[0])
                        {
                        case '!':
                            unterminated = ParseBangTag(tag.Name);
                            break;

                        case '?':
                            unterminated = ParseProcessingInstruction();
                            break;

                        default:
                            if (tag.IsEndTag)
                            {
                                unterminated = ParseEndTag(tags, tag, inDocument);
                            }
                            else
                            {
                                unterminated = ParseStartTag(tags, tag);
                            }
                            break;
                        }
                        if (tags.Count == 0 && unterminated != null)
                        {
                            canGrow = unterminated.Value;
                        }
                    }
                    else
                    {
                        canGrow = true;
                        if (tags.Count == 0)
                        {
                            OnError(CurrentLocation, RazorResources.ParseError_OuterTagMissingName);
                        }
                    }
                }
            } while (!EndOfFile && tags.Count > 0);

            if (canGrow == null)
            {
                canGrow = tags.Count > 0;
            }

            if (tags.Count > 0)
            {
                // Ended because of EOF, not matching close tag.  Throw error for last tag
                while (tags.Count > 1)
                {
                    tags.Pop();
                }
                TagInfo tag = tags.Pop();
                OnError(tag.Start, RazorResources.ParseError_MissingEndTag, tag.Name);
            }

            // Add the remaining whitespace (up to and including the next newline) to the token if run-time mode
            if (!DesignTimeMode)
            {
                // Dev10 Bug 884969 - Emit space between markup and code
                Context.AcceptWhiteSpace(includeNewLines: false);
                if (Char.IsWhiteSpace(CurrentCharacter))
                {
                    Context.AcceptLine(includeNewLineSequence: true);
                }
            }
            else if (canGrow.Value)
            {
                Context.AcceptWhiteSpace(includeNewLines: false);
                if (ParserHelpers.IsNewLine(CurrentCharacter))
                {
                    Context.AcceptNewLine();
                }
            }

            return(canGrow.Value);
        }
Exemplo n.º 24
0
        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);
        }
Exemplo n.º 25
0
        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
        }