public override NonNullable <string> OnSourceFile(NonNullable <string> f) { var dir = Path.GetDirectoryName(f.Value); var fileName = Path.GetFileNameWithoutExtension(f.Value); return(NonNullable <string> .New(Path.Combine(dir, fileName + ".qs"))); }
/// <summary> /// Returns the names of all namespaces that have been opened without an alias and are visible from the given /// position in the file. Returns an empty enumerator if the position is invalid. /// </summary> /// <exception cref="ArgumentNullException">Thrown when any argument is null.</exception> /// <exception cref="ArgumentException">Thrown when the position is invalid.</exception> private static IEnumerable <string> GetOpenNamespaces( FileContentManager file, CompilationUnit compilation, Position position) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (compilation == null) { throw new ArgumentNullException(nameof(compilation)); } if (!Utils.IsValidPosition(position)) { throw new ArgumentException(nameof(position)); } var @namespace = file.TryGetNamespaceAt(position); if (@namespace == null || !compilation.GlobalSymbols.NamespaceExists(NonNullable <string> .New(@namespace))) { return(Array.Empty <string>()); } return(compilation .GetOpenDirectives(NonNullable <string> .New(@namespace))[file.FileName] .Where(open => open.Item2 == null) // Only include open directives without an alias. .Select(open => open.Item1.Value) .Concat(new[] { @namespace })); }
static ArgDeclType BuildArgument(string name, ResolvedType t) { var validName = QsLocalSymbol.NewValidName(NonNullable <string> .New(name)); var info = new InferredExpressionInformation(false, false); return(new ArgDeclType(validName, t, info, QsNullable <Tuple <int, int> > .Null, EmptyRange)); }
/// <summary> /// Resolves the namespace alias and returns its full namespace name. If the alias couldn't be resolved, returns /// the alias unchanged. /// </summary> /// <exception cref="ArgumentNullException">Thrown when any argument is null.</exception> /// <exception cref="ArgumentException">Thrown when the position is invalid.</exception> private static string ResolveNamespaceAlias( FileContentManager file, CompilationUnit compilation, Position position, string alias) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (compilation == null) { throw new ArgumentNullException(nameof(compilation)); } if (!Utils.IsValidPosition(position)) { throw new ArgumentException(nameof(position)); } if (alias == null) { throw new ArgumentNullException(nameof(alias)); } var nsName = file.TryGetNamespaceAt(position); if (nsName == null || !compilation.GlobalSymbols.NamespaceExists(NonNullable <string> .New(nsName))) { return(alias); } return(compilation.GlobalSymbols.TryResolveNamespaceAlias( NonNullable <string> .New(alias), NonNullable <string> .New(nsName), file.FileName) ?? alias); }
/// <summary> /// Given the argument tuple of a specialization, returns the argument tuple for its controlled version. /// Returns null if the given argument tuple is null. /// </summary> private static QsTuple <LocalVariableDeclaration <QsLocalSymbol> > ControlledArg(QsTuple <LocalVariableDeclaration <QsLocalSymbol> > arg) => arg != null ? SyntaxGenerator.WithControlQubits(arg, QsNullable <Tuple <int, int> > .Null, QsLocalSymbol.NewValidName(NonNullable <string> .New(InternalUse.ControlQubitsName)), QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null) : null;
public override QsTypeKind onTypeParameter(QsTypeParameter tp) { this.CodeOutput.onTypeParameter(tp); var tpName = NonNullable <string> .New(this.CodeOutput.Output ?? ""); this.OnIdentifier?.Invoke(Identifier.NewLocalVariable(tpName), tp.Range); return(QsTypeKind.NewTypeParameter(tp)); }
/// <summary> /// Builds the corresponding .net core assembly from the code in the given files. /// </summary> public AssemblyInfo BuildFiles(string[] files, CompilerMetadata metadatas, QSharpLogger logger, string dllName) { var syntaxTree = BuildQsSyntaxTree(files, metadatas.QsMetadatas, logger); Uri FileUri(string f) => CompilationUnitManager.TryGetUri(NonNullable <string> .New(f), out var uri) ? uri : null; var assembly = BuildAssembly(files.Select(FileUri).ToArray(), syntaxTree, metadatas.RoslynMetadatas, logger, dllName); return(assembly); }
/// <summary> /// Returns all namespaces in which a callable with the name of the symbol at the given position in the given file belongs to. /// Returns an empty collection if any of the arguments is null or if no unqualified symbol exists at that location. /// Returns the name of the identifier as out parameter if an unqualified symbol exists at that location. /// </summary> private static IEnumerable <NonNullable <string> > NamespaceSuggestionsForIdAtPosition (this FileContentManager file, Position pos, CompilationUnit compilation, out string idName) { var variables = file?.TryGetQsSymbolInfo(pos, true, out CodeFragment _)?.UsedVariables; idName = variables != null && variables.Any() ? variables.Single().Symbol.AsDeclarationName(null) : null; return(idName != null && compilation != null ? compilation.GlobalSymbols.NamespacesContainingCallable(NonNullable <string> .New(idName)) : ImmutableArray <NonNullable <string> > .Empty); }
/// <summary> /// Returns the position and the kind of the closest specialization preceding the given position, /// and the name of the callable it belongs to as well as its position as Nullable. /// Returns null if the given file or position is null, or if no preceding callable can be found (e.g. because the callable name is invalid). /// If a callable name but no specializations (preceding or otherwise) within that callable can be found, /// assumes that the correct specialization is an auto-inserted default body, /// and returns QsBody as well as the start position of the callable declaration along with the callable name and its position. /// If a callable name as well as existing specializations can be found, but no specialization precedes the given position, /// returns null for the specialization kind as well as for its position. /// </summary> public static ((NonNullable <string>, Position), (QsSpecializationKind, Position))? TryGetClosestSpecialization(this FileContentManager file, Position pos) { QsSpecializationKind GetSpecializationKind(CodeFragment fragment) { var specDecl = fragment.Kind.DeclaredSpecialization(); if (specDecl.IsNull) { return(null); } var((kind, gen), typeArgs) = specDecl.Item; // note: if we want to support type specializations we need to compute the signature of the spec to find the right one return(kind); } if (file == null || pos == null || !Utils.IsValidPosition(pos, file)) { return(null); } file.SyncRoot.EnterReadLock(); try { var declarations = file.CallableDeclarationTokens(); var precedingDecl = declarations.TakeWhile(tIndex => tIndex.GetFragment().GetRange().Start.IsSmallerThan(pos)); if (!precedingDecl.Any()) { return(null); } var closestCallable = precedingDecl.Last(); var callablePosition = closestCallable.GetFragment().GetRange().Start; var callableName = closestCallable.GetFragment().Kind.DeclaredCallableName(null); if (callableName == null) { return(null); } var specializations = FileHeader.FilterCallableSpecializations(closestCallable.GetChildren(deep: false).Select(tIndex => tIndex.GetFragment())); var precedingSpec = specializations.TakeWhile(fragment => fragment.GetRange().Start.IsSmallerThan(pos)); var lastPreceding = precedingSpec.Any() ? precedingSpec.Last() : null; if (specializations.Any() && lastPreceding == null) { // the given position is within a callable declaration return((NonNullable <string> .New(callableName), callablePosition), (null, null)); } return(lastPreceding == null ? ((NonNullable <string> .New(callableName), callablePosition), (QsSpecializationKind.QsBody, callablePosition)) : ((NonNullable <string> .New(callableName), callablePosition), (GetSpecializationKind(lastPreceding), lastPreceding.GetRange().Start))); } finally { file.SyncRoot.ExitReadLock(); } }
/// <summary> /// If the given uri corresponds to a C# project file, /// determines if the project is consistent with a recognized Q# project using the ProjectLoader. /// Returns the project information containing the outputPath of the project /// along with the Q# source files as well as all project and dll references as out parameter if it is. /// Returns null if it isn't, or if the project file itself has been listed as to be ignored. /// Calls SendTelemetry with suitable data if the project is a recognized Q# project. /// </summary> internal bool QsProjectLoader(Uri projectFile, out ProjectInformation info) { info = null; if (projectFile == null || !ValidFileUri(projectFile) || IgnoreFile(projectFile)) { return(false); } var projectInstance = this.ProjectLoader.TryGetQsProjectInstance(projectFile.LocalPath, out var telemetryProps); if (projectInstance == null) { return(false); } var outputDir = projectInstance.GetPropertyValue("OutputPath"); var targetFile = projectInstance.GetPropertyValue("TargetFileName"); var outputPath = Path.Combine(projectInstance.Directory, outputDir, targetFile); var executionTarget = projectInstance.GetPropertyValue("ResolvedQsharpExecutionTarget"); var resRuntimeCapability = projectInstance.GetPropertyValue("ResolvedRuntimeCapabilities"); var runtimeCapabilities = Enum.TryParse(resRuntimeCapability, out AssemblyConstants.RuntimeCapabilities capability) ? capability : AssemblyConstants.RuntimeCapabilities.Unknown; var sourceFiles = GetItemsByType(projectInstance, "QsharpCompile"); var csharpFiles = GetItemsByType(projectInstance, "Compile").Where(file => !file.EndsWith(".g.cs")); var projectReferences = GetItemsByType(projectInstance, "ProjectReference"); var references = GetItemsByType(projectInstance, "Reference"); var version = projectInstance.GetPropertyValue("QsharpLangVersion"); var isExecutable = "QsharpExe".Equals(projectInstance.GetPropertyValue("ResolvedQsharpOutputType"), StringComparison.InvariantCultureIgnoreCase); var loadTestNames = "true".Equals(projectInstance.GetPropertyValue("ExposeReferencesViaTestNames"), StringComparison.InvariantCultureIgnoreCase); var defaultSimulator = projectInstance.GetPropertyValue("DefaultSimulator")?.Trim(); var telemetryMeas = new Dictionary <string, int>(); telemetryMeas["sources"] = sourceFiles.Count(); telemetryMeas["csharpfiles"] = csharpFiles.Count(); telemetryProps["defaultSimulator"] = defaultSimulator; this.SendTelemetry("project-load", telemetryProps, telemetryMeas); // does not send anything unless the corresponding flag is defined upon compilation info = new ProjectInformation( version, outputPath, runtimeCapabilities, isExecutable, NonNullable <string> .New(string.IsNullOrWhiteSpace(executionTarget) ? "Unspecified" : executionTarget), loadTestNames, sourceFiles, projectReferences, references); return(true); }
/// <summary> /// Returns all namespaces in which a type with the name of the symbol at the given position in the given file belongs to. /// Returns an empty collection if any of the arguments is null or if no unqualified symbol exists at that location. /// Returns the name of the type as out parameter if an unqualified symbol exists at that location. /// </summary> private static IEnumerable <NonNullable <string> > NamespaceSuggestionsForTypeAtPosition (this FileContentManager file, Position pos, CompilationUnit compilation, out string typeName) { var types = file?.TryGetQsSymbolInfo(pos, true, out CodeFragment _)?.UsedTypes; typeName = types != null && types.Any() && types.Single().Type is QsTypeKind <QsType, QsSymbol, QsSymbol, Characteristics> .UserDefinedType udt ? udt.Item.Symbol.AsDeclarationName(null) : null; return(typeName != null && compilation != null ? compilation.GlobalSymbols.NamespacesContainingType(NonNullable <string> .New(typeName)) : ImmutableArray <NonNullable <string> > .Empty); }
public async Task <ExecutionResult> RunAsync(string input, IChannel channel) { var(name, args) = ParseInput(input); var symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } var snippetsWithNoOverlap = this.Snippets.Items.Where(s => s.Elements.Select(IQSharp.Extensions.ToFullName).Contains(Snippets.SNIPPETS_NAMESPACE + "." + symbol.Name)); var files = new List <Uri>(); files.Add(snippetsWithNoOverlap.FirstOrDefault().Uri); var l = snippetsWithNoOverlap.FirstOrDefault().Elements; Console.WriteLine(l.Count()); foreach (var s in l) { Console.WriteLine(s.ToFullName()); //AssemblyInfo = Compiler.BuildFiles(files, GlobalReferences.CompilerMetadata, logger, CacheDll); } var qsNamespace = new QsCompiler.SyntaxTree.QsNamespace(NonNullable <string> .New(Snippets.SNIPPETS_NAMESPACE), ImmutableArray.Create(l), null); var logger = new QSharpLogger(Logger); var newAssembly = CompilerService.BuildAssembly(files.ToArray(), new[] { qsNamespace }, GlobalReferences.CompilerMetadata.RoslynMetadatas, logger, Path.Combine(Path.GetTempPath(), "__snippets__.dll")); Assembly.LoadFrom(newAssembly.Location); symbol = SymbolResolver.Resolve(name) as IQSharpSymbol; if (symbol == null) { throw new InvalidOperationException($"Invalid operation name: {name}"); } var aSCIICircuitizer = new ASCIICircuitizer(); var qsim = new CircuitizerSimulator(aSCIICircuitizer); qsim.DisableLogToConsole(); qsim.OnLog += channel.Stdout; var value = await symbol.Operation.RunAsync(qsim, args); var result = qsim.Render(); // TODO : currently we are ignoring the Render result from qsim and rendering a local file instead. var imageHtml = new ImageDataWrapper { imageFileName = @"C:\Users\angarg\Pictures\bad_status.PNG" }; //return imageHtml.ToExecutionResult(); return(result.ToExecutionResult()); }
/// <summary> /// Compiles the given Q# code and returns the list of elements found in it. /// The compiler does this on a best effort, so it will return the elements even if the compilation fails. /// </summary> public IEnumerable <QsNamespaceElement> IdentifyElements(string source) { var uri = new Uri(Path.GetFullPath("__CODE_SNIPPET__.qs")); var ns = NonNullable <string> .New(Snippets.SNIPPETS_NAMESPACE); var sources = new Dictionary <Uri, string>() { { uri, $"namespace {ns.Value} {{ {source} }}" } }.ToImmutableDictionary(); var loadOptions = new CompilationLoader.Configuration(); var loaded = new CompilationLoader(_ => sources, _ => QsReferences.Empty, loadOptions); return(loaded.VerifiedCompilation?.SyntaxTree[ns].Elements); }
public IEnumerable <QsNamespaceElement> IdentifyElements(string source) { var loader = CreateTemporaryLoader(source); if (loader.VerifiedCompilation == null) { return(ImmutableArray <QsNamespaceElement> .Empty); } var ns = NonNullable <string> .New(Snippets.SNIPPETS_NAMESPACE); return(loader.VerifiedCompilation.SyntaxTree.TryGetValue(ns, out var tree) ? tree.Elements : ImmutableArray <QsNamespaceElement> .Empty); }
// external routines for context verification /// <summary> /// Given the line number of the lines that contain tokens that (possibly) have been modified, /// checks which callable declaration they can potentially belong to and returns the fully qualified name of those callables. /// Throws an ArgumentNullException if the given file or the collection of changed lines is null. /// </summary> internal static IEnumerable <(Range, QsQualifiedName)> CallablesWithContentModifications(this FileContentManager file, IEnumerable <int> changedLines) { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (changedLines == null) { throw new ArgumentNullException(nameof(changedLines)); } var lastInFile = file.LastToken()?.GetFragment()?.GetRange()?.End ?? file.End(); var callables = file.GetCallableDeclarations().Select(tuple => // these are sorted according to their line number { var ns = file.TryGetNamespaceAt(tuple.Item2.Start); QsCompilerError.Verify(ns != null, "namespace for callable declaration should not be null"); // invalid namespace names default to an unknown namespace name, but remain included in the compilation return(tuple.Item2.Start, new QsQualifiedName(NonNullable <string> .New(ns), tuple.Item1)); }).ToList(); // NOTE: The range of modifications that has to trigger an update of the syntax tree for a callable // does need to go up to and include modifications to the line containing the next callable! // Otherwise inserting a callable declaration in the middle of an existing callable does not trigger the right behavior! (Range, QsQualifiedName) TypeCheckingRange((Position, QsQualifiedName) lastPreceding, IEnumerable <(Position, QsQualifiedName)> next) { var callableStart = lastPreceding.Item1; var callableEnd = next.Any() ? next.First().Item1 : lastInFile; return(new Range { Start = callableStart, End = callableEnd }, lastPreceding.Item2); } foreach (var lineNr in changedLines) { bool precedes((Position, QsQualifiedName) tuple) => tuple.Item1.Line < lineNr; var preceding = callables.TakeWhile(precedes); var following = callables.SkipWhile(precedes); if (preceding.Any()) { yield return(TypeCheckingRange(preceding.Last(), following)); } if (following.Any() && following.First().Item1.Line == lineNr) { yield return(TypeCheckingRange(following.First(), following.Skip(1))); } } }
/// <summary> /// Compiles the given Q# code and returns the list of elements found in it. /// The compiler does this on a best effort, so it will return the elements even if the compilation fails. /// </summary> public IEnumerable <QsCompiler.SyntaxTree.QsNamespaceElement> IdentifyElements(string source) { var ns = NonNullable <string> .New(Snippets.SNIPPETS_NAMESPACE); var logger = new QSharpLogger(null); var sources = new Dictionary <Uri, string>() { { new Uri($"file:///temp"), $"namespace {ns.Value} {{ {source} }}" } }.ToImmutableDictionary(); var references = QsReferences.Empty; var loadOptions = new QsCompiler.CompilationLoader.Configuration(); // do not generate functor support var loaded = new QsCompiler.CompilationLoader(_ => sources, _ => references, loadOptions, logger); return(loaded.VerifiedCompilation?.SyntaxTree[ns].Elements); }
private FileContentManager InitializeFileManager(IEnumerable <string> examples, QsCompilation compilation, string nsName = null) { var(pre, post) = ($"namespace {nsName ?? DefaultNamespaceName}{{ {Environment.NewLine}", $"{Environment.NewLine}}}"); var openDirs = String.Join(Environment.NewLine, OpenedForTesting .Where(nsName => ContainsNamespace(compilation, nsName)) .Select(nsName => $"open {nsName};")); string WrapInNamespace(string example) => pre + openDirs + example + post; examples = examples.Where(ex => !String.IsNullOrWhiteSpace(ex)); var sourceCode = String.Join(Environment.NewLine, examples.Select(WrapInNamespace)); var sourceName = NonNullable <string> .New(Path.GetFullPath($"{nsName}{CodeSource}")); return(CompilationUnitManager.TryGetUri(sourceName, out var sourceUri) ? CompilationUnitManager.InitializeFileManager(sourceUri, sourceCode) : null); }
/// <summary> /// Returns documentation for the callable (if kind is Function or Constructor) or type (if kind is Struct) in /// the compilation unit with the given qualified name. Returns null if no documentation is available or the /// completion item data is missing properties. /// </summary> /// <exception cref="ArgumentNullException">Thrown when any argument is null.</exception> private static string TryGetDocumentation( CompilationUnit compilation, CompletionItemData data, CompletionItemKind kind, bool useMarkdown) { if (compilation == null) { throw new ArgumentNullException(nameof(compilation)); } if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data.QualifiedName == null || data.SourceFile == null || !compilation.GlobalSymbols.NamespaceExists(data.QualifiedName.Namespace)) { return(null); } switch (kind) { case CompletionItemKind.Function: case CompletionItemKind.Constructor: var callable = compilation.GlobalSymbols.TryGetCallable( data.QualifiedName, data.QualifiedName.Namespace, NonNullable <string> .New(data.SourceFile)); if (callable.IsNull) { return(null); } var signature = callable.Item.PrintSignature(); var documentation = callable.Item.Documentation.PrintSummary(useMarkdown); return(signature.Trim() + "\n\n" + documentation.Trim()); case CompletionItemKind.Struct: var type = compilation.GlobalSymbols.TryGetType( data.QualifiedName, data.QualifiedName.Namespace, NonNullable <string> .New(data.SourceFile)) .Item; return(type?.Documentation.PrintSummary(useMarkdown).Trim()); default: return(null); } }
/// <summary> /// Returns completions for namespace aliases with the given prefix that are visible at the given position in /// the file. /// <para/> /// Note: a dot will be added after the given prefix if it is not the empty string, and doesn't already end with /// a dot. /// </summary> /// <exception cref="ArgumentNullException">Thrown when any argument is null.</exception> /// <exception cref="ArgumentException">Thrown when the position is invalid.</exception> private static IEnumerable <CompletionItem> GetNamespaceAliasCompletions( FileContentManager file, CompilationUnit compilation, Position position, string prefix = "") { if (file == null) { throw new ArgumentNullException(nameof(file)); } if (compilation == null) { throw new ArgumentNullException(nameof(compilation)); } if (!Utils.IsValidPosition(position)) { throw new ArgumentException(nameof(position)); } if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } if (prefix.Length != 0 && !prefix.EndsWith(".")) { prefix += "."; } var @namespace = file.TryGetNamespaceAt(position); if (@namespace == null || !compilation.GlobalSymbols.NamespaceExists(NonNullable <string> .New(@namespace))) { return(Array.Empty <CompletionItem>()); } return(compilation .GetOpenDirectives(NonNullable <string> .New(@namespace))[file.FileName] .Where(open => open.Item2 != null && open.Item2.StartsWith(prefix)) .GroupBy(open => NextNamespacePart(open.Item2, prefix.Length)) .Select(open => new CompletionItem() { Label = open.Key, Kind = CompletionItemKind.Module, Detail = open.Count() == 1 && prefix + open.Key == open.Single().Item2 ? open.Single().Item1.Value : prefix + open.Key })); }
public bool Transformation(QsCompilation compilation, out QsCompilation transformed) { var context = CodegenContext.Create(compilation, _assemblyConstants); var sources = GetSourceFiles.Apply(compilation.Namespaces); foreach (var source in sources.Where(s => !s.Value.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))) { var content = SimulationCode.generate(source, context); GeneratedFiles.Add(source.Value, content); } if (!compilation.EntryPoints.IsEmpty) { var callable = context.allCallables.First(c => c.Key == compilation.EntryPoints.First()).Value; var content = EntryPoint.generate(context, callable); NonNullable <string> entryPointName = NonNullable <string> .New(callable.SourceFile.Value + ".EntryPoint"); GeneratedFiles.Add(entryPointName.Value, content); } transformed = compilation; return(true); }
/// <summary> /// Builds the corresponding .net core assembly from the Q# syntax tree. /// </summary> private AssemblyInfo BuildAssembly(ImmutableDictionary <Uri, string> sources, CompilerMetadata metadata, QSharpLogger logger, string dllName) { logger.LogDebug($"Compiling the following Q# files: {string.Join(",", sources.Keys.Select(f => f.LocalPath))}"); var qsCompilation = this.UpdateCompilation(sources, metadata.QsMetadatas, logger); if (logger.HasErrors) { return(null); } try { // Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees: var trees = new List <SyntaxTree>(); NonNullable <string> GetFileId(Uri uri) => CompilationUnitManager.TryGetFileId(uri, out var id) ? id : NonNullable <string> .New(uri.AbsolutePath); foreach (var file in sources.Keys) { var sourceFile = GetFileId(file); var code = SimulationCode.generate(sourceFile, CodegenContext.Create(qsCompilation.Namespaces)); var tree = CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8); trees.Add(tree); logger.LogDebug($"Generated the following C# code for {sourceFile.Value}:\n=============\n{code}\n=============\n"); } // Compile the C# syntax trees: var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug); var compilation = CSharpCompilation.Create( Path.GetFileNameWithoutExtension(dllName), trees, metadata.RoslynMetadatas, options); // Generate the assembly from the C# compilation: using (var ms = new MemoryStream()) using (var bsonStream = new MemoryStream()) { using var writer = new BsonDataWriter(bsonStream) { CloseOutput = false }; var fromSources = qsCompilation.Namespaces.Select(ns => FilterBySourceFile.Apply(ns, s => s.Value.EndsWith(".qs"))); Json.Serializer.Serialize(writer, new QsCompilation(fromSources.ToImmutableArray(), qsCompilation.EntryPoints)); var resourceDescription = new ResourceDescription ( resourceName: QsCompiler.ReservedKeywords.DotnetCoreDll.ResourceName, dataProvider: () => new MemoryStream(bsonStream.ToArray()), isPublic: true ); var result = compilation.Emit(ms, manifestResources: new[] { resourceDescription }); if (!result.Success) { IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); logger.LogError("IQS000", "Could not compile Roslyn dll from working folder."); foreach (Diagnostic diagnostic in failures) { logger.LogError(diagnostic.Id, diagnostic.GetMessage()); } return(null); } else { logger.LogDebug($"Assembly successfully generated. Caching at {dllName}."); var data = ms.ToArray(); try { File.WriteAllBytes(dllName, data); } catch (Exception e) { logger.LogError("IQS001", $"Unable to save assembly cache: {e.Message}."); } return(new AssemblyInfo(Assembly.Load(data), dllName, fromSources.ToArray())); } } } catch (Exception e) { logger.LogError("IQS002", $"Unexpected error compiling assembly: {e.Message}."); return(null); } }
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 # 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.defaultaccessoperation summary: '' newtypes: - uid: microsoft.quantum.canon.defaultaccesstype summary: '' ... "; var actual = Encoding.UTF8.GetString(stream.ToArray()); Assert.Equal(expected, actual); }
/// <summary> /// Builds a string literal with the given content that can be used as argument to a Q# attribute. /// The value of the string literal is set to the empty string if the given content is null. /// </summary> public static TypedExpression StringArgument(string content) => SyntaxGenerator.StringLiteral(NonNullable <string> .New(content ?? ""), ImmutableArray <TypedExpression> .Empty);
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); }
private QsQualifiedName MakeFullName(string name) { return(new QsQualifiedName(CanonName, NonNullable <string> .New(name))); }
public void ParseOp() { ArgDeclType BuildArgument(string name, ResolvedType t) { var validName = QsLocalSymbol.NewValidName(NonNullable <string> .New(name)); var info = new InferredExpressionInformation(false, false); return(new ArgDeclType(validName, t, info, QsNullable <Tuple <int, int> > .Null, EmptyRange)); } string[] comments = { "# Summary", "Convenience function that performs state preparation by applying a ", "`statePrepUnitary` on the input state, followed by adiabatic state ", "preparation using a `adiabaticUnitary`, and finally phase estimation ", "with respect to `qpeUnitary`on the resulting state using a ", "`phaseEstAlgorithm`.", "", "# Input", "## statePrepUnitary", "An oracle representing state preparation for the initial dynamical", "generator.", "## adiabaticUnitary", "An oracle representing the adiabatic evolution algorithm to be used", "to implement the sweeps to the final state of the algorithm.", "## qpeUnitary", "An oracle representing a unitary operator $U$ representing evolution", "for time $\\delta t$ under a dynamical generator with ground state", "$\\ket{\\phi}$ and ground state energy $E = \\phi\\\\,\\delta t$.", "## phaseEstAlgorithm", "An operation that performs phase estimation on a given unitary operation.", "See [iterative phase estimation](/quantum/libraries/characterization#iterative-phase-estimation)", "for more details.", "## qubits", "A register of qubits to be used to perform the simulation.", "", "# Output", "An estimate $\\hat{\\phi}$ of the ground state energy $\\phi$", "of the generator represented by $U$." }; string expected = @"### YamlMime:QSharpType uid: microsoft.quantum.canon.adiabaticstateenergyunitary name: AdiabaticStateEnergyUnitary type: operation namespace: Microsoft.Quantum.Canon summary: |- Convenience function that performs state preparation by applying a `statePrepUnitary` on the input state, followed by adiabatic state preparation using a `adiabaticUnitary`, and finally phase estimation with respect to `qpeUnitary`on the resulting state using a `phaseEstAlgorithm`. syntax: 'operation AdiabaticStateEnergyUnitary (statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit is Adj + Ctl), phaseEstAlgorithm : ((Microsoft.Quantum.Canon.DiscreteOracle, Qubit[]) => Double), qubits : Qubit[]) : Double' input: content: '(statePrepUnitary : (Qubit[] => Unit), adiabaticUnitary : (Qubit[] => Unit), qpeUnitary : (Qubit[] => Unit is Adj + Ctl), phaseEstAlgorithm : ((Microsoft.Quantum.Canon.DiscreteOracle, Qubit[]) => Double), qubits : Qubit[])' types: - name: statePrepUnitary summary: |- An oracle representing state preparation for the initial dynamical generator. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit - name: adiabaticUnitary summary: |- An oracle representing the adiabatic evolution algorithm to be used to implement the sweeps to the final state of the algorithm. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit - name: qpeUnitary summary: |- An oracle representing a unitary operator $U$ representing evolution for time $\delta t$ under a dynamical generator with ground state $\ket{\phi}$ and ground state energy $E = \phi\\,\delta t$. isOperation: true input: types: - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Unit functors: - Adjoint - Controlled - name: phaseEstAlgorithm summary: |- An operation that performs phase estimation on a given unitary operation. See [iterative phase estimation](/quantum/libraries/characterization#iterative-phase-estimation) for more details. isOperation: true input: types: - uid: microsoft.quantum.canon.discreteoracle - isArray: true isPrimitive: true uid: Qubit output: types: - isPrimitive: true uid: Double - name: qubits summary: A register of qubits to be used to perform the simulation. isArray: true isPrimitive: true uid: Qubit output: content: Double types: - summary: |- An estimate $\hat{\phi}$ of the ground state energy $\phi$ of the generator represented by $U$. isPrimitive: true uid: Double ... "; var qubitArrayType = ResolvedType.New(QsType.NewArrayType(ResolvedType.New(QsType.Qubit))); var unitType = ResolvedType.New(QsType.UnitType); var doubleType = ResolvedType.New(QsType.Double); var oracleType = ResolvedType.New(QsType.NewUserDefinedType(new UserDefinedType(CanonName, NonNullable <string> .New("DiscreteOracle"), QsNullable <Tuple <QsPositionInfo, QsPositionInfo> > .Null))); var noInfo = CallableInformation.NoInformation; var acFunctors = ResolvedCharacteristics.FromProperties(new[] { OpProperty.Adjointable, OpProperty.Controllable }); var acInfo = new CallableInformation(acFunctors, InferredCallableInformation.NoInformation); var qubitToUnitOp = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(qubitArrayType, unitType), noInfo)); var qubitToUnitOpAC = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(qubitArrayType, unitType), acInfo)); var phaseEstArgs = new ResolvedType[] { oracleType, qubitArrayType }.ToImmutableArray(); var phaseEstArgTuple = ResolvedType.New(QsType.NewTupleType(phaseEstArgs)); var phaseEstOp = ResolvedType.New(QsType.NewOperation(new SigTypeTuple(phaseEstArgTuple, doubleType), noInfo)); var typeParams = new QsLocalSymbol[] { }.ToImmutableArray(); var argTypes = new ResolvedType[] { qubitToUnitOp, qubitToUnitOp, qubitToUnitOpAC, phaseEstOp, qubitArrayType }.ToImmutableArray(); var argTupleType = ResolvedType.New(QsType.NewTupleType(argTypes)); var signature = new ResolvedSignature(typeParams, argTupleType, doubleType, noInfo); var args = new List <ArgDeclType> { BuildArgument("statePrepUnitary", qubitToUnitOp), BuildArgument("adiabaticUnitary", qubitToUnitOp), BuildArgument("qpeUnitary", qubitToUnitOpAC), BuildArgument("phaseEstAlgorithm", phaseEstOp), BuildArgument("qubits", qubitArrayType) } .ConvertAll(arg => QsTuple <ArgDeclType> .NewQsTupleItem(arg)) .ToImmutableArray(); var argTuple = QsTuple <ArgDeclType> .NewQsTuple(args); var specs = new QsSpecialization[] { }.ToImmutableArray(); var qsCallable = new QsCallable(QsCallableKind.Operation, MakeFullName("AdiabaticStateEnergyUnitary"), ImmutableArray <QsDeclarationAttribute> .Empty, NonNullable <string> .New("Techniques.qs"), ZeroLocation, signature, argTuple, specs, comments.ToImmutableArray(), QsComments.Empty); var callable = new DocCallable("Microsoft.Quantum.Canon", qsCallable); var stream = new StringWriter(); callable.WriteToFile(stream); var s = stream.ToString(); Assert.Equal(expected, s); }
NonNullable <string> SourceOr(NonNullable <string> origSource) => NonNullable <string> .New(source ?? origSource.Value);
/// <summary> /// Builds the corresponding .net core assembly from the Q# syntax tree. /// </summary> private static AssemblyInfo BuildAssembly(Uri[] fileNames, QsCompiler.SyntaxTree.QsNamespace[] syntaxTree, IEnumerable <MetadataReference> references, QSharpLogger logger, string targetDll) { if (logger.HasErrors) { return(null); } logger.LogDebug($"Compiling the following Q# files: {string.Join(",", fileNames.Select(f => f.LocalPath))}"); try { // Generate C# simulation code from Q# syntax tree and convert it into C# syntax trees: var trees = new List <SyntaxTree>(); NonNullable <string> GetFileId(Uri uri) => CompilationUnitManager.TryGetFileId(uri, out var id) ? id : NonNullable <string> .New(uri.AbsolutePath); foreach (var file in fileNames) { var sourceFile = GetFileId(file); var code = SimulationCode.generate(sourceFile, syntaxTree); var tree = CSharpSyntaxTree.ParseText(code, encoding: UTF8Encoding.UTF8); trees.Add(tree); logger.LogDebug($"Generated the following C# code for {sourceFile.Value}:\n=============\n{code}\n=============\n"); } // Compile the C# syntax trees: var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug); var compilation = CSharpCompilation.Create( Path.GetFileNameWithoutExtension(targetDll), trees, references, options); // Generate the assembly from the C# compilation: using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms); if (!result.Success) { IEnumerable <Diagnostic> failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); logger.LogError("IQS000", "Could not compile Roslyn dll from working folder."); foreach (Diagnostic diagnostic in failures) { logger.LogError(diagnostic.Id, diagnostic.GetMessage()); } return(null); } else { logger.LogDebug($"Assembly successfully generated. Caching at {targetDll}."); var data = ms.ToArray(); try { File.WriteAllBytes(targetDll, data); } catch (Exception e) { logger.LogError("IQS001", $"Unable to save assembly cache: {e.Message}."); } return(new AssemblyInfo(Assembly.Load(data), targetDll, syntaxTree)); } } } catch (Exception e) { logger.LogError("IQS002", $"Unexpected error compiling assembly: {e.Message}."); return(null); } }
private static Identifier GetConcreteIdentifier( Response currentResponse, Stack <Request> requests, List <Response> responses, Identifier.GlobalCallable globalCallable, ImmutableConcretion types) { QsQualifiedName concreteName = globalCallable.Item; var typesHashSet = ImmutableHashSet <KeyValuePair <Tuple <QsQualifiedName, NonNullable <string> >, ResolvedType> > .Empty; if (types != null && !types.IsEmpty) { typesHashSet = types.ToImmutableHashSet(); } string name = null; // Check for recursive call if (currentResponse.OriginalName.Equals(globalCallable.Item) && typesHashSet.SetEquals(currentResponse.TypeResolutions)) { name = currentResponse.ConcreteCallable.FullName.Name.Value; } // Search requests for identifier if (name == null) { name = requests .Where(req => req.OriginalName.Equals(globalCallable.Item) && typesHashSet.SetEquals(req.TypeResolutions)) .Select(req => req.ConcreteName.Name.Value) .FirstOrDefault(); } // Search responses for identifier if (name == null) { name = responses .Where(res => res.OriginalName.Equals(globalCallable.Item) && typesHashSet.SetEquals(res.TypeResolutions)) .Select(res => res.ConcreteCallable.FullName.Name.Value) .FirstOrDefault(); } // If identifier can't be found, make a new request if (name == null) { // If this is not a generic, do not change the name if (!typesHashSet.IsEmpty) { // Create new name concreteName = UniqueVariableNames.PrependGuid(globalCallable.Item); } requests.Push(new Request() { OriginalName = globalCallable.Item, TypeResolutions = types, ConcreteName = concreteName }); } else { // If the identifier was found, update with the name concreteName = new QsQualifiedName(globalCallable.Item.Namespace, NonNullable <string> .New(name)); } return(Identifier.NewGlobalCallable(concreteName)); }
internal static QsQualifiedName MakeFullName(string name) { return(new QsQualifiedName(CanonName, NonNullable <string> .New(name))); }