/// <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()); }
/// <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()); }
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)); }
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()); }
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 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); }
/// <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 ); }
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); }
internal static IAttributeBuilder <QsCustomType> AttributeBuilder( this QsCustomType type) => new Udt(type);
internal static string ToSyntax(this QsCustomType type) => SyntaxTreeToQsharp.Default.ToCode(type);
/// <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; }