microsoft/qdk

Public

mirrored fromhttps://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
billti/num2-sim

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/npm/qsharp/src/browser.ts

200lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4// This module is the entry point for browser environments. For Node.js environment,
5// the "./main.js" module is the entry point.
6
7import * as wasm from "../lib/web/qsc_wasm.js";
8import initWasm, {
9 IProjectHost,
10 ProjectType,
11 TargetProfile,
12} from "../lib/web/qsc_wasm.js";
13import {
14 Compiler,
15 ICompiler,
16 ICompilerWorker,
17 compilerProtocol,
18} from "./compiler/compiler.js";
19import {
20 IDebugService,
21 IDebugServiceWorker,
22 QSharpDebugService,
23 debugServiceProtocol,
24} from "./debug-service/debug-service.js";
25import {
26 ILanguageService,
27 ILanguageServiceWorker,
28 QSharpLanguageService,
29 languageServiceProtocol,
30 qsharpGithubUriScheme,
31 qsharpLibraryUriScheme,
32} from "./language-service/language-service.js";
33import { LogLevel, log } from "./log.js";
34import { ProjectLoader } from "./project.js";
35import { createProxy } from "./workers/browser.js";
36
37export { qsharpGithubUriScheme, qsharpLibraryUriScheme };
38
39// Create once. A module is stateless and can be efficiently passed to WebWorkers.
40let wasmModule: WebAssembly.Module | null = null;
41let wasmModulePromise: Promise<void> | null = null;
42
43// Used to track if an instance is already instantiated
44let wasmInstancePromise: Promise<wasm.InitOutput> | null = null;
45
46async function wasmLoader(uriOrBuffer: string | ArrayBuffer) {
47 if (typeof uriOrBuffer === "string") {
48 log.info("Fetching wasm module from %s", uriOrBuffer);
49 performance.mark("fetch-wasm-start");
50 const wasmRequst = await fetch(uriOrBuffer);
51 const wasmBuffer = await wasmRequst.arrayBuffer();
52 const fetchTiming = performance.measure("fetch-wasm", "fetch-wasm-start");
53 log.logTelemetry({
54 id: "fetch-wasm",
55 data: {
56 duration: fetchTiming.duration,
57 uri: uriOrBuffer,
58 },
59 });
60
61 wasmModule = await WebAssembly.compile(wasmBuffer);
62 } else {
63 log.info("Compiling wasm module from provided buffer");
64 wasmModule = await WebAssembly.compile(uriOrBuffer);
65 }
66}
67
68export function loadWasmModule(
69 uriOrBuffer: string | ArrayBuffer,
70): Promise<void> {
71 // Only initiate if not already in flight, to avoid race conditions
72 if (!wasmModulePromise) {
73 wasmModulePromise = wasmLoader(uriOrBuffer);
74 }
75 return wasmModulePromise;
76}
77
78async function instantiateWasm() {
79 // Ensure loading the module has been initiated, and wait for it.
80 if (!wasmModulePromise) throw "Wasm module must be loaded first";
81 await wasmModulePromise;
82 if (!wasmModule) throw "Wasm module failed to load";
83
84 if (wasmInstancePromise) {
85 // Either in flight or already complete. The prior request will do the init,
86 // so just wait on that.
87 await wasmInstancePromise;
88 return;
89 }
90
91 // Set the promise to signal this is in flight, then wait on the result.
92 wasmInstancePromise = initWasm(wasmModule);
93 await wasmInstancePromise;
94
95 // Once ready, set up logging and telemetry as soon as possible after instantiating
96 wasm.initLogging(log.logWithLevel, log.getLogLevel());
97 log.onLevelChanged = (level) => wasm.setLogLevel(level);
98}
99
100export async function getLibrarySourceContent(
101 path: string,
102): Promise<string | undefined> {
103 await instantiateWasm();
104 return wasm.get_library_source_content(path);
105}
106
107export async function getDebugService(): Promise<IDebugService> {
108 await instantiateWasm();
109 return new QSharpDebugService(wasm);
110}
111
112export async function getProjectLoader(
113 host: IProjectHost,
114): Promise<ProjectLoader> {
115 await instantiateWasm();
116 return new ProjectLoader(wasm, host);
117}
118
119// Create the debugger inside a WebWorker and proxy requests.
120// If the Worker was already created via other means and is ready to receive
121// messages, then the worker may be passed in and it will be initialized.
122export function getDebugServiceWorker(
123 worker: string | Worker,
124): IDebugServiceWorker {
125 if (!wasmModule) throw "Wasm module must be loaded first";
126 return createProxy(worker, wasmModule, debugServiceProtocol);
127}
128
129export async function getCompiler(): Promise<ICompiler> {
130 await instantiateWasm();
131 return new Compiler(wasm);
132}
133
134// Create the compiler inside a WebWorker and proxy requests.
135// If the Worker was already created via other means and is ready to receive
136// messages, then the worker may be passed in and it will be initialized.
137export function getCompilerWorker(worker: string | Worker): ICompilerWorker {
138 if (!wasmModule) throw "Wasm module must be loaded first";
139 return createProxy(worker, wasmModule, compilerProtocol);
140}
141
142export async function getLanguageService(
143 host?: IProjectHost,
144): Promise<ILanguageService> {
145 await instantiateWasm();
146 return new QSharpLanguageService(wasm, host);
147}
148
149// Create the compiler inside a WebWorker and proxy requests.
150// If the Worker was already created via other means and is ready to receive
151// messages, then the worker may be passed in and it will be initialized.
152export function getLanguageServiceWorker(
153 worker: string | Worker,
154): ILanguageServiceWorker {
155 if (!wasmModule) throw "Wasm module must be loaded first";
156 return createProxy(worker, wasmModule, languageServiceProtocol);
157}
158
159export { StepResultId } from "../lib/web/qsc_wasm.js";
160export type {
161 IBreakpointSpan,
162 ICodeAction,
163 ICodeLens,
164 IDocFile,
165 ILocation,
166 IOperationInfo,
167 IPosition,
168 IProjectConfig,
169 IProjectHost,
170 IQSharpError,
171 IRange,
172 IStackFrame,
173 IStructStepResult,
174 ITestDescriptor,
175 IWorkspaceEdit,
176 VSDiagnostic,
177} from "../lib/web/qsc_wasm.js";
178export { type Dump, type ShotResult } from "./compiler/common.js";
179export { type CompilerState, type ProgramConfig } from "./compiler/compiler.js";
180export { QscEventTarget } from "./compiler/events.js";
181export { QdkDiagnostics } from "./diagnostics.js";
182export type {
183 LanguageServiceDiagnosticEvent,
184 LanguageServiceEvent,
185 LanguageServiceTestCallablesEvent,
186} from "./language-service/language-service.js";
187export { default as openqasm_samples } from "./openqasm-samples.generated.js";
188export type { ProjectLoader } from "./project.js";
189export { default as samples } from "./samples.generated.js";
190export type { CircuitGroup as CircuitData } from "./data-structures/circuit.js";
191export * as utils from "./utils.js";
192export { log, type LogLevel, type ProjectType, type TargetProfile };
193export type {
194 ICompiler,
195 ICompilerWorker,
196 IDebugService,
197 IDebugServiceWorker,
198 ILanguageService,
199 ILanguageServiceWorker,
200};
201