Example #1
0
        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);
        }
Example #2
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);
            }
        }
Example #3
0
        /// <summary>
        /// Starts a block of the specified type
        /// </summary>
        /// <remarks>
        /// The current contents of the buffer will be outputted as a transition token AFTER starting the block if outputCurrentBufferAsTransition is true
        /// </remarks>
        /// <param name="blockType">The type of the block to start</param>
        public IDisposable StartBlock(BlockType blockType, bool outputCurrentBufferAsTransition)
        {
            AssertOnOwnerTask();
            if (blockType == BlockType.Template)
            {
                HandleNestingCheck(RazorResources.ParseError_InlineMarkup_Blocks_Cannot_Be_Nested,
                                   ref _nestedAnonymousSections);
            }
            else if (blockType == BlockType.Section)
            {
                HandleNestingCheck(FormatForLanguage(RazorResources.ParseError_Sections_Cannot_Be_Nested,
                                                     RazorResources.SectionExample_VB,
                                                     RazorResources.SectionExample_CS),
                                   ref _nestedNamedSections);
                if (_nestedHelpers > 0)
                {
                    OnError(CurrentLocation, RazorResources.ParseError_Helpers_Cannot_Contain_Sections);
                }
            }
            else if (blockType == BlockType.Helper)
            {
                HandleNestingCheck(RazorResources.ParseError_Helpers_Cannot_Be_Nested, ref _nestedHelpers);
            }

            // TODO: Remove this super-hacky whitespace rewriting
            if (!DesignTimeMode &&
                !WhiteSpaceIsImportantToAncestorBlock &&
                blockType == BlockType.Statement &&
                (_blockStack.Count == 0 || _blockStack.Peek() != BlockType.Statement) &&
                _nextSpanToOutput != null)
            {
                HandleWhitespaceRewriting();
            }
            else
            {
                FlushNextOutputSpan();
            }

            _blockStack.Push(blockType);
            Visitor.VisitStartBlock(blockType);
            if (outputCurrentBufferAsTransition && HaveContent)
            {
                OutputSpan(TransitionSpan.Create(this, hidden: false, acceptedCharacters: AcceptedCharacters.None));
                ResetBuffers();
            }
            return(new DisposableAction(EndBlock));
        }
Example #4
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));
                }
            }
        }
Example #5
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);
        }
Example #6
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);
                }
            }
        }