public void UpdateLocationAdvancesAbsoluteIndexOnSlashRFollowedByNonNewlineCharacter()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\r', 'o');

            // Assert
            Assert.Equal(11, tracker.CurrentLocation.AbsoluteIndex);
        }
        public void UpdateLocationAdvancesCharacterIndexOnSlashRFollowedBySlashN()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\r', '\n');

            // Assert
            Assert.Equal(46, tracker.CurrentLocation.CharacterIndex);
        }
        public void UpdateLocationAdvancesAbsoluteIndexOnSlashN()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\n', 'o');

            // Assert
            Assert.Equal(11, tracker.CurrentLocation.AbsoluteIndex);
        }
Exemplo n.º 4
0
        public void UpdateLocationResetsCharacterIndexOnSlashRFollowedByNonNewlineCharacter()
        {
            // Arrange
            var tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\r', 'o');

            // Assert
            Assert.Equal(0, tracker.CurrentLocation.CharacterIndex);
        }
Exemplo n.º 5
0
        public void UpdateLocationDoesNotAdvanceLineIndexOnSlashRFollowedBySlashN()
        {
            // Arrange
            var tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\r', '\n');

            // Assert
            Assert.Equal(42, tracker.CurrentLocation.LineIndex);
        }
Exemplo n.º 6
0
        public void UpdateLocationAdvancesCharacterIndexOnNonNewlineCharacter()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('f', () => 'o');

            // Assert
            Assert.AreEqual(46, tracker.CurrentLocation.CharacterIndex);
        }
Exemplo n.º 7
0
        public void UpdateLocationAdvancesLineIndexOnSlashN()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\n', () => 'o');

            // Assert
            Assert.AreEqual(43, tracker.CurrentLocation.LineIndex);
        }
Exemplo n.º 8
0
 internal void CalculateStart(Span prev)
 {
     if (prev == null)
     {
         Start = SourceLocation.Zero;
     }
     else
     {
         Start = new SourceLocationTracker(prev.Start).UpdateLocation(prev.Content).CurrentLocation;
     }
 }
        public void UpdateLocationResetsCharacterIndexOnSlashN()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('\n', 'o');

            // Assert
            Assert.Equal(0, tracker.CurrentLocation.CharacterIndex);
        }
Exemplo n.º 10
0
 private static void EvaluateSpan(ErrorCollector collector, SourceLocationTracker tracker, Span actual, Span expected)
 {
     if (!actual.Equals(expected))
     {
         AddMismatchError(collector, tracker, actual, expected);
     }
     else
     {
         AddPassedMessage(collector, tracker, expected);
     }
 }
Exemplo n.º 11
0
        public virtual Tuple <TSymbol, TSymbol> SplitSymbol(TSymbol symbol, int splitAt, TSymbolType leftType)
        {
            TSymbol left  = CreateSymbol(symbol.Start, symbol.Content.Substring(0, splitAt), leftType, Enumerable.Empty <RazorError>());
            TSymbol right = null;

            if (splitAt < symbol.Content.Length)
            {
                right = CreateSymbol(SourceLocationTracker.CalculateNewLocation(symbol.Start, left.Content), symbol.Content.Substring(splitAt), symbol.Type, symbol.Errors);
            }
            return(Tuple.Create(left, right));
        }
Exemplo n.º 12
0
        public void UpdateLocationAdvancesCorrectlyForMultilineString()
        {
            var          tracker = new SourceLocationTracker(TestStartLocation);
            const string text    = "foo\nbar\rbaz\r\nbox";

            tracker.UpdateLocation(text);

            Assert.Equal(26, tracker.CurrentLocation.Absolute);
            Assert.Equal(45, tracker.CurrentLocation.Line);
            Assert.Equal(3, tracker.CurrentLocation.Character);
        }
        public void UpdateLocationDoesNotAdvanceLineIndexOnNonNewlineCharacter()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation('f', 'o');

            // Assert
            Assert.Equal(42, tracker.CurrentLocation.LineIndex);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Advances the <see cref="SourceLocation"/> by the length of the <paramref name="text" />.
        /// </summary>
        /// <param name="left">The <see cref="SourceLocation"/> to advance.</param>
        /// <param name="text">The <see cref="string"/> to advance <paramref name="left"/> by.</param>
        /// <returns>The advanced <see cref="SourceLocation"/>.</returns>
        public static SourceLocation Advance(SourceLocation left, string text)
        {
            if (text == null)
            {
                throw new ArgumentNullException(nameof(text));
            }

            var tracker = new SourceLocationTracker(left);

            tracker.UpdateLocation(text);
            return(tracker.CurrentLocation);
        }
