Пример #1
0
        /// <summary>
        /// Generates a syntax string for a user-defined type.
        /// This is more or less the same as the Q# type definition.
        /// </summary>
        /// <param name="customType">The UDT to create a syntax string for</param>
        /// <returns>The syntax string</returns>
        internal static string CustomTypeToSyntax(QsCustomType customType)
        {
            var sb = new StringBuilder();

            sb.Append("newtype ");
            sb.Append(customType.FullName.Name.Value);
            sb.Append(" = ");
            sb.Append(ResolvedTypeToString(customType.Type));
            sb.Append(";");
            return(sb.ToString());
        }
Пример #2
0
        /// <summary>
        /// Generates a syntax string for a user-defined type.
        /// This is more or less the same as the Q# type definition.
        /// </summary>
        /// <param name="customType">The UDT to create a syntax string for</param>
        /// <returns>The syntax string</returns>
        internal static string CustomTypeToSyntax(QsCustomType customType)
        {
            // TODO: Include modifiers.
            var sb = new StringBuilder();

            sb.Append("newtype ");
            sb.Append(customType.FullName.Name);
            sb.Append(" = ");
            sb.Append(ResolvedTypeToString(customType.Type));
            sb.Append(";");
            return(sb.ToString());
        }
Пример #3
0
 public override QsCustomType onType(QsCustomType t)
 {
     if (!this.IsRelevant(t.SourceFile) || t.Location.IsNull)
     {
         return(t);
     }
     if (t.FullName.Equals(this.IdentifierName))
     {
         this.DeclarationLocation = new Tuple <NonNullable <string>, QsLocation>(t.SourceFile, t.Location.Item);
     }
     return(base.onType(t));
 }
Пример #4
0
            public override QsCustomType OnTypeDeclaration(QsCustomType type)
            {
                type = base.OnTypeDeclaration(type);
                // If the UDT didn't come from a Q# source file, then it
                // came in from a reference, and shouldn't be documented in this
                // project.
                if (!type.IsInCompilationUnit())
                {
                    return(type);
                }

                var isDeprecated = type.IsDeprecated(out var replacement);
                var docComment   = new DocComment(
                    type.Documentation, type.FullName.Name,
                    deprecated: isDeprecated,
                    replacement: replacement
                    );

                // Validate named item names.
                var inputDeclarations = type.TypeItems.ToDictionaryOfDeclarations();

                this.ValidateNames(
                    $"{type.FullName.Namespace}.{type.FullName.Name}",
                    "named item",
                    name => inputDeclarations.ContainsKey(name),
                    docComment.Input.Keys,
                    range: null, // TODO: provide more exact locations once supported by DocParser.
                    source: type.SourceFile
                    );

                this.writer?.WriteOutput(type, docComment)?.Wait();

                return(type
                       .AttributeBuilder()
                       .MaybeWithSimpleDocumentationAttribute("Summary", docComment.Summary)
                       .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description)
                       .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks)
                       .MaybeWithSimpleDocumentationAttribute("References", docComment.References)
                       .WithListOfDocumentationAttributes("SeeAlso", docComment.SeeAlso)
                       .WithListOfDocumentationAttributes("Example", docComment.Examples)
                       .WithDocumentationAttributesFromDictionary("NamedItem", docComment.NamedItems)
                       .Build());
            }
Пример #5
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);
        }
Пример #6
0
        public void ParseUdt()
        {
            string[] comments =
            {
                "# Summary",
                "Represents a single primitive term in the set of all dynamical generators, e.g.",
                "Hermitian operators, for which there exists a map from that generator",
                "to time-evolution by that that generator, through \"EvolutionSet\".",
                "",
                "# Description",
                "The first element",
                "(Int[], Double[]) is indexes that single term -- For instance, the Pauli string",
                "XXY with coefficient 0.5 would be indexed by ([1,1,2], [0.5]). Alternatively,",
                "Hamiltonians parameterized by a continuous variable, such as X cos φ + Y sin φ,",
                "might for instance be represented by ([], [φ]). The second",
                "element indexes the subsystem on which the generator acts on.",
                "",
                "# Remarks",
                "> [!WARNING]",
                "> The interpretation of an `GeneratorIndex` is not defined except",
                "> with reference to a particular set of generators.",
                "",
                "# Example",
                "Using  <xref:microsoft.quantum.canon.paulievolutionset>, the operator",
                "$\\pi X_2 X_5 Y_9$ is represented as:",
                "```qsharp",
                "let index = GeneratorIndex(([1; 1; 2], [PI()]), [2; 5; 9]);",
                "```",
                "",
                "# See Also",
                "- @\"microsoft.quantum.canon.paulievolutionset\"",
                "- @\"microsoft.quantum.canon.evolutionset\""
            };
            string expected = @"### YamlMime:QSharpType
uid: microsoft.quantum.canon.generatorindex
name: GeneratorIndex
type: newtype
namespace: Microsoft.Quantum.Canon
summary: |-
  Represents a single primitive term in the set of all dynamical generators, e.g.
  Hermitian operators, for which there exists a map from that generator
  to time-evolution by that that generator, through ""EvolutionSet"".

  The first element
  (Int[], Double[]) is indexes that single term -- For instance, the Pauli string
  XXY with coefficient 0.5 would be indexed by ([1,1,2], [0.5]). Alternatively,
  Hamiltonians parameterized by a continuous variable, such as X cos φ + Y sin φ,
  might for instance be represented by ([], [φ]). The second
  element indexes the subsystem on which the generator acts on.
remarks: |-
  > [!WARNING]
  > The interpretation of an `GeneratorIndex` is not defined except
  > with reference to a particular set of generators.

  ### Examples
  Using  <xref:microsoft.quantum.canon.paulievolutionset>, the operator
  $\pi X_2 X_5 Y_9$ is represented as:

  ```qsharp
  let index = GeneratorIndex(([1; 1; 2], [PI()]), [2; 5; 9]);
  ```
syntax: newtype GeneratorIndex = ((Int[], Double[]), Int[]);
seeAlso:
- microsoft.quantum.canon.paulievolutionset
- microsoft.quantum.canon.evolutionset
...
";
            var    intArrayType = ResolvedType.New(QsType.NewArrayType(ResolvedType.New(QsType.Int)));
            var    doubleArrayType = ResolvedType.New(QsType.NewArrayType(ResolvedType.New(QsType.Double)));
            var    innerTuple = new ResolvedType[] { intArrayType, doubleArrayType }.ToImmutableArray();
            var    innerTupleType = ResolvedType.New(QsType.NewTupleType(innerTuple));
            var    baseTuple = new ResolvedType[] { innerTupleType, intArrayType }.ToImmutableArray();
            var    baseType      = ResolvedType.New(QsType.NewTupleType(baseTuple));
            var    anonymousItem = QsTuple <QsTypeItem> .NewQsTupleItem(QsTypeItem.NewAnonymous(baseType));

            var typeItems = QsTuple <QsTypeItem> .NewQsTuple(ImmutableArray.Create(anonymousItem));

            var generatorIndexType = new QsCustomType(MakeFullName("GeneratorIndex"),
                                                      ImmutableArray <QsDeclarationAttribute> .Empty,
                                                      NonNullable <string> .New("GeneratorRepresentation.qs"),
                                                      ZeroLocation,
                                                      baseType,
                                                      typeItems,
                                                      comments.ToImmutableArray(),
                                                      QsComments.Empty);
            var udt = new DocUdt("Microsoft.Quantum.Canon", generatorIndexType);

            var stream = new StringWriter();

            udt.WriteToFile(stream);
            var s = stream.ToString();

            Assert.Equal(expected, s);
        }
