/// <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); }