cppbolt 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -62
- package/dist/compiler.d.ts +16 -0
- package/dist/compiler.js +92 -0
- package/dist/cppbolt.browser.js +509 -0
- package/dist/host.d.ts +45 -0
- package/dist/host.js +408 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +27 -0
- package/dist/runner.d.ts +29 -0
- package/dist/runner.js +40 -0
- package/package.json +15 -2
- package/wasm/cppbolt.wasm +0 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var CppBolt = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
8
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
9
|
+
}) : x)(function(x) {
|
|
10
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
11
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
12
|
+
});
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
|
+
|
|
27
|
+
// npm/src/index.ts
|
|
28
|
+
var index_exports = {};
|
|
29
|
+
__export(index_exports, {
|
|
30
|
+
CompileError: () => CompileError,
|
|
31
|
+
CppBoltCompiler: () => CppBoltCompiler,
|
|
32
|
+
CppBoltRunner: () => CppBoltRunner,
|
|
33
|
+
compileAndRun: () => compileAndRun,
|
|
34
|
+
createCompiler: () => createCompiler,
|
|
35
|
+
createWasmHost: () => createWasmHost
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// npm/src/host.ts
|
|
39
|
+
function roundToEvenExact(vNum, prec) {
|
|
40
|
+
if (isNaN(vNum)) return "nan";
|
|
41
|
+
if (vNum === Infinity) return "inf";
|
|
42
|
+
if (vNum === -Infinity) return "-inf";
|
|
43
|
+
if (Object.is(vNum, -0)) {
|
|
44
|
+
return "-0" + (prec > 0 ? "." + "0".repeat(prec) : "");
|
|
45
|
+
}
|
|
46
|
+
if (vNum === 0) {
|
|
47
|
+
return "0" + (prec > 0 ? "." + "0".repeat(prec) : "");
|
|
48
|
+
}
|
|
49
|
+
const isNeg = vNum < 0;
|
|
50
|
+
const v = Math.abs(vNum);
|
|
51
|
+
const buf = new ArrayBuffer(8);
|
|
52
|
+
const view = new DataView(buf);
|
|
53
|
+
view.setFloat64(0, v, false);
|
|
54
|
+
const bits = view.getBigUint64(0, false);
|
|
55
|
+
const rawExp = Number(bits >> 52n & 0x7ffn);
|
|
56
|
+
const rawMantissa = bits & 0xfffffffffffffn;
|
|
57
|
+
let mantissa;
|
|
58
|
+
let exp;
|
|
59
|
+
if (rawExp === 0) {
|
|
60
|
+
mantissa = rawMantissa;
|
|
61
|
+
exp = -1022 - 52;
|
|
62
|
+
} else {
|
|
63
|
+
mantissa = rawMantissa | 1n << 52n;
|
|
64
|
+
exp = rawExp - 1023 - 52;
|
|
65
|
+
}
|
|
66
|
+
const P = BigInt(prec);
|
|
67
|
+
const p5 = 5n ** P;
|
|
68
|
+
const expP = BigInt(exp) + P;
|
|
69
|
+
let num;
|
|
70
|
+
let den;
|
|
71
|
+
if (expP >= 0n) {
|
|
72
|
+
num = mantissa * 2n ** expP * p5;
|
|
73
|
+
den = 1n;
|
|
74
|
+
} else {
|
|
75
|
+
num = mantissa * p5;
|
|
76
|
+
den = 2n ** -expP;
|
|
77
|
+
}
|
|
78
|
+
const Q = num / den;
|
|
79
|
+
const R = num % den;
|
|
80
|
+
const twoR = R * 2n;
|
|
81
|
+
let rounded;
|
|
82
|
+
if (twoR < den) {
|
|
83
|
+
rounded = Q;
|
|
84
|
+
} else if (twoR > den) {
|
|
85
|
+
rounded = Q + 1n;
|
|
86
|
+
} else {
|
|
87
|
+
rounded = Q % 2n === 0n ? Q : Q + 1n;
|
|
88
|
+
}
|
|
89
|
+
let s = rounded.toString();
|
|
90
|
+
if (prec > 0) {
|
|
91
|
+
while (s.length <= prec) {
|
|
92
|
+
s = "0" + s;
|
|
93
|
+
}
|
|
94
|
+
const intPart = s.slice(0, s.length - prec);
|
|
95
|
+
const fracPart = s.slice(s.length - prec);
|
|
96
|
+
s = intPart + "." + fracPart;
|
|
97
|
+
}
|
|
98
|
+
return (isNeg ? "-" : "") + s;
|
|
99
|
+
}
|
|
100
|
+
function formatExpExact(vNum, prec) {
|
|
101
|
+
if (isNaN(vNum)) return "nan";
|
|
102
|
+
if (vNum === Infinity) return "inf";
|
|
103
|
+
if (vNum === -Infinity) return "-inf";
|
|
104
|
+
if (Object.is(vNum, -0)) {
|
|
105
|
+
const zeros = prec > 0 ? "." + "0".repeat(prec) : "";
|
|
106
|
+
return "-0" + zeros + "e+00";
|
|
107
|
+
}
|
|
108
|
+
if (vNum === 0) {
|
|
109
|
+
const zeros = prec > 0 ? "." + "0".repeat(prec) : "";
|
|
110
|
+
return "0" + zeros + "e+00";
|
|
111
|
+
}
|
|
112
|
+
const isNeg = vNum < 0;
|
|
113
|
+
const v = Math.abs(vNum);
|
|
114
|
+
let exp = Math.floor(Math.log10(v));
|
|
115
|
+
const buf = new ArrayBuffer(8);
|
|
116
|
+
const view = new DataView(buf);
|
|
117
|
+
view.setFloat64(0, v, false);
|
|
118
|
+
const bits = view.getBigUint64(0, false);
|
|
119
|
+
const rawExp = Number(bits >> 52n & 0x7ffn);
|
|
120
|
+
const rawMantissa = bits & 0xfffffffffffffn;
|
|
121
|
+
let mantissa;
|
|
122
|
+
let bexp;
|
|
123
|
+
if (rawExp === 0) {
|
|
124
|
+
mantissa = rawMantissa;
|
|
125
|
+
bexp = -1022 - 52;
|
|
126
|
+
} else {
|
|
127
|
+
mantissa = rawMantissa | 1n << 52n;
|
|
128
|
+
bexp = rawExp - 1023 - 52;
|
|
129
|
+
}
|
|
130
|
+
let Q;
|
|
131
|
+
let R;
|
|
132
|
+
let den;
|
|
133
|
+
while (true) {
|
|
134
|
+
const shift = prec - exp;
|
|
135
|
+
const S = BigInt(shift);
|
|
136
|
+
let num;
|
|
137
|
+
if (S >= 0n) {
|
|
138
|
+
const p5 = 5n ** S;
|
|
139
|
+
const expP = BigInt(bexp) + S;
|
|
140
|
+
if (expP >= 0n) {
|
|
141
|
+
num = mantissa * 2n ** expP * p5;
|
|
142
|
+
den = 1n;
|
|
143
|
+
} else {
|
|
144
|
+
num = mantissa * p5;
|
|
145
|
+
den = 2n ** -expP;
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
const negS = -S;
|
|
149
|
+
const p5 = 5n ** negS;
|
|
150
|
+
const expP = BigInt(bexp) - negS;
|
|
151
|
+
if (expP >= 0n) {
|
|
152
|
+
num = mantissa * 2n ** expP;
|
|
153
|
+
den = p5;
|
|
154
|
+
} else {
|
|
155
|
+
num = mantissa;
|
|
156
|
+
den = p5 * 2n ** -expP;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
Q = num / den;
|
|
160
|
+
R = num % den;
|
|
161
|
+
if (Q === 0n && v > 0) {
|
|
162
|
+
exp--;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (Q >= 10n ** BigInt(prec + 1)) {
|
|
166
|
+
exp++;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
const twoR = R * 2n;
|
|
172
|
+
let rounded;
|
|
173
|
+
if (twoR < den) {
|
|
174
|
+
rounded = Q;
|
|
175
|
+
} else if (twoR > den) {
|
|
176
|
+
rounded = Q + 1n;
|
|
177
|
+
} else {
|
|
178
|
+
rounded = Q % 2n === 0n ? Q : Q + 1n;
|
|
179
|
+
}
|
|
180
|
+
if (rounded >= 10n ** BigInt(prec + 1)) {
|
|
181
|
+
rounded = rounded / 10n;
|
|
182
|
+
exp++;
|
|
183
|
+
}
|
|
184
|
+
let s = rounded.toString();
|
|
185
|
+
while (s.length < prec + 1) {
|
|
186
|
+
s = "0" + s;
|
|
187
|
+
}
|
|
188
|
+
const mStr = s[0] + (prec > 0 ? "." + s.slice(1) : "");
|
|
189
|
+
const expSign = exp >= 0 ? "+" : "-";
|
|
190
|
+
const expVal = Math.abs(exp).toString().padStart(2, "0");
|
|
191
|
+
return (isNeg ? "-" : "") + mStr + "e" + expSign + expVal;
|
|
192
|
+
}
|
|
193
|
+
function formatGExact(vNum, prec, alternate = false) {
|
|
194
|
+
if (isNaN(vNum)) return "nan";
|
|
195
|
+
if (vNum === Infinity) return "inf";
|
|
196
|
+
if (vNum === -Infinity) return "-inf";
|
|
197
|
+
if (!prec || prec <= 0) prec = 1;
|
|
198
|
+
if (Object.is(vNum, -0) || vNum === 0) {
|
|
199
|
+
if (!alternate) return Object.is(vNum, -0) ? "-0" : "0";
|
|
200
|
+
const res2 = roundToEvenExact(vNum, prec - 1);
|
|
201
|
+
return res2.includes(".") ? res2 : res2 + ".";
|
|
202
|
+
}
|
|
203
|
+
const v = Math.abs(vNum);
|
|
204
|
+
const exp = Math.floor(Math.log10(v));
|
|
205
|
+
let res;
|
|
206
|
+
if (exp < -4 || exp >= prec) {
|
|
207
|
+
res = formatExpExact(vNum, prec - 1);
|
|
208
|
+
if (!alternate) {
|
|
209
|
+
let [m, e] = res.split("e");
|
|
210
|
+
if (m.includes(".")) {
|
|
211
|
+
m = m.replace(/0+$/, "").replace(/\.$/, "");
|
|
212
|
+
}
|
|
213
|
+
res = m + "e" + e;
|
|
214
|
+
} else if (Number.isFinite(vNum) && !res.includes(".")) {
|
|
215
|
+
const e = res.indexOf("e");
|
|
216
|
+
res = e >= 0 ? res.slice(0, e) + "." + res.slice(e) : res + ".";
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
const pAfterDot = Math.max(0, prec - 1 - exp);
|
|
220
|
+
res = roundToEvenExact(vNum, pAfterDot);
|
|
221
|
+
if (!alternate) {
|
|
222
|
+
if (res.includes(".")) {
|
|
223
|
+
res = res.replace(/0+$/, "").replace(/\.$/, "");
|
|
224
|
+
}
|
|
225
|
+
} else if (Number.isFinite(vNum) && !res.includes(".")) {
|
|
226
|
+
res += ".";
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return res;
|
|
230
|
+
}
|
|
231
|
+
function createWasmHost(options = {}) {
|
|
232
|
+
const { stdin, onStdout, onExit } = options;
|
|
233
|
+
let stdoutBuffer = "";
|
|
234
|
+
let inPos = 0;
|
|
235
|
+
const writeStdout = (str) => {
|
|
236
|
+
stdoutBuffer += str;
|
|
237
|
+
if (onStdout) {
|
|
238
|
+
onStdout(str);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const imports = {
|
|
242
|
+
env: {
|
|
243
|
+
print_char: (ch) => {
|
|
244
|
+
writeStdout(String.fromCharCode(ch));
|
|
245
|
+
},
|
|
246
|
+
print_int: (val, radix, width, precision, flags) => {
|
|
247
|
+
const isZeroPad = (flags & 1) !== 0;
|
|
248
|
+
const isLeftAlign = (flags & 2) !== 0;
|
|
249
|
+
const isShowSign = (flags & 4) !== 0;
|
|
250
|
+
const isSpaceSign = (flags & 8) !== 0;
|
|
251
|
+
const isUppercase = (flags & 16) !== 0;
|
|
252
|
+
const isUnsigned = (flags & 32) !== 0;
|
|
253
|
+
const isAlternate = (flags & 64) !== 0;
|
|
254
|
+
let numVal = BigInt(val);
|
|
255
|
+
let isNeg = false;
|
|
256
|
+
if (isUnsigned) {
|
|
257
|
+
numVal = BigInt.asUintN(64, numVal);
|
|
258
|
+
} else {
|
|
259
|
+
if (numVal < 0n) {
|
|
260
|
+
isNeg = true;
|
|
261
|
+
numVal = -numVal;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
let s = numVal.toString(radix);
|
|
265
|
+
if (isUppercase) {
|
|
266
|
+
s = s.toUpperCase();
|
|
267
|
+
}
|
|
268
|
+
if (precision >= 0) {
|
|
269
|
+
if (precision === 0 && numVal === 0n) {
|
|
270
|
+
s = "";
|
|
271
|
+
} else {
|
|
272
|
+
while (s.length < precision) {
|
|
273
|
+
s = "0" + s;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
let signStr = "";
|
|
278
|
+
if (isNeg) {
|
|
279
|
+
signStr = "-";
|
|
280
|
+
} else if (!isUnsigned && isShowSign) {
|
|
281
|
+
signStr = "+";
|
|
282
|
+
} else if (!isUnsigned && isSpaceSign) {
|
|
283
|
+
signStr = " ";
|
|
284
|
+
}
|
|
285
|
+
let prefix = "";
|
|
286
|
+
if (isAlternate) {
|
|
287
|
+
if (radix === 8) {
|
|
288
|
+
if (!s.startsWith("0")) {
|
|
289
|
+
prefix = "0";
|
|
290
|
+
}
|
|
291
|
+
} else if (radix === 16 && numVal !== 0n) {
|
|
292
|
+
prefix = isUppercase ? "0X" : "0x";
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
let fullStr;
|
|
296
|
+
if (precision < 0 && isZeroPad && !isLeftAlign) {
|
|
297
|
+
let zeros = "";
|
|
298
|
+
while (signStr.length + prefix.length + zeros.length + s.length < width) {
|
|
299
|
+
zeros += "0";
|
|
300
|
+
}
|
|
301
|
+
fullStr = signStr + prefix + zeros + s;
|
|
302
|
+
} else {
|
|
303
|
+
fullStr = signStr + prefix + s;
|
|
304
|
+
}
|
|
305
|
+
if (fullStr.length < width) {
|
|
306
|
+
const padLen = width - fullStr.length;
|
|
307
|
+
const pad = " ".repeat(padLen);
|
|
308
|
+
fullStr = isLeftAlign ? fullStr + pad : pad + fullStr;
|
|
309
|
+
}
|
|
310
|
+
writeStdout(fullStr);
|
|
311
|
+
return fullStr.length;
|
|
312
|
+
},
|
|
313
|
+
print_double: (val, width, precision, mode, flags) => {
|
|
314
|
+
const isAlternate = (flags & 64) !== 0;
|
|
315
|
+
let s = "";
|
|
316
|
+
if (mode === 0) {
|
|
317
|
+
const prec = precision >= 0 ? precision : 6;
|
|
318
|
+
s = formatGExact(val, prec, isAlternate);
|
|
319
|
+
} else if (mode === 1) {
|
|
320
|
+
const p = precision >= 0 ? precision : 6;
|
|
321
|
+
s = roundToEvenExact(val, p);
|
|
322
|
+
if (isAlternate && Number.isFinite(val) && !s.includes(".")) {
|
|
323
|
+
s += ".";
|
|
324
|
+
}
|
|
325
|
+
} else if (mode === 2) {
|
|
326
|
+
const p = precision >= 0 ? precision : 6;
|
|
327
|
+
s = formatExpExact(val, p);
|
|
328
|
+
if (isAlternate && Number.isFinite(val) && !s.includes(".")) {
|
|
329
|
+
const e = s.indexOf("e");
|
|
330
|
+
s = e >= 0 ? s.slice(0, e) + "." + s.slice(e) : s + ".";
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
throw new Error("unknown float format mode: " + mode);
|
|
334
|
+
}
|
|
335
|
+
if ((flags & 16) !== 0) {
|
|
336
|
+
s = s.toUpperCase();
|
|
337
|
+
}
|
|
338
|
+
const isZeroPad = (flags & 1) !== 0;
|
|
339
|
+
const isLeftAlign = (flags & 2) !== 0;
|
|
340
|
+
const isShowSign = (flags & 4) !== 0;
|
|
341
|
+
const isSpaceSign = (flags & 8) !== 0;
|
|
342
|
+
let sign = "";
|
|
343
|
+
if (s.startsWith("-")) {
|
|
344
|
+
sign = "-";
|
|
345
|
+
s = s.slice(1);
|
|
346
|
+
} else if (isShowSign) {
|
|
347
|
+
sign = "+";
|
|
348
|
+
} else if (isSpaceSign) {
|
|
349
|
+
sign = " ";
|
|
350
|
+
}
|
|
351
|
+
if (width > 0 && sign.length + s.length < width) {
|
|
352
|
+
const padLen = width - sign.length - s.length;
|
|
353
|
+
if (isZeroPad && !isLeftAlign && Number.isFinite(val)) {
|
|
354
|
+
s = sign + "0".repeat(padLen) + s;
|
|
355
|
+
} else {
|
|
356
|
+
const pad = " ".repeat(padLen);
|
|
357
|
+
s = isLeftAlign ? sign + s + pad : pad + sign + s;
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
s = sign + s;
|
|
361
|
+
}
|
|
362
|
+
writeStdout(s);
|
|
363
|
+
return s.length;
|
|
364
|
+
},
|
|
365
|
+
read_char: () => {
|
|
366
|
+
if (typeof stdin === "function") {
|
|
367
|
+
return stdin();
|
|
368
|
+
} else if (typeof stdin === "string") {
|
|
369
|
+
if (inPos < stdin.length) {
|
|
370
|
+
return stdin.charCodeAt(inPos++);
|
|
371
|
+
}
|
|
372
|
+
return -1;
|
|
373
|
+
}
|
|
374
|
+
return -1;
|
|
375
|
+
},
|
|
376
|
+
exit: (code) => {
|
|
377
|
+
if (onExit) {
|
|
378
|
+
onExit(code);
|
|
379
|
+
} else if (typeof process !== "undefined" && typeof process.exit === "function") {
|
|
380
|
+
process.exit(code);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
return {
|
|
386
|
+
imports,
|
|
387
|
+
getStdout: () => stdoutBuffer
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// npm/src/runner.ts
|
|
392
|
+
var CppBoltRunner = class {
|
|
393
|
+
constructor(host) {
|
|
394
|
+
this.host = host;
|
|
395
|
+
}
|
|
396
|
+
host;
|
|
397
|
+
/**
|
|
398
|
+
* Instantiates `wasmBytes`, calls the program entry point (`main`, falling
|
|
399
|
+
* back to `_start`), and collects its stdout and exit status.
|
|
400
|
+
*
|
|
401
|
+
* A WebAssembly trap is reported as exit status 134 rather than thrown, so
|
|
402
|
+
* callers can inspect partial output the same way a shell would.
|
|
403
|
+
*/
|
|
404
|
+
async run(wasmBytes) {
|
|
405
|
+
const { instance } = await WebAssembly.instantiate(
|
|
406
|
+
wasmBytes,
|
|
407
|
+
this.host.imports
|
|
408
|
+
);
|
|
409
|
+
let exitCode = 0;
|
|
410
|
+
try {
|
|
411
|
+
const exports = instance.exports;
|
|
412
|
+
const fn = exports.main ?? exports._start;
|
|
413
|
+
if (fn) exitCode = fn() ?? 0;
|
|
414
|
+
} catch {
|
|
415
|
+
return { stdout: this.host.getStdout(), exitCode: 134 };
|
|
416
|
+
}
|
|
417
|
+
return { stdout: this.host.getStdout(), exitCode };
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// npm/src/compiler.ts
|
|
422
|
+
function tryRequire(id) {
|
|
423
|
+
if (typeof __require !== "function") return null;
|
|
424
|
+
try {
|
|
425
|
+
return __require(id);
|
|
426
|
+
} catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
var fs = tryRequire("fs");
|
|
431
|
+
var path = tryRequire("path");
|
|
432
|
+
var scriptSrc = typeof document !== "undefined" && document.currentScript instanceof HTMLScriptElement ? document.currentScript.src : null;
|
|
433
|
+
function decodeString(memory, ptr, len) {
|
|
434
|
+
return new TextDecoder().decode(new Uint8Array(memory.buffer, ptr, len));
|
|
435
|
+
}
|
|
436
|
+
var CompileError = class extends Error {
|
|
437
|
+
diagnostic;
|
|
438
|
+
constructor(diagnostic) {
|
|
439
|
+
super(diagnostic);
|
|
440
|
+
this.name = "CompileError";
|
|
441
|
+
this.diagnostic = diagnostic;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
var CppBoltCompiler = class {
|
|
445
|
+
_exports;
|
|
446
|
+
constructor(instance) {
|
|
447
|
+
this._exports = instance.exports;
|
|
448
|
+
}
|
|
449
|
+
compile(source) {
|
|
450
|
+
const ex = this._exports;
|
|
451
|
+
const mem = ex.memory;
|
|
452
|
+
const srcBytes = new TextEncoder().encode(source);
|
|
453
|
+
const srcPtr = ex.alloc_buffer(srcBytes.length);
|
|
454
|
+
new Uint8Array(mem.buffer, srcPtr, srcBytes.length).set(srcBytes);
|
|
455
|
+
const resultPtr = ex.compile_wasm(srcPtr, srcBytes.length);
|
|
456
|
+
ex.dealloc_buffer(srcPtr, srcBytes.length);
|
|
457
|
+
if (resultPtr === 0) {
|
|
458
|
+
throw new CompileError(
|
|
459
|
+
decodeString(mem, ex.get_error_ptr(), ex.get_error_len())
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
const resultLen = ex.get_result_len();
|
|
463
|
+
const output = new Uint8Array(mem.buffer, resultPtr, resultLen).slice();
|
|
464
|
+
ex.free_result(resultPtr, resultLen);
|
|
465
|
+
return output;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
async function createCompiler() {
|
|
469
|
+
if (fs && path && typeof __dirname === "string") {
|
|
470
|
+
const localPath = path.join(__dirname, "..", "wasm", "cppbolt.wasm");
|
|
471
|
+
if (fs.existsSync(localPath)) {
|
|
472
|
+
return new CppBoltCompiler(
|
|
473
|
+
await loadFromBytes(fs.readFileSync(localPath))
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const wasmUrl = scriptSrc ? new URL("../wasm/cppbolt.wasm", scriptSrc).href : null;
|
|
478
|
+
if (wasmUrl) {
|
|
479
|
+
return new CppBoltCompiler(await loadFromResponse(await fetch(wasmUrl)));
|
|
480
|
+
}
|
|
481
|
+
throw new Error(
|
|
482
|
+
"cppbolt: could not locate wasm binary. Load this script from a URL (CDN / local server) or use the Node.js package."
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
async function loadFromResponse(response) {
|
|
486
|
+
if (!response.ok) {
|
|
487
|
+
throw new Error(`cppbolt: failed to fetch wasm (HTTP ${response.status})`);
|
|
488
|
+
}
|
|
489
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
490
|
+
if (contentType.includes("application/wasm")) {
|
|
491
|
+
const { instance } = await WebAssembly.instantiateStreaming(response, {});
|
|
492
|
+
return instance;
|
|
493
|
+
}
|
|
494
|
+
return loadFromBytes(await response.arrayBuffer());
|
|
495
|
+
}
|
|
496
|
+
async function loadFromBytes(bytes) {
|
|
497
|
+
const { instance } = await WebAssembly.instantiate(bytes, {});
|
|
498
|
+
return instance;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// npm/src/index.ts
|
|
502
|
+
async function compileAndRun(compiler, source, options) {
|
|
503
|
+
const host = createWasmHost(options);
|
|
504
|
+
const runner = new CppBoltRunner(host);
|
|
505
|
+
const bytes = compiler.compile(source);
|
|
506
|
+
return runner.run(bytes);
|
|
507
|
+
}
|
|
508
|
+
return __toCommonJS(index_exports);
|
|
509
|
+
})();
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for the runtime import environment used by compiled programs.
|
|
3
|
+
*/
|
|
4
|
+
export interface WasmHostOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Stdin source for `read_char`.
|
|
7
|
+
* - A `string` is consumed character by character; EOF returns -1.
|
|
8
|
+
* - A `() => number` callback is called once per character; return -1 for EOF.
|
|
9
|
+
* - Omit (or leave undefined) for no stdin input.
|
|
10
|
+
*/
|
|
11
|
+
stdin?: string | (() => number);
|
|
12
|
+
/**
|
|
13
|
+
* Called whenever the program writes characters to stdout.
|
|
14
|
+
* Receives the chunk as a string; chunks are flushed per print call,
|
|
15
|
+
* not per character.
|
|
16
|
+
*/
|
|
17
|
+
onStdout?: (chunk: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Called when the program invokes `exit(code)`.
|
|
20
|
+
* If omitted, falls back to `process.exit(code)` in Node.js. Browser hosts
|
|
21
|
+
* should provide this hook because there is no `process` to terminate.
|
|
22
|
+
*/
|
|
23
|
+
onExit?: (code: number) => void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The runtime host for a compiled C++ WebAssembly program.
|
|
27
|
+
* Pass `imports` to `WebAssembly.instantiate`, then call `getStdout()` to
|
|
28
|
+
* retrieve the accumulated output after the program finishes.
|
|
29
|
+
*/
|
|
30
|
+
export interface WasmHost {
|
|
31
|
+
/** The WebAssembly import object — provide this to `WebAssembly.instantiate`. */
|
|
32
|
+
imports: WebAssembly.Imports;
|
|
33
|
+
/** Returns all stdout output accumulated since the host was created. */
|
|
34
|
+
getStdout(): string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates the runtime import environment (`env.*`) required by programs
|
|
38
|
+
* compiled with cppbolt.
|
|
39
|
+
*
|
|
40
|
+
* Every module emitted by the compiler imports exactly five functions:
|
|
41
|
+
* `print_char`, `print_int`, `print_double`, `read_char`, and `exit`.
|
|
42
|
+
* This function provides all five with correct printf-exact semantics that
|
|
43
|
+
* match the compiler's runtime contract.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createWasmHost(options?: WasmHostOptions): WasmHost;
|