Exemplo n.º 15
0
    public void UpdateLocationAdvancesCorrectlyForMultiLineString()
    {
        // Arrange
        var location = TestStartLocation;

        // Act
        var currentLocation = SourceLocationTracker.Advance(location, "foo\nbar\rbaz\r\nbox");

        // Assert
        Assert.Equal(26, currentLocation.AbsoluteIndex);
        Assert.Equal(45, currentLocation.LineIndex);
        Assert.Equal(3, currentLocation.CharacterIndex);
    }
Exemplo n.º 16
0
        /// <summary>
        /// Changes the start position of the current span.
        /// </summary>
        /// <param name="newStart">The new start location.</param>
        public void ChangeStart(SourceLocation newStart)
        {
            _start = newStart;
            var current = this;
            var tracker = new SourceLocationTracker(newStart);

            tracker.UpdateLocation(Content);
            while ((current = current.Next) != null)
            {
                current._start = tracker.CurrentLocation;
                tracker.UpdateLocation(current.Content);
            }
        }
        public void UpdateLocationAdvancesCorrectlyForMultiLineString()
        {
            // Arrange
            SourceLocationTracker tracker = new SourceLocationTracker(TestStartLocation);

            // Act
            tracker.UpdateLocation("foo\nbar\rbaz\r\nbox");

            // Assert
            Assert.Equal(26, tracker.CurrentLocation.AbsoluteIndex);
            Assert.Equal(45, tracker.CurrentLocation.LineIndex);
            Assert.Equal(3, tracker.CurrentLocation.CharacterIndex);
        }
Exemplo n.º 18
0
    public void Advance_PreservesSourceLocationFilePath(string path)
    {
        // Arrange
        var sourceLocation = new SourceLocation(path, 15, 2, 8);

        // Act
        var result = SourceLocationTracker.Advance(sourceLocation, "Hello world");

        // Assert
        Assert.Equal(path, result.FilePath);
        Assert.Equal(26, result.AbsoluteIndex);
        Assert.Equal(2, result.LineIndex);
        Assert.Equal(19, result.CharacterIndex);
    }
Exemplo n.º 19
0
            // public SourceLocationTracker SourceLocationTracker => _tracker;

            public override void VisitToken(SyntaxToken token)
            {
                if (token != null && !token.IsMissing && token.Kind != SyntaxKind.Marker)
                {
                    var start = token.GetSourceLocation(_source);
                    if (!start.Equals(_currentLocation))
                    {
                        throw new InvalidOperationException($"Token starting at {start} should start at {_currentLocation} - {token} ");
                    }

                    _currentLocation = SourceLocationTracker.Advance(_currentLocation, token.Content);
                }

                base.VisitToken(token);
            }
Exemplo n.º 20
0
        public static void EvaluateParseTree(TestContext context, Block actualRoot, Block expectedRoot)
        {
            // Evaluate the result
            ErrorCollector        collector = new ErrorCollector();
            SourceLocationTracker tracker   = new SourceLocationTracker();

            // Link all the nodes
            Span first    = null;
            Span previous = null;

            foreach (Span span in expectedRoot.Flatten())
            {
                if (first == null)
                {
                    first = span;
                }
                span.Previous = previous;
                if (previous != null)
                {
                    previous.Next = span;
                }
                previous = span;
            }
            Span.ClearCachedStartPoints(first);

            if (expectedRoot == null)
            {
                Assert.IsNull(actualRoot, "Expected an empty document.  Actual: {0}", actualRoot);
            }
            else
            {
                Assert.IsNotNull(actualRoot, "Expected a valid document, but it was empty");
                EvaluateSyntaxTreeNode(collector, tracker, actualRoot, expectedRoot);
                if (collector.Success)
                {
                    if (context != null)
                    {
                        context.WriteLine("Parse Tree Validation Succeeded:\r\n{0}", collector.Message);
                    }
                }
                else
                {
                    Assert.Fail("\r\n{0}", collector.Message);
                }
            }
        }
