コード例 #1
0
        /// <summary>
        /// Dequeues all lines whose tokens has changed and verifies the positions of these tokens.
        /// Does nothing if no lines have been modified.
        /// Recomputes and pushes the context diagnostics for the processed tokens otherwise.
        /// </summary>
        internal static void UpdateContext(this FileContentManager file)
        {
            file.SyncRoot.EnterUpgradeableReadLock();
            try
            {
                var changedLines = file.DequeueTokenChanges();
                if (!changedLines.Any())
                {
                    return;
                }
                QsCompilerError.RaiseOnFailure(
                    () =>
                {
                    var verifiedLines = file.VerifyContext(changedLines, out List <Diagnostic> diagnostics);
                    file.UpdateContextDiagnostics(verifiedLines, diagnostics);
                },
                    "updating the ContextDiagnostics failed");

                var edited = file.CallablesWithContentModifications(changedLines);
                file.MarkCallableAsContentEdited(edited);
            }
            finally
            {
                file.SyncRoot.ExitUpgradeableReadLock();
            }
        }
コード例 #2
0
        }                                                                                           // will raise an exception if file is null

        // the actual update routine

        /// <summary>
        /// Attempts to perform the necessary updates when replacing the range [start, start + count) by newText for the given file
        /// wrapping each step in a QsCompilerError.RaiseOnFailure.
        /// </summary>
        private static void Update(this FileContentManager file, int start, int count, IEnumerable <string> newText)
        {
            CodeLine[] replacements = QsCompilerError.RaiseOnFailure(() =>
                                                                     ComputeCodeLines(newText, start > 0 ? file.GetLine(start - 1) : null).ToArray(),
                                                                     "scope tracking update failed during computing the replacements");

            IEnumerable <CodeLine> updateRemaining = QsCompilerError.RaiseOnFailure(() =>
                                                                                    ComputeUpdates(file, start, count, replacements),
                                                                                    "scope tracking update failed during computing the updates");

            QsCompilerError.RaiseOnFailure(() =>
            {
                if (updateRemaining == null)
                {
                    file.ContentUpdate(start, count, replacements);
                }
                else
                {
                    file.ContentUpdate(start, file.NrLines() - start, replacements.Concat(updateRemaining).ToArray());
                }
            }, "the proposed ContentUpdate failed");

            QsCompilerError.RaiseOnFailure(() =>
            {
                if (updateRemaining == null)
                {
                    file.AddScopeDiagnostics(file.ComputeScopeDiagnostics(start, replacements.Length));
                }
                else
                {
                    file.AddScopeDiagnostics(file.ComputeScopeDiagnostics(start));
                }
                file.AddScopeDiagnostics(file.CheckForMissingClosings());
            }, "updating the scope diagnostics failed");
        }
コード例 #3
0
        /// <summary>
        /// Assuming both the current tokens and the tokens to update are sorted according to their range,
        /// merges the current and updated tokens such that the merged collection is sorted as well.
        /// </summary>
        /// <exception cref="QsCompilerException">The token verification for the merged collection failed.</exception>
        internal static List <CodeFragment> MergeTokens(IEnumerable <CodeFragment> current, IEnumerable <CodeFragment> updated)
        {
            var merged = new List <CodeFragment>(0);

            void NextBatch(ref IEnumerable <CodeFragment> batch, IEnumerable <CodeFragment> next)
            {
                if (next.Any())
                {
                    var start = next.First().Range.Start;
                    merged.AddRange(batch.TakeWhile(TokensUpTo(start)));
                    batch = batch.SkipWhile(TokensUpTo(start)).ToList();
                }
                else
                {
                    merged.AddRange(batch);
                    batch = Enumerable.Empty <CodeFragment>();
                }
            }

            while (updated.Any() || current.Any())
            {
                NextBatch(ref current, updated);
                NextBatch(ref updated, current);
            }

            var mergedTokens = merged.ToList();

            QsCompilerError.RaiseOnFailure(() => VerifyTokenOrdering(mergedTokens), "merged tokens are not ordered");
            return(mergedTokens);
        }
