コード例 #1
0
ファイル: Blender.cs プロジェクト: stark-lang/stark
        /// <summary>
        /// Affected range of a change is the range within which nodes can be affected by a change
        /// and cannot be reused. Because of lookahead effective range of a change is larger than
        /// the change itself.
        /// </summary>
        private static TextChangeRange ExtendToAffectedRange(
            Stark.CSharpSyntaxNode oldTree,
            TextChangeRange changeRange)
        {
            // we will increase affected range of the change by the number of lookahead tokens
            // original code in Blender seem to imply the lookahead at the end of a node is 1 token
            // max. TODO: 1 token lookahead seems a bit too optimistic. Increase if needed.
            const int maxLookahead = 1;

            // check if change is not after the end. TODO: there should be an assert somewhere about
            // changes starting at least at the End of old tree
            var lastCharIndex = oldTree.FullWidth - 1;

            // Move the start of the change range so that it is contained within oldTree.
            var start = Math.Max(Math.Min(changeRange.Span.Start, lastCharIndex), 0);

            // the first iteration aligns us with the change start. subsequent iteration move us to
            // the left by maxLookahead tokens.  We only need to do this as long as we're not at the
            // start of the tree.  Also, the tokens we get back may be zero width.  In that case we
            // need to keep on looking backward.
            for (var i = 0; start > 0 && i <= maxLookahead;)
            {
                var token = oldTree.FindToken(start, findInsideTrivia: false);
                Debug.Assert(token.Kind() != SyntaxKind.None, "how could we not get a real token back?");

                start = Math.Max(0, token.Position - 1);

                // Only increment i if we got a non-zero width token.  Otherwise, we want to just do
                // this again having moved back one space.
                if (token.FullWidth > 0)
                {
                    i++;
                }
            }

            if (IsInsideInterpolation(oldTree, start))
            {
                // If the changed range starts inside an interpolated string, we
                // move the start of the change range to the beginning of the line so that any
                // interpolated string literal in the changed range will be scanned in its entirety.
                var column = oldTree.SyntaxTree.GetLineSpan(new TextSpan(start, 0)).Span.Start.Character;
                start = Math.Max(start - column, 0);
            }

            var finalSpan   = TextSpan.FromBounds(start, changeRange.Span.End);
            var finalLength = changeRange.NewLength + (changeRange.Span.Start - start);

            return(new TextChangeRange(finalSpan, finalLength));
        }
コード例 #2
0
ファイル: Blender.cs プロジェクト: stark-lang/stark
        private static bool IsInsideInterpolation(Stark.CSharpSyntaxNode oldTree, int start)
        {
            var token = oldTree.FindToken(start, findInsideTrivia: false);

            for (var parent = token.Parent; // for each parent
                 parent != null;
                 parent = parent.Parent)
            {
                if (parent.Kind() == SyntaxKind.InterpolatedStringExpression)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #3
0
ファイル: Blender.cs プロジェクト: stark-lang/stark
        public Blender(Lexer lexer, Stark.CSharpSyntaxNode oldTree, IEnumerable <TextChangeRange> changes)
        {
            Debug.Assert(lexer != null);
            _lexer   = lexer;
            _changes = ImmutableStack.Create <TextChangeRange>();

            if (changes != null)
            {
                // TODO: Consider implementing NormalizedChangeCollection for TextSpan. the real
                // reason why we are collapsing is because we want to extend change ranges and
                // cannot allow them to overlap. This does not seem to be a big deal since multiple
                // changes are infrequent and typically close to each other. However if we have
                // NormalizedChangeCollection for TextSpan we can have both - we can extend ranges
                // and not require collapsing them. NormalizedChangeCollection would also ensure
                // that changes are always normalized.

                // TODO: this is a temporary measure to prevent individual change spans from
                // overlapping after they are widened to effective width (+1 token at the start).
                // once we have normalized collection for TextSpan we will not need to collapse all
                // the change spans.

                var collapsed = TextChangeRange.Collapse(changes);

                // extend the change to its affected range. This will make it easier
                // to filter out affected nodes since we will be able simply check
                // if node intersects with a change.
                var affectedRange = ExtendToAffectedRange(oldTree, collapsed);
                _changes = _changes.Push(affectedRange);
            }

            if (oldTree == null)
            {
                // start at lexer current position if no nodes specified
                _oldTreeCursor = new Cursor();
                _newPosition   = lexer.TextWindow.Position;
            }
            else
            {
                _oldTreeCursor = Cursor.FromRoot(oldTree).MoveToFirstChild();
                _newPosition   = 0;
            }

            _changeDelta        = 0;
            _newDirectives      = default(DirectiveStack);
            _oldDirectives      = default(DirectiveStack);
            _newLexerDrivenMode = 0;
        }
コード例 #4
0
        protected SyntaxParser(
            Lexer lexer,
            LexerMode mode,
            Stark.CSharpSyntaxNode oldTree,
            IEnumerable <TextChangeRange> changes,
            bool allowModeReset,
            bool preLexIfNotIncremental         = false,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            this.lexer             = lexer;
            _mode                  = mode;
            _allowModeReset        = allowModeReset;
            this.cancellationToken = cancellationToken;
            _currentNode           = default(BlendedNode);
            _isIncremental         = oldTree != null;

            if (this.IsIncremental || allowModeReset)
            {
                _firstBlender  = new Blender(lexer, oldTree, changes);
                _blendedTokens = s_blendedNodesPool.Allocate();
            }
            else
            {
                _firstBlender = default(Blender);
                _lexedTokens  = new ArrayElement <SyntaxToken> [32];
            }

            // PreLex is not cancellable.
            //      If we may cancel why would we aggressively lex ahead?
            //      Cancellations in a constructor make disposing complicated
            //
            // So, if we have a real cancellation token, do not do prelexing.
            if (preLexIfNotIncremental && !this.IsIncremental && !cancellationToken.CanBeCanceled)
            {
                this.PreLex();
            }
        }
コード例 #5
0
 internal BlendedNode(Stark.CSharpSyntaxNode node, SyntaxToken token, Blender blender)
 {
     this.Node    = node;
     this.Token   = token;
     this.Blender = blender;
 }
コード例 #6
0
ファイル: Blender.Reader.cs プロジェクト: stark-lang/stark
 private BlendedNode CreateBlendedNode(Stark.CSharpSyntaxNode node, SyntaxToken token)
 {
     return(new BlendedNode(node, token,
                            new Blender(_lexer, _oldTreeCursor, _changes, _newPosition, _changeDelta, _newDirectives, _oldDirectives, _newLexerDrivenMode)));
 }
コード例 #7
0
ファイル: Blender.Reader.cs プロジェクト: stark-lang/stark
 private static bool IsIncomplete(Stark.CSharpSyntaxNode node)
 {
     // A node is incomplete if the last token in it is a missing token.  Use the green
     // node to determine this as it's much faster than going through the red API.
     return(node.Green.GetLastTerminal().IsMissing);
 }
コード例 #8
0
 public static Cursor FromRoot(Stark.CSharpSyntaxNode node)
 {
     return(new Cursor(node, indexInParent: 0));
 }