Exemplo n.º 21
0
        protected virtual SpanBuilder UpdateSpan(Span target, TextChange normalizedChange)
        {
            var newContent = normalizedChange.ApplyChange(target);
            var newSpan    = new SpanBuilder(target);

            newSpan.ClearSymbols();
            foreach (ISymbol sym in Tokenizer(newContent))
            {
                sym.OffsetStart(target.Start);
                newSpan.Accept(sym);
            }
            if (target.Next != null)
            {
                var newEnd = SourceLocationTracker.CalculateNewLocation(target.Start, newContent);
                target.Next.ChangeStart(newEnd);
            }
            return(newSpan);
        }
Exemplo n.º 22
0
        private void HandleWhitespaceRewriting()
        {
            Debug.Assert(!String.IsNullOrEmpty(_nextSpanToOutput.Content));

            // Check the last span for trailing whitespace
            int endOfWhitespaceToCapture = _nextSpanToOutput.Content.Length;

            for (int i = _nextSpanToOutput.Content.Length - 1; i >= 0; i--)
            {
                char c = _nextSpanToOutput.Content[i];
                if (CharUtils.IsNewLine(c))
                {
                    break;
                }
                else if (!Char.IsWhiteSpace(c))
                {
                    return; // Saw non-whitespace before newline, markup owns this whitespace so don't touch it
                }
                else
                {
                    endOfWhitespaceToCapture = i;
                }
            }

            // Ok, endOfWhitespaceToCapture is now at the offset of the first whitespace character after the newline
            string oldContent = _nextSpanToOutput.Content;

            _nextSpanToOutput.Content = oldContent.Substring(0, endOfWhitespaceToCapture);

            SourceLocationTracker tracker = new SourceLocationTracker();

            tracker.CurrentLocation = _nextSpanToOutput.Start;
            tracker.UpdateLocation(_nextSpanToOutput.Content);
            Span whitespaceSpan = new CodeSpan(tracker.CurrentLocation, oldContent.Substring(endOfWhitespaceToCapture));

            Visitor.VisitSpan(_nextSpanToOutput);
            _nextSpanToOutput = whitespaceSpan;
        }
Exemplo n.º 23
0
        private static void EvaluateSyntaxTreeNode(ErrorCollector collector, SourceLocationTracker tracker, SyntaxTreeNode actual, SyntaxTreeNode expected)
        {
            if (actual == null)
            {
                AddNullActualError(collector, tracker, actual, expected);
            }

            if (actual.IsBlock != expected.IsBlock)
            {
                AddMismatchError(collector, tracker, actual, expected);
            }
            else
            {
                if (expected.IsBlock)
                {
                    EvaluateBlock(collector, tracker, (Block)actual, (Block)expected);
                }
                else
                {
                    EvaluateSpan(collector, tracker, (Span)actual, (Span)expected);
                }
            }
        }
