Exemple #1
0
        /// <summary>
        /// Logs the generated Q# code for the part of the given evaluated syntax tree that corresponds to each file
        /// in the given compilation as Information using the given logger.
        /// If the given evaluated tree is null, queries the tree contained in the given compilation instead.
        /// If the id of a file is consistent with the one assigned to a code snippet,
        /// strips the lines of code that correspond to the wrapping defined by WrapSnippet.
        /// Throws an ArgumentException if this is not possible because the given syntax tree is inconsistent with that wrapping.
        /// Throws an ArgumentNullException if the given compilation is null.
        /// </summary>
        private static void PrintGeneratedQs(IEnumerable <QsNamespace> evaluatedTree, Compilation compilation, ILogger logger)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }
            evaluatedTree ??= compilation.SyntaxTree.Values;

            foreach (var file in compilation.SourceFiles)
            {
                if (Options.IsCodeSnippet(file))
                {
                    var subtree = evaluatedTree.Select(ns => FilterBySourceFile.Apply(ns, file)).Where(ns => ns.Elements.Any());
                    var code = new string[] { "" }.Concat(StripSnippetWrapping(subtree).Select(SyntaxTreeToQsharp.Default.ToCode));
                    logger.Log(InformationCode.FormattedQsCode, Enumerable.Empty <string>(), messageParam: code.ToArray());
                }
                else
                {
                    var imports = evaluatedTree.ToImmutableDictionary(ns => ns.Name, ns => compilation.OpenDirectives(file, ns.Name).ToImmutableArray());
                    SyntaxTreeToQsharp.Apply(out List <ImmutableDictionary <NonNullable <string>, string> > generated, evaluatedTree, (file, imports));
                    var code = new string[] { "" }.Concat(generated.Single().Values.Select(nsCode => $"{nsCode}{Environment.NewLine}"));
                    logger.Log(InformationCode.FormattedQsCode, Enumerable.Empty <string>(), file.Value, messageParam: code.ToArray());
                };
            }
        }
        /// <inheritdoc/>
        public AssemblyInfo BuildEntryPoint(OperationInfo operation, CompilerMetadata metadatas, QSharpLogger logger, string dllName, string executionTarget = null)
        {
            var signature     = operation.Header.PrintSignature();
            var argumentTuple = SyntaxTreeToQsharp.ArgumentTuple(operation.Header.ArgumentTuple, type => type.ToString(), symbolsOnly: true);

            var entryPointUri     = new Uri(Path.GetFullPath(Path.Combine("/", $"entrypoint.qs")));
            var entryPointSnippet = @$ "namespace ENTRYPOINT
                {{
                    open {operation.Header.QualifiedName.Namespace.Value};
Exemple #3
0
        /// <summary>
        /// Generates formatted Q# code based on the part of the syntax tree that corresponds to each file in the given compilation.
        /// If the id of a file is consistent with the one assigned to a code snippet,
        /// strips the lines of code that correspond to the wrapping defined by WrapSnippet.
        /// Throws an ArgumentException if this is not possible because the given syntax tree is inconsistent with that wrapping.
        /// Throws an ArgumentNullException if the given compilation is null.
        /// </summary>
        private static IEnumerable <string> GenerateQsCode(Compilation compilation, NonNullable <string> file, ILogger logger)
        {
            if (compilation == null)
            {
                throw new ArgumentNullException(nameof(compilation));
            }
            if (Options.IsCodeSnippet(file))
            {
                var subtree = compilation.SyntaxTree.Values.Select(ns => FilterBySourceFile.Apply(ns, file)).Where(ns => ns.Elements.Any());
                return(DiagnoseCompilation.StripSnippetWrapping(subtree).Select(SyntaxTreeToQsharp.Default.ToCode));
            }
            else
            {
                var imports = compilation.SyntaxTree.Values
                              .ToImmutableDictionary(ns => ns.Name, ns => compilation.OpenDirectives(file, ns.Name).ToImmutableArray());
                var success = SyntaxTreeToQsharp.Apply(out List <ImmutableDictionary <NonNullable <string>, string> > generated, compilation.SyntaxTree.Values, (file, imports));
                if (!success)
                {
                    logger?.Log(WarningCode.UnresolvedItemsInGeneratedQs, Enumerable.Empty <string>(), file.Value);
                }

                return(generated.Single().Select(entry =>
                {
                    var nsComments = compilation.NamespaceComments(file, entry.Key);
                    string FormatComments(IEnumerable <string> comments) =>
                    string.Join(
                        Environment.NewLine,
                        comments.Select(line => line.Trim()).Select(line => string.IsNullOrWhiteSpace(line) ? "" : $"// {line}"))
                    .Trim();
                    var leadingComments = entry.Value.StartsWith("///")
                        ? $"{FormatComments(nsComments.OpeningComments)}{Environment.NewLine}"
                        : FormatComments(nsComments.OpeningComments);
                    var trailingComments = FormatComments(nsComments.ClosingComments);

                    var code = new string[] { leadingComments, entry.Value, trailingComments }.Where(s => !string.IsNullOrWhiteSpace(s));
                    return string.Join(Environment.NewLine, code);
                }));
            }
        }
Exemple #4
0
        /// <summary>
        /// Returns a sequence of suggestions on how deprecated syntax can be updated based on the generated diagnostics,
        /// and given the file for which those diagnostics were generated.
        /// Returns an empty enumerable if any of the given arguments is null.
        /// </summary>
        internal static IEnumerable <(string, WorkspaceEdit)> SuggestionsForDeprecatedSyntax
            (this FileContentManager file, IEnumerable <Diagnostic> diagnostics)
        {
            if (file == null || diagnostics == null)
            {
                return(Enumerable.Empty <(string, WorkspaceEdit)>());
            }
            var deprecatedUnitTypes         = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedUnitType));
            var deprecatedNOToperators      = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedNOToperator));
            var deprecatedANDoperators      = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedANDoperator));
            var deprecatedORoperators       = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedORoperator));
            var deprecatedOpCharacteristics = diagnostics.Where(DiagnosticTools.WarningType(WarningCode.DeprecatedOpCharacteristics));

            (string, WorkspaceEdit) ReplaceWith(string text, LSP.Range range)
            {
                bool NeedsWs(Char ch) => Char.IsLetterOrDigit(ch) || ch == '_';

                if (range?.Start != null && range.End != null)
                {
                    var beforeEdit = file.GetLine(range.Start.Line).Text.Substring(0, range.Start.Character);
                    var afterEdit  = file.GetLine(range.End.Line).Text.Substring(range.End.Character);
                    if (beforeEdit.Any() && NeedsWs(beforeEdit.Last()))
                    {
                        text = $" {text}";
                    }
                    if (afterEdit.Any() && NeedsWs(afterEdit.First()))
                    {
                        text = $"{text} ";
                    }
                }
                var edit = new TextEdit {
                    Range = range?.Copy(), NewText = text
                };

                return($"Replace with \"{text.Trim()}\".", file.GetWorkspaceEdit(edit));
            }

            // update deprecated keywords and operators

            var suggestionsForUnitType = deprecatedUnitTypes.Select(d => ReplaceWith(Keywords.qsUnit.id, d.Range));
            var suggestionsForNOT      = deprecatedNOToperators.Select(d => ReplaceWith(Keywords.qsNOTop.op, d.Range));
            var suggestionsForAND      = deprecatedANDoperators.Select(d => ReplaceWith(Keywords.qsANDop.op, d.Range));
            var suggestionsForOR       = deprecatedORoperators.Select(d => ReplaceWith(Keywords.qsORop.op, d.Range));

            // update deprecated operation characteristics syntax

            string CharacteristicsAnnotation(Characteristics c)
            {
                var charEx = SyntaxTreeToQsharp.CharacteristicsExpression(SymbolResolution.ResolveCharacteristics(c));

                return(charEx == null ? "" : $"{Keywords.qsCharacteristics.id} {charEx}");
            }

            var suggestionsForOpCharacteristics = deprecatedOpCharacteristics.SelectMany(d =>
            {
                // TODO: TryGetQsSymbolInfo currently only returns information about the inner most leafs rather than all types etc.
                // Once it returns indeed all types in the fragment, the following code block should be replaced by the commented out code below.
                var fragment = file.TryGetFragmentAt(d.Range.Start, out var _);
                IEnumerable <Characteristics> GetCharacteristics(QsTuple <Tuple <QsSymbol, QsType> > argTuple) =>
                SyntaxGenerator.ExtractItems(argTuple).SelectMany(item => item.Item2.ExtractCharacteristics()).Distinct();
                var characteristicsInFragment =
                    fragment?.Kind is QsFragmentKind.FunctionDeclaration function ? GetCharacteristics(function.Item2.Argument) :
                    fragment?.Kind is QsFragmentKind.OperationDeclaration operation ? GetCharacteristics(operation.Item2.Argument) :
                    fragment?.Kind is QsFragmentKind.TypeDefinition type ? GetCharacteristics(type.Item2) :
                    Enumerable.Empty <Characteristics>();

                //var symbolInfo = file.TryGetQsSymbolInfo(d.Range.Start, false, out var fragment);
                //var characteristicsInFragment = (symbolInfo?.UsedTypes ?? Enumerable.Empty<QsType>())
                //    .SelectMany(t => t.ExtractCharacteristics()).Distinct();
                var fragmentStart = fragment?.GetRange()?.Start;
                return(characteristicsInFragment
                       .Where(c => c.Range.IsValue && DiagnosticTools.GetAbsoluteRange(fragmentStart, c.Range.Item).Overlaps(d.Range))
                       .Select(c => ReplaceWith(CharacteristicsAnnotation(c), d.Range)));
            });

            return(suggestionsForOpCharacteristics.ToArray()
                   .Concat(suggestionsForUnitType)
                   .Concat(suggestionsForNOT)
                   .Concat(suggestionsForAND)
                   .Concat(suggestionsForOR));
        }