Beispiel #1
0
        /// <summary>
        /// Get the first declared function of this undecorated name.
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="nameSpace"></param>
        /// <param name="functionName"></param>
        /// <returns></returns>
        public static QsFunction GetFirstDeclaredFunction(
            QsScope scope,
            string nameSpace,
            string functionName)
        {
            IEnumerable <KeyValuePair <string, object> > Items = null;

            if (!string.IsNullOrEmpty(nameSpace))
            {
                var ns = QsNamespace.GetNamespace(scope, nameSpace);
                Items = ns.GetItems();
            }
            else
            {
                Items = scope.GetItems();
            }

            var func_Pass1 = from item in Items
                             where item.Value is QsFunction
                             select(QsFunction) item.Value;

            var qf = from fun in func_Pass1
                     where fun.FunctionName.Equals(functionName, StringComparison.OrdinalIgnoreCase)
                     select fun;


            return(qf.ElementAtOrDefault(0));
        }
Beispiel #2
0
            public override QsCallable OnFunction(QsCallable c) => c; // Prevent anything in functions from being lifted

            /// <inheritdoc/>
            public override QsNamespace OnNamespace(QsNamespace ns)
            {
                // Generated operations list will be populated in the transform
                this.SharedState.GeneratedOperations = new List <QsCallable>();
                return(base.OnNamespace(ns)
                       .WithElements(elems => elems.AddRange(this.SharedState.GeneratedOperations.Select(op => QsNamespaceElement.NewQsCallable(op)))));
            }
 /// <summary>
 /// Returns a copy of the accepting namespace that includes all the elements from the overriding namespace.
 /// If there are elements found in both namespaces, the resulting ns takes the overriding ns's version of the elements
 /// The resulting namespace takes the overriding namespace's version of the elements found in both input namespaces.
 /// Custom type elements are treated separately from callable elements.
 /// </summary>
 private static QsNamespace MergeNamespaces(QsNamespace overriding, QsNamespace accepting)
 {
     return(accepting.WithElements(_ =>
                                   MergeElements(overriding.Elements.Where(x => x.IsQsCallable), accepting.Elements.Where(x => x.IsQsCallable))
                                   .Concat(MergeElements(overriding.Elements.Where(x => x.IsQsCustomType), accepting.Elements.Where(x => x.IsQsCustomType)))
                                   .ToImmutableArray()));
 }
Beispiel #4
0
        public bool PreconditionVerification(QsCompilation compilation)
        {
            var controlNs = compilation.Namespaces
                            .FirstOrDefault(ns => ns.Name.Equals(BuiltIn.ClassicallyControlledNamespace));

            if (controlNs == null)
            {
                return(false);
            }

            var providedOperations = new QsNamespace[] { controlNs }
            .Callables()
            .Select(c => c.FullName)
            .ToHashSet();
            var requiredBuiltIns = new HashSet <QsQualifiedName>()
            {
                BuiltIn.ApplyIfZero.FullName,
                BuiltIn.ApplyIfZeroA.FullName,
                BuiltIn.ApplyIfZeroC.FullName,
                BuiltIn.ApplyIfZeroCA.FullName,

                BuiltIn.ApplyIfOne.FullName,
                BuiltIn.ApplyIfOneA.FullName,
                BuiltIn.ApplyIfOneC.FullName,
                BuiltIn.ApplyIfOneCA.FullName,

                BuiltIn.ApplyIfElseR.FullName,
                BuiltIn.ApplyIfElseRA.FullName,
                BuiltIn.ApplyIfElseRC.FullName,
                BuiltIn.ApplyIfElseRCA.FullName
            };

            return(requiredBuiltIns.IsSubsetOf(providedOperations));
        }