Exemplo n.º 24
0
        public override SyntaxNode VisitMarkupElement(MarkupElementSyntax node)
        {
            if (IsPartOfStartTag(node))
            {
                // If this element is inside a start tag, it is some sort of malformed case like
                // <p @do { someattribute=\"btn\"></p>, where the end "p" tag is inside the start "p" tag.
                // We don't want to do tag helper parsing for this tag.
                return(base.VisitMarkupElement(node));
            }

            MarkupTagHelperStartTagSyntax tagHelperStart = null;
            MarkupTagHelperEndTagSyntax   tagHelperEnd   = null;
            TagHelperInfo tagHelperInfo = null;

            // Visit the start tag.
            var startTag = (MarkupStartTagSyntax)Visit(node.StartTag);

            if (startTag != null)
            {
                var tagName = startTag.GetTagNameWithOptionalBang();
                if (TryRewriteTagHelperStart(startTag, node.EndTag, out tagHelperStart, out tagHelperInfo))
                {
                    // This is a tag helper.
                    if (tagHelperInfo.TagMode == TagMode.SelfClosing || tagHelperInfo.TagMode == TagMode.StartTagOnly)
                    {
                        var tagHelperElement   = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body: new SyntaxList <RazorSyntaxNode>(), endTag: null);
                        var rewrittenTagHelper = tagHelperElement.WithTagHelperInfo(tagHelperInfo);
                        if (node.Body.Count == 0 && node.EndTag == null)
                        {
                            return(rewrittenTagHelper);
                        }

                        // This tag contains a body and/or an end tag which needs to be moved to the parent.
                        var rewrittenNodes = SyntaxListBuilder <RazorSyntaxNode> .Create();

                        rewrittenNodes.Add(rewrittenTagHelper);
                        var rewrittenBody = VisitList(node.Body);
                        rewrittenNodes.AddRange(rewrittenBody);

                        return(SyntaxFactory.MarkupElement(startTag: null, body: rewrittenNodes.ToList(), endTag: node.EndTag));
                    }
                    else if (node.EndTag == null)
                    {
                        // Start tag helper with no corresponding end tag.
                        _errorSink.OnError(
                            RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(
                                new SourceSpan(SourceLocationTracker.Advance(startTag.GetSourceLocation(_source), "<"), tagName.Length),
                                tagName));
                    }
                    else
                    {
                        // Tag helper start tag. Keep track.
                        var tracker = new TagHelperTracker(_tagHelperPrefix, tagHelperInfo);
                        _trackerStack.Push(tracker);
                    }
                }
                else
                {
                    // Non-TagHelper tag.
                    ValidateParentAllowsPlainStartTag(startTag);

                    if (node.EndTag != null || (!startTag.IsSelfClosing() && !startTag.IsVoidElement()))
                    {
                        // Ideally we don't want to keep track of self-closing or void tags.
                        // But if a matching end tag exists, keep track of the start tag no matter what.
                        // We will just assume the parser had a good reason to do this.
                        var tracker = new TagTracker(tagName, isTagHelper: false);
                        _trackerStack.Push(tracker);
                    }
                }
            }

            // Visit body between start and end tags.
            var body = VisitList(node.Body);

            // Visit end tag.
            var endTag = (MarkupEndTagSyntax)Visit(node.EndTag);

            if (endTag != null)
            {
                var tagName = endTag.GetTagNameWithOptionalBang();
                if (TryRewriteTagHelperEnd(startTag, endTag, out tagHelperEnd))
                {
                    // This is a tag helper
                    if (startTag == null)
                    {
                        // The end tag helper has no corresponding start tag, create an error.
                        _errorSink.OnError(
                            RazorDiagnosticFactory.CreateParsing_TagHelperFoundMalformedTagHelper(
                                new SourceSpan(SourceLocationTracker.Advance(endTag.GetSourceLocation(_source), "</"), tagName.Length), tagName));
                    }
                }
                else
                {
                    // Non tag helper end tag.
                    if (startTag == null)
                    {
                        // Standalone end tag. We may need to error if it is not supposed to be here.
                        // If there was a corresponding start tag, we would have already added this error.
                        ValidateParentAllowsPlainEndTag(endTag);
                    }
                    else
                    {
                        // Since a start tag exists, we must already be tracking it.
                        // Pop the stack as we're done with the end tag.
                        _trackerStack.Pop();
                    }
                }
            }

            if (tagHelperInfo != null)
            {
                // If we get here it means this element was rewritten as a tag helper.
                var tagHelperElement = SyntaxFactory.MarkupTagHelperElement(tagHelperStart, body, tagHelperEnd);
                return(tagHelperElement.WithTagHelperInfo(tagHelperInfo));
            }

            // There was no matching tag helper for this element. Return.
            return(node.Update(startTag, body, endTag));
        }
