コード例 #1
0
 public Location(string source, Position declOffset, QsLocation stmLoc, Range range)
 {
     this.SourceFile                = source;
     this.DeclarationOffset         = declOffset;
     this.RelativeStatementLocation = stmLoc;
     this.SymbolRange               = range;
 }
コード例 #2
0
 /// <summary>
 /// Note that the only thing that may be set to null is the fragment kind - all other properties need to be set upon initialization
 /// </summary>
 private CodeFragment(int indent, Range range, string text, char next, QsComments?comments, QsFragmentKind?kind, bool include)
 {
     if (!DelimitingChars.Contains(next) && next != MissingDelimiter)
     {
         throw new ArgumentException("a CodeFragment needs to be followed by a DelimitingChar");
     }
     this.Indentation          = indent < 0 ? throw new ArgumentException("indentation needs to be positive") : indent;
     this.Text                 = text.TrimEnd();
     this.FollowedBy           = next;
     this.Comments             = comments ?? QsComments.Empty;
     this.Kind                 = kind; // nothing here should be modifiable
     this.Range                = range;
     this.HeaderRange          = GetHeaderRange(this.Text, this.Kind);
     this.IncludeInCompilation = include;
 }
コード例 #3
0
        // external routines for context verification

        /// <summary>
        /// Given the line number of the lines that contain tokens that (possibly) have been modified,
        /// checks which callable declaration they can potentially belong to and returns the fully qualified name of those callables.
        /// </summary>
        internal static IEnumerable <(Range, QsQualifiedName)> CallablesWithContentModifications(this FileContentManager file, IEnumerable <int> changedLines)
        {
            var lastInFile = file.LastToken()?.GetFragment()?.Range?.End ?? file.End();
            var callables  = file.GetCallableDeclarations().Select(tuple => // these are sorted according to their line number
            {
                var ns = file.TryGetNamespaceAt(tuple.Item2.Start);
                QsCompilerError.Verify(ns != null, "namespace for callable declaration should not be null"); // invalid namespace names default to an unknown namespace name, but remain included in the compilation
                return(tuple.Item2.Start, new QsQualifiedName(ns, tuple.Item1));
            }).ToList();

            // NOTE: The range of modifications that has to trigger an update of the syntax tree for a callable
            // does need to go up to and include modifications to the line containing the next callable!
            // Otherwise inserting a callable declaration in the middle of an existing callable does not trigger the right behavior!
            (Range, QsQualifiedName) TypeCheckingRange((Position, QsQualifiedName) lastPreceding, IEnumerable <(Position, QsQualifiedName)> next)
            {
                var callableStart = lastPreceding.Item1;
                var callableEnd   = next.Any() ? next.First().Item1 : lastInFile;

                return(Range.Create(callableStart, callableEnd), lastPreceding.Item2);
            }

            foreach (var lineNr in changedLines)
            {
                bool Precedes((Position, QsQualifiedName) tuple) => tuple.Item1.Line < lineNr;

                var preceding = callables.TakeWhile(Precedes);
                var following = callables.SkipWhile(Precedes);

                if (preceding.Any())
                {
                    yield return(TypeCheckingRange(preceding.Last(), following));
                }
                if (following.Any() && following.First().Start.Line == lineNr)
                {
                    yield return(TypeCheckingRange(following.First(), following.Skip(1)));
                }
            }
        }
コード例 #4
0
 internal CodeFragment SetRange(Range range) =>
 new CodeFragment(this.Indentation, range, this.Text, this.FollowedBy, this.Comments, this.Kind, this.IncludeInCompilation);
コード例 #5
0
 internal CodeFragment(int indent, Range range, string text, char next, QsFragmentKind?kind = null)
     : this(indent, range, text, next, null, kind, true)
 {
 }
コード例 #6
0
 /// <summary>
 /// Returns a function that returns true if a given fragment does not overlap with the specified range.
 /// </summary>
 internal static Func <CodeFragment, bool> NotOverlappingWith(Range relRange) => token =>
 token.IsWithinRange(Range.Create(Position.Zero, relRange.Start)) ||
 TokensAfter(relRange.End)(token);
コード例 #7
0
 /// <summary>
 /// Returns true if the given token is fully included in the given range.
 /// </summary>
 internal static bool IsWithinRange(this CodeFragment token, Range range) =>
 range.Contains(token.Range.Start) && range.ContainsEnd(token.Range.End);