Beispiel #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="nameSpace"></param>
        /// <param name="parametersCount">filter functions by number of parameters</param>
        /// <param name="parametersNames"></param>
        /// <returns></returns>
        public static QsFunction[] FindFunctionByParameters(
            QsScope scope,
            string qsNamespace,
            string functionName,
            int parametersCount,
            params string[] parametersNames)
        {
            IEnumerable <KeyValuePair <string, object> > Items = null;

            if (!string.IsNullOrEmpty(qsNamespace))
            {
                var ns = QsNamespace.GetNamespace(scope, qsNamespace);
                Items = ns.GetItems();
            }
            else
            {
                Items = scope.GetItems();
            }

            var func_Pass1 = from item in Items
                             where item.Value is QsFunction
                             select(QsFunction) item.Value;

            var func_Pass2 = from func in func_Pass1
                             where func.ContainsParameters(parametersNames) && func.Parameters.Length == parametersCount
                             select func;

            var func_Pass3 = from fc in func_Pass2
                             where fc.FunctionName.Equals(functionName, StringComparison.OrdinalIgnoreCase)
                             select fc;


            return(func_Pass3.ToArray());
        }
        public bool PreconditionVerification(QsCompilation compilation)
        {
            var controlNs = compilation.Namespaces
                            .FirstOrDefault(ns => ns.Name.Equals(BuiltIn.ClassicallyControlledNamespace));

            if (controlNs == null)
            {
                return(false);
            }

            var providedOperations = new QsNamespace[] { controlNs }.Callables().Select(c => c.FullName.Name);
            var requiredBuiltIns = new List <NonNullable <string> >()
            {
                BuiltIn.ApplyIfZero.Name,
                BuiltIn.ApplyIfZeroA.Name,
                BuiltIn.ApplyIfZeroC.Name,
                BuiltIn.ApplyIfZeroCA.Name,

                BuiltIn.ApplyIfOne.Name,
                BuiltIn.ApplyIfOneA.Name,
                BuiltIn.ApplyIfOneC.Name,
                BuiltIn.ApplyIfOneCA.Name,

                BuiltIn.ApplyIfElseR.Name,
                BuiltIn.ApplyIfElseRA.Name,
                BuiltIn.ApplyIfElseRC.Name,
                BuiltIn.ApplyIfElseRCA.Name
            };

            return(requiredBuiltIns.All(builtIn => providedOperations.Any(provided => provided.Equals(builtIn))));
        }
Beispiel #7
0
        // static methods for convenience

        public static IEnumerable <Location> Find(QsQualifiedName idName, QsNamespace ns, QsLocation defaultOffset,
                                                  out Tuple <NonNullable <string>, QsLocation> declarationLocation, IImmutableSet <NonNullable <string> > limitToSourceFiles = null)
        {
            var finder = new IdentifierReferences(idName, defaultOffset, limitToSourceFiles);

            finder.Transform(ns ?? throw new ArgumentNullException(nameof(ns)));
            declarationLocation = finder.DeclarationLocation;
            return(finder.Locations);
        }