Exemplo n.º 25
0
 private static SourceLocation GetEndTagDeclarationErrorStart(MarkupEndTagSyntax tagBlock, RazorSourceDocument source)
 {
     return(SourceLocationTracker.Advance(tagBlock.GetSourceLocation(source), "</"));
 }
Exemplo n.º 26
0
        private bool TryRewriteTagHelperEnd(MarkupStartTagSyntax startTag, MarkupEndTagSyntax endTag, out MarkupTagHelperEndTagSyntax rewritten)
        {
            rewritten = null;
            var tagName = endTag.GetTagNameWithOptionalBang();

            // Could not determine tag name, it can't be a TagHelper, continue on and track the element.
            if (string.IsNullOrEmpty(tagName) || tagName.StartsWith("!", StringComparison.Ordinal))
            {
                return(false);
            }

            var tracker      = CurrentTagHelperTracker;
            var tagNameScope = tracker?.TagName ?? string.Empty;

            if (!IsPotentialTagHelperEnd(tagName, endTag))
            {
                return(false);
            }

            // Validate that our end tag matches the currently scoped tag, if not we may need to error.
            if (startTag != null && tagNameScope.Equals(tagName, StringComparison.OrdinalIgnoreCase))
            {
                // If there are additional end tags required before we can build our block it means we're in a
                // situation like this: <myth req="..."><myth></myth></myth> where we're at the inside </myth>.
                if (tracker.OpenMatchingTags > 0)
                {
                    tracker.OpenMatchingTags--;

                    return(false);
                }

                ValidateEndTagSyntax(tagName, endTag);

                _trackerStack.Pop();
            }
            else
            {
                var tagHelperBinding = _tagHelperBinder.GetBinding(
                    tagName,
                    attributes: Array.Empty <KeyValuePair <string, string> >(),
                    parentTagName: CurrentParentTagName,
                    parentIsTagHelper: CurrentParentIsTagHelper);

                // If there are not TagHelperDescriptors associated with the end tag block that also have no
                // required attributes then it means we can't be a TagHelper, bail out.
                if (tagHelperBinding == null)
                {
                    return(false);
                }

                foreach (var descriptor in tagHelperBinding.Descriptors)
                {
                    var boundRules  = tagHelperBinding.Mappings[descriptor];
                    var invalidRule = boundRules.FirstOrDefault(rule => rule.TagStructure == TagStructure.WithoutEndTag);

                    if (invalidRule != null)
                    {
                        // End tag TagHelper that states it shouldn't have an end tag.
                        _errorSink.OnError(
                            RazorDiagnosticFactory.CreateParsing_TagHelperMustNotHaveAnEndTag(
                                new SourceSpan(SourceLocationTracker.Advance(endTag.GetSourceLocation(_source), "</"), tagName.Length),
                                tagName,
                                descriptor.DisplayName,
                                invalidRule.TagStructure));

                        return(false);
                    }
                }
            }

            rewritten = SyntaxFactory.MarkupTagHelperEndTag(
                endTag.OpenAngle, endTag.ForwardSlash, endTag.Bang, endTag.Name, endTag.MiscAttributeContent, endTag.CloseAngle);

            return(true);
        }
Exemplo n.º 27
0
 public SpanFactory()
 {
     LocationTracker = new SourceLocationTracker();
 }
Exemplo n.º 28
0
 public Verifier(RazorSourceDocument source)
 {
     _tracker = new SourceLocationTracker(new SourceLocation(source.FilePath, 0, 0, 0));
     _source  = source;
 }
Exemplo n.º 29
0
 private static void AddMismatchError(ErrorCollector collector, SourceLocationTracker tracker, SyntaxTreeNode actual, SyntaxTreeNode expected)
 {
     collector.AddError("{0} - FAILED :: Actual: {1}", expected, actual);
 }
Exemplo n.º 30
0
 private static void AddNullActualError(ErrorCollector collector, SourceLocationTracker tracker, SyntaxTreeNode actual, SyntaxTreeNode expected)
 {
     collector.AddError("{0} - FAILED :: Actual: << Null >>", expected);
 }