Пример #7
0
 /// <summary>
 /// Constructs an instance from the name of the namespace this UDT is defined in
 /// and the compiled UDT itself.
 /// </summary>
 /// <param name="ns">The name of the defining namespace</param>
 /// <param name="udt">The compiled UDT</param>
 internal DocUdt(string ns, QsCustomType udt)
     : base(ns, udt.FullName.Name, Utils.UdtKind, udt.Documentation, udt.Attributes)
 {
     this.syntax     = Utils.CustomTypeToSyntax(udt);
     this.customType = udt;
 }
 public override QsCustomType OnTypeDeclaration(QsCustomType t) => t;
        /// <summary>
        ///     Given a documentation comment describing a Q# user-defined type
        ///     declaration, writes a Markdown file documenting that UDT
        ///     declaration to <see cref="OutputPath" />.
        /// </summary>
        /// <param name="type">The Q# UDT being documented.</param>
        /// <param name="docComment">
        ///     The API documentation comment describing <paramref name="type"/>.
        /// </param>
        /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
        public async Task WriteOutput(QsCustomType type, DocComment docComment)
        {
            var namedItemDeclarations = type.TypeItems.ToDictionaryOfDeclarations();

            // Make a new Markdown document for the type declaration.
            var title  = $"{type.FullName.Name} user defined type";
            var header = new Dictionary <string, object>
            {
                // DocFX metadata
                ["uid"]   = type.FullName.ToString(),
                ["title"] = title,

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

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

Namespace: [{type.FullName.Namespace}](xref:{type.FullName.Namespace})
{this.packageLink}

{docComment.Summary}

```{this.LanguageMode}
{type.WithoutDocumentationAndComments().ToSyntax()}
```

"
                           .MaybeWithSection(
                "Named Items",
                string.Join("\n", type.TypeItems.TypeDeclarations().Select(
                                item =>
            {
                (var itemName, var resolvedType) = item;
                var documentation =
                    docComment.NamedItems.TryGetValue(itemName, out var comment)
                            ? comment
                            : string.Empty;
                return($"### {itemName} : {resolvedType.ToMarkdownLink()}\n\n{documentation}");
            }
                                ))
                )
                           .MaybeWithSection("Description", docComment.Description)
                           .MaybeWithSection("Remarks", docComment.Remarks)
                           .MaybeWithSection("References", docComment.References)
                           .MaybeWithSection(
                "See Also",
                string.Join("\n", docComment.SeeAlso.Select(
                                seeAlso => AsSeeAlsoLink(seeAlso, type.FullName.Namespace)
                                ))
                )
                           .WithYamlHeader(header);

            // Open a file to write the new doc to.
            await this.WriteAllTextAsync(
                $"{type.FullName.Namespace}.{type.FullName.Name}.md",
                document
                );
        }
Пример #10
0
        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);
        }
Пример #11
0
 internal static IAttributeBuilder <QsCustomType> AttributeBuilder(
     this QsCustomType type) =>
 new Udt(type);
Пример #12
0
 internal static string ToSyntax(this QsCustomType type) =>
 SyntaxTreeToQsharp.Default.ToCode(type);
Пример #13
0
 /// <summary>
 /// Constructs an instance from the name of the namespace this UDT is defined in
 /// and the compiled UDT itself.
 /// </summary>
 /// <param name="ns">The name of the defining namespace</param>
 /// <param name="udt">The compiled UDT</param>
 internal DocUdt(string ns, QsCustomType udt)
     : base(ns, udt.FullName.Name.Value, Utils.UdtKind, udt.Documentation)
 {
     syntax     = Utils.CustomTypeToSyntax(udt);
     customType = udt;
 }