コード例 #4
0
ファイル: TextProcessor.cs プロジェクト: sw23/qsharp-compiler
        /// <summary>
        /// Dequeues all lines whose content has changed and extracts the code fragments overlapping with those lines that need to be reprocessed.
        /// Does nothing if no lines have been modified.
        /// Recomputes and pushes the syntax diagnostics for the extracted fragments and all end-of-file diagnostics otherwise.
        /// Processes the extracted fragment and inserts the processed fragments into the corresponding data structure
        /// Throws an ArgumentNullException if file is null.
        /// </summary>
        internal static void UpdateLanguageProcessing(this FileContentManager file)
        {
            if (file == null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            file.SyncRoot.EnterUpgradeableReadLock();
            try
            {
                var changedLines = file.DequeueContentChanges();
                if (!changedLines.Any())
                {
                    return;
                }

                var reprocess   = QsCompilerError.RaiseOnFailure(() => file.FragmentsToProcess(changedLines).ToList(), "processing the edited lines failed");
                var diagnostics = reprocess.CheckForEmptyFragments(file.FileName.Value)
                                  .Concat(ParseCode(ref reprocess, file.FileName.Value)).ToList();

                QsCompilerError.RaiseOnFailure(() => file.TokensUpdate(reprocess), "the computed token update failed");
                QsCompilerError.RaiseOnFailure(() => file.AddSyntaxDiagnostics(diagnostics), "updating the SyntaxDiagnostics failed");
            }
            finally { file.SyncRoot.ExitUpgradeableReadLock(); }
        }
コード例 #5
0
 private Task ProcessingTaskAsync(Action action) =>
 new Task(() =>
 {
     try
     {
         QsCompilerError.RaiseOnFailure(action, this.exceptionHeader);
     }
     catch (Exception ex)
     {
         this.logException(ex);
     }
 });
コード例 #6
0
        /// <summary>
        /// Calls the Q# parser on each fragment, splitting one fragment into several if necessary
        /// (i.e. modifies the list of given fragments!).
        /// Fragments for which the code only consists of whitespace are left unchanged (i.e. the Kind remains set to null).
        /// Adds a suitable error to the returned diagnostics for each fragment that cannot be processed.
        /// Raises an ArgumentNullException if the given diagnostics or fragments are null.
        /// </summary>
        private static IEnumerable <Diagnostic> ParseCode(ref List <CodeFragment> fragments, string filename)
        {
            if (fragments == null)
            {
                throw new ArgumentNullException(nameof(fragments));
            }
            var processedFragments = new List <CodeFragment>(fragments.Count());
            var diagnostics        = new List <Diagnostic>();

            foreach (var snippet in fragments)
            {
                var snippetStart = snippet.GetRange().Start;
                var outputs      = Parsing.ProcessCodeFragment(snippet.Text);
                for (var outputIndex = 0; outputIndex < outputs.Length; ++outputIndex)
                {
                    var output        = outputs[outputIndex];
                    var fragmentRange = DiagnosticTools.GetAbsoluteRange(snippetStart, output.Range);
                    var fragment      = new CodeFragment(
                        snippet.Indentation,
                        fragmentRange,
                        output.Text.Value,
                        outputIndex == outputs.Length - 1 ? snippet.FollowedBy : CodeFragment.MissingDelimiter,
                        output.Kind);
                    processedFragments.Add(fragment);

                    var checkEnding = true; // if there is already a diagnostic overlapping with the ending, then don't bother checking the ending
                    foreach (var fragmentDiagnostic in output.Diagnostics)
                    {
                        var generated = Diagnostics.Generate(filename, fragmentDiagnostic, fragmentRange.Start);
                        diagnostics.Add(generated);

                        var fragmentEnd = fragment.GetRange().End;
                        var diagnosticGoesUpToFragmentEnd = fragmentEnd.IsWithinRange(generated.Range) || fragmentEnd.Equals(generated.Range.End);
                        if (fragmentDiagnostic.Diagnostic.IsError && diagnosticGoesUpToFragmentEnd)
                        {
                            checkEnding = false;
                        }
                    }
                    if (checkEnding)
                    {
                        diagnostics.AddRange(fragment.CheckFragmentDelimiters(filename));
                    }
                }
                if (outputs.Length == 0)
                {
                    processedFragments.Add(snippet); // keep empty fragments around (note that the kind is set to null in this case!)
                }
            }
            QsCompilerError.RaiseOnFailure(() => ContextBuilder.VerifyTokenOrdering(processedFragments), "processed fragments are not ordered properly and/or overlap");
            fragments = processedFragments;
            return(diagnostics);
        }
コード例 #7
0
        /// <summary>
        /// Verifies the given stringDelimiters and returns the given text without the content between the delimiters.
        /// </summary>
        private static string RemoveStrings(string text, IEnumerable <int> stringDelimiters)
        {
            QsCompilerError.RaiseOnFailure(() => VerifyStringDelimiters(text, stringDelimiters), "invalid delimiters for given text in call to RemoveStrings");

            var iter    = stringDelimiters.GetEnumerator();
            var trimmed =
                iter.MoveNext() ?
                iter.Current < 0 ? string.Empty : text.Substring(0, StartDelimiter(iter.Current)) :
                text;

            while (iter.MoveNext() && iter.Current < text.Length)
            {
                // Note: if modifications here are needed, modify Start- and EndDelimiter to make sure these changes are reflected in IndexInFullString
                var end   = iter.Current == text.Length ? text.Length : EndDelimiter(iter.Current); // end of a substring
                var start = iter.MoveNext() ? StartDelimiter(iter.Current) : text.Length;
                trimmed += text.Substring(end, start - end);
            }
            return(trimmed);
        }
コード例 #8
0
        // language server tools -
        // wrapping these into a try .. catch .. to make sure errors don't go unnoticed as they otherwise would

        public static T TryJTokenAs <T>(JToken arg)
            where T : class =>
        QsCompilerError.RaiseOnFailure(() => arg.ToObject <T>(), "could not cast given JToken");