コード例 #8
0
        /// <summary>
        /// Returns true if the given file contains any tokens overlapping with the given fragment.
        /// The range of the tokens in the file is assumed to be relative to their start line (the index at which they are listed),
        /// whereas the range of the given fragment is assumed to be the absolute range.
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="range"/> is not a valid range within <paramref name="file"/>.</exception>
        internal static bool ContainsTokensOverlappingWith(this FileContentManager file, Range range)
        {
            if (!file.ContainsRange(range))
            {
                throw new ArgumentOutOfRangeException(nameof(range));
            }

            var(start, end) = (range.Start.Line, range.End.Line);
            if (start != end && file.GetTokenizedLines(start + 1, end - start - 1).SelectMany(x => x).Any())
            {
                return(true);
            }

            var inRange = file.GetTokenizedLine(start).Where(TokensAfter(Position.Create(0, range.Start.Column))); // checking tokens overlapping with range.Start below

            inRange = start == end
                ? inRange.Where(TokensStartingBefore(Position.Create(0, range.End.Column)))
                : inRange.Concat(file.GetTokenizedLine(end).Where(TokensStartingBefore(Position.Create(0, range.End.Column))));

            if (inRange.Any())
            {
                QsCompilerError.Raise($"{range.DiagnosticString()} overlaps for start = {start}, end = {end}, \n\n" +
                                      $"{string.Join("\n", file.GetTokenizedLine(start).Select(x => $"{x.Range.DiagnosticString()}"))},\n\n " +
                                      $"{string.Join("\n", file.GetTokenizedLine(end).Select(x => $"{x.Range.DiagnosticString()}"))},");
                return(true);
            }

            var overlapsWithStart = file.TryGetFragmentAt(range.Start, out _);

            return(overlapsWithStart != null);
        }
コード例 #9
0
        /// <summary>
        /// Given the location information for a declared symbol,
        /// as well as the position of the declaration within which the symbol is declared,
        /// returns the zero-based line and character index indicating the position of the symbol in the file.
        /// Returns null if the given object is not compatible with the position information generated by this CompilationBuilder.
        /// </summary>
        public static Position SymbolPosition(QsLocation rootLocation, QsNullable <Position> symbolPosition, Range symbolRange)
        {
            // the position offset is set to null (only) for variables defined in the declaration
            var offset = symbolPosition.IsNull ? rootLocation.Offset : rootLocation.Offset + symbolPosition.Item;

            return(offset + symbolRange.Start);
        }
コード例 #10
0
 /// <summary>
 /// Returns true if the start position of the diagnostic range is contained in the given range, excluding the
 /// given range's end position.
 /// </summary>
 internal static bool SelectByStart(this Diagnostic m, Range range) =>
 !(m?.Range?.Start is null) && range.Contains(m.Range.Start.ToQSharp());
コード例 #11
0
        // utils for getting the necessary information for editor commands

        internal static Location AsLocation(string source, Position offset, Range relRange) =>
コード例 #12
0
        /// <summary>
        /// Returns all code fragments in the specified file that overlap with the given range.
        /// Returns an empty sequence if any of the given arguments is null.
        /// </summary>
        private static IEnumerable <CodeFragment> FragmentsOverlappingWithRange(this FileContentManager file, Range range)
        {
            if (file is null || range is null)
            {
                return(Enumerable.Empty <CodeFragment>());
            }
            var(start, end) = (range.Start.Line, range.End.Line);

            var fragAtStart = file.TryGetFragmentAt(range.Start, out _, includeEnd: true);
            var inRange     = file.GetTokenizedLine(start).Select(t => t.WithLineNumOffset(start)).Where(ContextBuilder.TokensAfter(range.Start)); // does not include fragAtStart

            inRange = start == end
                ? inRange.Where(ContextBuilder.TokensStartingBefore(range.End))
                : inRange.Concat(file.GetTokenizedLines(start + 1, end - start - 1).SelectMany((x, i) => x.Select(t => t.WithLineNumOffset(start + 1 + i))))
                      .Concat(file.GetTokenizedLine(end).Select(t => t.WithLineNumOffset(end)).Where(ContextBuilder.TokensStartingBefore(range.End)));

            var fragments = ImmutableArray.CreateBuilder <CodeFragment>();

            if (fragAtStart != null)
            {
                fragments.Add(fragAtStart);
            }
            fragments.AddRange(inRange);
            return(fragments.ToImmutableArray());
        }