Beispiel #8
0
 public override QsNamespace OnNamespace(QsNamespace ns)
 {
     // Removes unused or generic callables from the namespace
     // Adds in the used concrete callables
     return(ns.WithElements(elems => elems
                            .Where(this.NamespaceElementFilter)
                            .Concat(this.SharedState.NamespaceCallables[ns.Name].Select(QsNamespaceElement.NewQsCallable))
                            .ToImmutableArray()));
 }
        /// <summary>
        /// Constructs an instance from a compiled namespace and list of source files.
        /// </summary>
        /// <param name="ns">The namespace to be represented</param>
        /// <param name="sourceFiles">If specified, only the items in the specified source files are included.</param>
        internal DocNamespace(QsNamespace ns, IEnumerable <string> sourceFiles = null)
        {
            var sourceFileSet = sourceFiles == null ? null : new HashSet <string>(sourceFiles);

            bool IsVisible(NonNullable <string> qualifiedName, NonNullable <string> source)
            {
                var name          = qualifiedName.Value;
                var includeInDocs = sourceFileSet == null || sourceFileSet.Contains(source.Value);

                return(includeInDocs && !(name.StartsWith("_") || name.EndsWith("_") ||
                                          name.EndsWith("Impl", StringComparison.InvariantCultureIgnoreCase) ||
                                          name.EndsWith("ImplA", StringComparison.InvariantCultureIgnoreCase) ||
                                          name.EndsWith("ImplC", StringComparison.InvariantCultureIgnoreCase) ||
                                          name.EndsWith("ImplCA", StringComparison.InvariantCultureIgnoreCase)));
            }

            this.name = ns.Name.Value;
            uid       = this.name.ToLowerInvariant();

            this.summary = "";
            foreach (var commentGroup in ns.Documentation)
            {
                foreach (var comment in commentGroup)
                {
                    if (!comment.IsDefaultOrEmpty)
                    {
                        this.summary = String.Join(Environment.NewLine, comment);
                    }
                }
            }

            foreach (var item in ns.Elements)
            {
                if (item is QsNamespaceElement.QsCallable c)
                {
                    var callable = c.Item;
                    if (IsVisible(callable.FullName.Name, callable.SourceFile) &&
                        (callable.Kind != QsCallableKind.TypeConstructor))
                    {
                        items.Add(new DocCallable(name, callable));
                    }
                }
                else if (item is QsNamespaceElement.QsCustomType u)
                {
                    var udt = u.Item;
                    if (IsVisible(udt.FullName.Name, udt.SourceFile))
                    {
                        items.Add(new DocUdt(name, udt));
                    }
                }
                // ignore anything else
            }

            // Sometimes we need the items in alphabetical order by UID, so let's do that here
            items.Sort((x, y) => x.Uid.CompareTo(y.Uid));
        }
Beispiel #10
0
                public override QsNamespace OnNamespace(QsNamespace ns)
                {
                    SharedState.NamespaceCallables.TryGetValue(ns.Name, out IEnumerable <QsCallable> concretesInNs);

                    // Removes unused or generic callables from the namespace
                    // Adds in the used concrete callables
                    return(ns.WithElements(elems => elems
                                           .Where(elem => !(elem is QsNamespaceElement.QsCallable))
                                           .Concat(concretesInNs?.Select(call => QsNamespaceElement.NewQsCallable(call)) ?? Enumerable.Empty <QsNamespaceElement>())
                                           .ToImmutableArray()));
                }
 public override QsNamespace OnNamespace(QsNamespace ns)
 {
     ns = base.OnNamespace(ns);
     if (ns.Elements.Any(element => element.IsInCompilationUnit()))
     {
         // Concatenate everything into one documentation comment.
         var comment = new DocComment(
             ns.Documentation.SelectMany(group => group).SelectMany(comments => comments));
         if (ns.Elements.Any(element => element switch
         {
             QsNamespaceElement.QsCallable {
                 Item: var callable
             } => callable.Access.IsPublic,
Beispiel #12
0
            public override QsNamespace OnNamespace(QsNamespace ns)
            {
                ns = base.OnNamespace(ns);
                if (ns.Elements.Any(element => element.IsInCompilationUnit()))
                {
                    // Concatenate everything into one documentation comment.
                    var comment = new DocComment(
                        ns.Documentation.SelectMany(group => group).SelectMany(comments => comments)
                        );
                    writer?.WriteOutput(ns, comment)?.Wait();
                }

                return(ns);
            }
        private bool CheckForRequired(QsCompilation compilation, string namespaceName, ImmutableHashSet <QsQualifiedName> requiredBuiltIns)
        {
            var builtInNs = compilation.Namespaces
                            .FirstOrDefault(ns => ns.Name.Equals(namespaceName));

            if (builtInNs == null)
            {
                return(false);
            }

            var providedOperations = new QsNamespace[] { builtInNs }
            .Callables()
            .Select(c => c.FullName)
            .ToImmutableHashSet();

            return(requiredBuiltIns.IsSubsetOf(providedOperations));
        }
        /// <summary>
        ///     Given a documentation comment describing a Q# namespace,
        ///     writes a Markdown file documenting that namespace to
        ///     <see cref="OutputPath" />.
        /// </summary>
        /// <param name="ns">The Q# namespace being documented.</param>
        /// <param name="docComment">
        ///     The API documentation comment describing <paramref name="ns" />.
        /// </param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        public async Task WriteOutput(QsNamespace ns, DocComment docComment)
        {
            var name   = ns.Name;
            var uid    = name;
            var title  = $"{name} namespace";
            var header = new Dictionary <string, object>
            {
                // DocFX metadata
                ["uid"]   = name,
                ["title"] = title,

                // docs.ms metadata
                ["ms.date"]  = DateTime.Today.ToString(),
                ["ms.topic"] = "managed-reference",

                // Q# metadata
                ["qsharp.kind"]    = "namespace",
                ["qsharp.name"]    = name,
                ["qsharp.summary"] = docComment.Summary,
            };
            var document = $@"
# {title}

{docComment.Summary}

"
                           .MaybeWithSection("Description", docComment.Description)
                           .WithSectionForEach("Example", docComment.Examples)
                           .MaybeWithSection(
                "See Also",
                string.Join("\n", docComment.SeeAlso.Select(
                                seeAlso => AsSeeAlsoLink(seeAlso)
                                ))
                )
                           .WithYamlHeader(header);

            // Open a file to write the new doc to.
            await this.WriteAllTextAsync(
                $"{name}.md", document
                );
        }
Beispiel #15
0
        public bool PreconditionVerification(QsCompilation compilation)
        {
            var requiredNamespace = compilation.Namespaces
                                    .FirstOrDefault(ns => ns.Name.Equals(BuiltIn.CoreNamespace));

            if (requiredNamespace == null)
            {
                return(false);
            }

            var providedOperations = new QsNamespace[] { requiredNamespace }
            .Callables()
            .Select(c => c.FullName)
            .ToHashSet();
            var requiredBuiltIns = new HashSet <QsQualifiedName>()
            {
                BuiltIn.Length.FullName,
                BuiltIn.RangeReverse.FullName
            };

            return(requiredBuiltIns.IsSubsetOf(providedOperations));
        }
        /// <summary>
        /// Get the function that is stored in the scope.
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="realName"></param>
        /// <returns></returns>
        public static QsFunction GetFunction(QsScope scope, string qsNamespace, string functionName)
        {
            if (string.IsNullOrEmpty(qsNamespace))
            {
                // no namespace included then it is from the local scope.


                // I am adding the mathmatical functions in the root namespace
                // so I will test for the function namespace and

                QsFunction function = (QsFunction)MathNamespace.GetValueOrNull(functionName);

                // built int math functions will be overwrite any other functions
                if (function != null)
                {
                    return(function);
                }
                else
                {
                    function = (QsFunction)QsEvaluator.GetScopeValueOrNull(scope, qsNamespace, functionName);
                }

                return(function);
            }
            else
            {
                try
                {
                    QsNamespace ns = QsNamespace.GetNamespace(scope, qsNamespace);


                    return((QsFunction)ns.GetValue(functionName));
                }
                catch (QsVariableNotFoundException)
                {
                    return(null);
                }
            }
        }
    /// <summary>
    /// List Command
    /// </summary>
    internal static void ListVariables()
    {
        Console.WriteLine();
        Console.ForegroundColor = ValuesColor;

        foreach (string var in GetVariablesKeys())
        {
            var v = GetVariable(var);
            Console.WriteLine("    " + var + " = " + v.ToString());
            if (v is QsNamespace)
            {
                QsNamespace ns = (QsNamespace)v;
                foreach (string nsvar in ns.GetVariablesKeys())
                {
                    Console.WriteLine("        " + nsvar + " = " + ns.GetValue(nsvar).ToString());
                }
            }
            Console.WriteLine();
        }

        Console.ForegroundColor = ForegroundColor;
        Console.WriteLine();
    }
Beispiel #18
0
        public void ExcludeInaccessible()
        {
            var elements = new[] { Access.Public, Access.Internal }
            .SelectMany(access =>
            {
                var source = new Source("Tests.qs", QsNullable <string> .Null);
                var unit   = ResolvedType.New(QsType.UnitType);

                var signature = new ResolvedSignature(
                    Array.Empty <QsLocalSymbol>().ToImmutableArray(),
                    unit,
                    unit,
                    CallableInformation.NoInformation);
                var argumentTuple = QsTuple <ArgDeclType> .NewQsTuple(ImmutableArray.Create <QsTuple <ArgDeclType> >());
                var callable      = new QsCallable(
                    kind: QsCallableKind.Operation,
                    fullName: MakeFullName(access + "Operation"),
                    attributes: ImmutableArray <QsDeclarationAttribute> .Empty,
                    access,
                    source: source,
                    location: ZeroLocation,
                    signature: signature,
                    argumentTuple: argumentTuple,
                    specializations: ImmutableArray.Create <QsSpecialization>(),
                    documentation: ImmutableArray.Create <string>(),
                    comments: QsComments.Empty);

                var typeItems = QsTuple <QsTypeItem> .NewQsTuple(
                    ImmutableArray.Create(QsTuple <QsTypeItem> .NewQsTupleItem(QsTypeItem.NewAnonymous(unit))));
                var type = new QsCustomType(
                    fullName: MakeFullName(access + "Type"),
                    attributes: ImmutableArray <QsDeclarationAttribute> .Empty,
                    access,
                    source: source,
                    location: ZeroLocation,
                    type: unit,
                    typeItems: typeItems,
                    documentation: ImmutableArray.Create <string>(),
                    comments: QsComments.Empty);
                return(new[]
                {
                    QsNamespaceElement.NewQsCallable(callable),
                    QsNamespaceElement.NewQsCustomType(type)
                });
            });
            var emptyLookup = Array.Empty <ImmutableArray <string> >().ToLookup(x => "");
            var ns          = new QsNamespace(CanonName, elements.ToImmutableArray(), emptyLookup);
            var docNs       = new DocNamespace(ns);
            var stream      = new MemoryStream();

#pragma warning disable 618 // WriteToStream is obsolete.
            docNs.WriteToStream(stream, null);
#pragma warning restore 618

            var expected = @"### YamlMime:QSharpNamespace
# This file is automatically generated.
# Please do not modify this file manually, or your changes may be lost when
# documentation is rebuilt.

uid: microsoft.quantum.canon
name: Microsoft.Quantum.Canon
operations:
- uid: microsoft.quantum.canon.publicoperation
  summary: ''
newtypes:
- uid: microsoft.quantum.canon.publictype
  summary: ''
...
";
            var actual   = Encoding.UTF8.GetString(stream.ToArray());
            Assert.Equal(expected, actual);
        }
        public void ExcludeInaccessible()
        {
            var elements =
                new[] { AccessModifier.DefaultAccess, AccessModifier.Internal }
            .SelectMany(access =>
            {
                var source = NonNullable <string> .New("Tests.qs");
                var unit   = ResolvedType.New(QsType.UnitType);

                var signature = new ResolvedSignature(Array.Empty <QsLocalSymbol>().ToImmutableArray(),
                                                      unit,
                                                      unit,
                                                      CallableInformation.NoInformation);
                var argumentTuple = QsTuple <ArgDeclType> .NewQsTuple(ImmutableArray.Create <QsTuple <ArgDeclType> >());
                var callable      = new QsCallable(kind: QsCallableKind.Operation,
                                                   fullName: MakeFullName(access + "Operation"),
                                                   attributes: ImmutableArray <QsDeclarationAttribute> .Empty,
                                                   modifiers: new Modifiers(access),
                                                   sourceFile: source,
                                                   location: ZeroLocation,
                                                   signature: signature,
                                                   argumentTuple: argumentTuple,
                                                   specializations: ImmutableArray.Create <QsSpecialization>(),
                                                   documentation: ImmutableArray.Create <string>(),
                                                   comments: QsComments.Empty);

                var typeItems = QsTuple <QsTypeItem> .NewQsTuple(
                    ImmutableArray.Create(QsTuple <QsTypeItem> .NewQsTupleItem(QsTypeItem.NewAnonymous(unit))));
                var type = new QsCustomType(fullName: MakeFullName(access + "Type"),
                                            attributes: ImmutableArray <QsDeclarationAttribute> .Empty,
                                            modifiers: new Modifiers(access),
                                            sourceFile: source,
                                            location: ZeroLocation,
                                            type: unit,
                                            typeItems: typeItems,
                                            documentation: ImmutableArray.Create <string>(),
                                            comments: QsComments.Empty);
                return(new[]
                {
                    QsNamespaceElement.NewQsCallable(callable),
                    QsNamespaceElement.NewQsCustomType(type)
                });
            });
            var emptyLookup = Array.Empty <ImmutableArray <string> >().ToLookup(x => NonNullable <string> .New(""));
            var ns          = new QsNamespace(CanonName, elements.ToImmutableArray(), emptyLookup);
            var docNs       = new DocNamespace(ns);
            var stream      = new MemoryStream();

            docNs.WriteToStream(stream, null);

            var expected = @"### YamlMime:QSharpNamespace
uid: microsoft.quantum.canon
name: Microsoft.Quantum.Canon
operations:
- uid: microsoft.quantum.canon.defaultaccessoperation
  summary: ''
newtypes:
- uid: microsoft.quantum.canon.defaultaccesstype
  summary: ''
...
";
            var actual   = Encoding.UTF8.GetString(stream.ToArray());

            Assert.Equal(expected, actual);
        }
        /// <summary>
        /// Replaces self adjoint generation directives in non-intrinsic callables with a provided implementation
        /// that calls the appropriate specialization of the callable.
        /// Intrinsic callables are left unchanged.
        /// </summary>
        private static QsNamespace ReplaceSelfAdjointSpecializations(QsNamespace ns)
        {
            var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>();

            foreach (var element in ns.Elements)
            {
                if (element is QsNamespaceElement.QsCallable c)
                {
                    if (c.Item.IsSelfAdjoint && !c.Item.IsIntrinsic)
                    {
                        var callableId = IdentifierForCallable(
                            c.Item.FullName,
                            OperationTypeFromSignature(c.Item.Signature));

                        var callable = c.Item.WithSpecializations(specs =>
                                                                  ImmutableArray.CreateRange(specs.Select(spec =>
                        {
                            if (spec.Kind.IsQsBody || spec.Kind.IsQsControlled)
                            {
                                return(spec);
                            }
                            else
                            {
                                var argTuple = BuildSpecArgTuple(c.Item.ArgumentTuple, spec.Kind);
                                var callee   = spec.Kind.IsQsControlledAdjoint
                                        ? SyntaxGenerator.AutoGeneratedExpression(
                                    ExpressionKind.NewControlledApplication(callableId),
                                    OperationTypeFromSignature(spec.Signature),
                                    false)
                                        : callableId;

                                var call = SyntaxGenerator.CallNonGeneric(
                                    callee,
                                    SyntaxGenerator.ArgumentTupleAsExpression(argTuple));
                                var statement = new QsStatement(
                                    QsStatementKind.NewQsReturnStatement(call),
                                    LocalDeclarations.Empty,
                                    QsNullable <QsLocation> .Null,
                                    QsComments.Empty);
                                var localDeclarations = new LocalDeclarations(
                                    SyntaxGenerator.ValidDeclarations(SyntaxGenerator.ExtractItems(argTuple)));

                                return(spec.WithImplementation(SpecializationImplementation.NewProvided(
                                                                   argTuple,
                                                                   new QsScope(ImmutableArray.Create(statement), localDeclarations))));
                            }
                        })));
                        elements.Add(QsNamespaceElement.NewQsCallable(callable));
                    }
                    else
                    {
                        elements.Add(element);
                    }
                }
                else
                {
                    elements.Add(element);
                }
            }
            return(new QsNamespace(ns.Name, elements.ToImmutable(), ns.Documentation));
        }
        /// <summary>
        /// Creates a separate callable for each intrinsic specialization,
        /// and replaces the specialization implementations of the original callable with a call to these.
        /// Self adjoint generation directives in intrinsic callables are replaced by a provided implementation.
        /// Type constructors and generic callables or callables that already define a target instruction name are left unchanged.
        /// </summary>
        /// <exception cref="ArgumentException">
        /// An intrinsic callable contains non-intrinsic specializations
        /// or a non-intrinsic callable contains intrinsic specializations,
        /// or the a callable doesn't have a body specialization.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// A specialization has explicit type arguments;
        /// Monomorphization needs to run before separating target instructions.
        /// </exception>
        private static QsNamespace LiftIntrinsicSpecializations(QsNamespace ns)
        {
            var elements = ImmutableArray.CreateBuilder <QsNamespaceElement>();

            foreach (var element in ns.Elements)
            {
                if (element is QsNamespaceElement.QsCallable c &&
                    c.Item.Signature.TypeParameters.Length == 0 &&
                    !c.Item.Kind.IsTypeConstructor)
                {
                    if (c.Item.IsIntrinsic)
                    {
                        QsCallable callable = c.Item;
                        if (!callable.Specializations.Any(spec => spec.Kind.IsQsBody))
                        {
                            throw new ArgumentException("missing body specialization");
                        }
                        else if (callable.Specializations.Any(spec => spec.TypeArguments.IsValue))
                        {
                            throw new InvalidOperationException("specialization with type arguments");
                        }
                        else if (callable.Specializations.Length == 1 && callable.Attributes.Any(BuiltIn.DefinesTargetInstruction))
                        {
                            elements.Add(element);
                        }
                        else
                        {
                            QsQualifiedName GeneratedName(QsSpecializationKind kind) =>
                            new QsQualifiedName(callable.FullName.Namespace, $"{callable.FullName.Name}{SpecializationSuffix(kind)}");

                            var specializations = ImmutableArray.CreateRange(callable.Specializations.Select(spec =>
                            {
                                var inferredInfo = spec.Signature.Information.InferredInformation;
                                if (!inferredInfo.IsIntrinsic && !inferredInfo.IsSelfAdjoint)
                                {
                                    throw new ArgumentException("non-intrinsic specialization for intrinsic callable");
                                }

                                // Get the correct argument tuple both for the added intrinsic callable
                                // and the generated provided specialization that replaces the intrinsic one.
                                var argTuple = BuildSpecArgTuple(callable.ArgumentTuple, spec.Kind);

                                // Create a separate callable for that specialization,
                                // unless the specialization is not needed for a self-adjoint callable.

                                var genCallableSignature = new ResolvedSignature(
                                    ImmutableArray <QsLocalSymbol> .Empty,
                                    spec.Signature.ArgumentType,
                                    spec.Signature.ReturnType,
                                    new CallableInformation(
                                        ResolvedCharacteristics.Empty,
                                        new InferredCallableInformation(isIntrinsic: true, isSelfAdjoint: false)));
                                var genCallableName = GeneratedName(
                                    inferredInfo.IsSelfAdjoint && spec.Kind.IsQsAdjoint ? QsSpecializationKind.QsBody :
                                    inferredInfo.IsSelfAdjoint && spec.Kind.IsQsControlledAdjoint ? QsSpecializationKind.QsControlled :
                                    spec.Kind);

                                if (!inferredInfo.IsSelfAdjoint || spec.Kind.IsQsBody || spec.Kind.IsQsControlled)
                                {
                                    var genCallableBody = new QsSpecialization(
                                        QsSpecializationKind.QsBody,
                                        genCallableName,
                                        spec.Attributes,
                                        spec.Source,
                                        QsNullable <QsLocation> .Null,
                                        spec.TypeArguments,
                                        genCallableSignature,
                                        SpecializationImplementation.Intrinsic,
                                        spec.Documentation,
                                        spec.Comments);
                                    var genCallable = new QsCallable(
                                        callable.Kind,
                                        genCallableName,
                                        callable.Attributes,
                                        callable.Access,
                                        spec.Source,
                                        spec.Location,
                                        genCallableSignature,
                                        argTuple,
                                        ImmutableArray.Create(genCallableBody),
                                        ImmutableArray <string> .Empty,
                                        QsComments.Empty);
                                    elements.Add(QsNamespaceElement.NewQsCallable(genCallable));
                                }

                                // Create a specialization that calls into the generated callable,
                                // or the corresponding callable no callable for the specialization
                                // has been added due to hte operation being self-adjoint.

                                var genCallableType =
                                    callable.Kind == QsCallableKind.Operation
                                    ? OperationTypeFromSignature(genCallableSignature)
                                    : TypeKind.NewFunction(genCallableSignature.ArgumentType, genCallableSignature.ReturnType);
                                var call = SyntaxGenerator.CallNonGeneric(
                                    IdentifierForCallable(genCallableName, genCallableType),
                                    SyntaxGenerator.ArgumentTupleAsExpression(argTuple));
                                var statement = new QsStatement(
                                    QsStatementKind.NewQsReturnStatement(call),
                                    LocalDeclarations.Empty,
                                    QsNullable <QsLocation> .Null,
                                    QsComments.Empty);
                                var localDeclarations = new LocalDeclarations(
                                    SyntaxGenerator.ValidDeclarations(SyntaxGenerator.ExtractItems(argTuple)));

                                return(spec.WithImplementation(SpecializationImplementation.NewProvided(
                                                                   argTuple,
                                                                   new QsScope(ImmutableArray.Create(statement), localDeclarations))));
                            }));

                            // Create a callable that contains all specializations that
                            // call into the generated callables for each specialization.

                            var inlineAttribute = AttributeUtils.BuildAttribute(BuiltIn.Inline.FullName, SyntaxGenerator.UnitValue);
                            var signature       = new ResolvedSignature(
                                ImmutableArray <QsLocalSymbol> .Empty,
                                callable.Signature.ArgumentType,
                                callable.Signature.ReturnType,
                                new CallableInformation(
                                    callable.Signature.Information.Characteristics,
                                    new InferredCallableInformation(isSelfAdjoint: callable.IsSelfAdjoint, isIntrinsic: false)));
                            var redirect = new QsCallable(
                                callable.Kind,
                                callable.FullName,
                                ImmutableArray.Create(inlineAttribute),
                                callable.Access,
                                callable.Source,
                                callable.Location,
                                signature,
                                callable.ArgumentTuple,
                                specializations,
                                callable.Documentation,
                                callable.Comments);
                            elements.Add(QsNamespaceElement.NewQsCallable(redirect));
                        }
                    }
                    else if (c.Item.Specializations.Any(spec => spec.Implementation.IsIntrinsic))
                    {
                        throw new ArgumentException("intrinsic specialization for non-intrinsic callable");
                    }
                    else
                    {
                        elements.Add(element);
                    }
                }
Beispiel #22
0
 public override QsNamespace OnNamespace(QsNamespace ns)
 {
     return(ns.WithElements(elements => elements
                            .Where(this.SharedState.NamespaceElementFilter)
                            .ToImmutableArray()));
 }