@wasmgroundup/emit 1.0.2 → 2.1.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.
Files changed (4) hide show
  1. package/index.d.ts +456 -0
  2. package/index.js +40 -10
  3. package/package.json +25 -3
  4. package/index.test.ts +0 -229
package/index.d.ts ADDED
@@ -0,0 +1,456 @@
1
+ export type Byte = number;
2
+ export type Bytes = readonly Byte[];
3
+
4
+ export type Fragment = readonly (Byte | Bytes | Fragment)[];
5
+
6
+ export type SectionId =
7
+ | typeof SECTION_ID_CUSTOM
8
+ | typeof SECTION_ID_TYPE
9
+ | typeof SECTION_ID_IMPORT
10
+ | typeof SECTION_ID_FUNCTION
11
+ | typeof SECTION_ID_TABLE
12
+ | typeof SECTION_ID_MEMORY
13
+ | typeof SECTION_ID_GLOBAL
14
+ | typeof SECTION_ID_EXPORT
15
+ | typeof SECTION_ID_START
16
+ | typeof SECTION_ID_ELEMENT
17
+ | typeof SECTION_ID_CODE
18
+ | typeof SECTION_ID_DATA;
19
+
20
+ declare const brand: unique symbol;
21
+ type Brand<T, B extends string> = T & {readonly [brand]: B};
22
+
23
+ export type typeidx = Brand<Bytes, 'typeidx'>;
24
+ export type funcidx = Brand<Bytes, 'funcidx'>;
25
+ export type localidx = Brand<Bytes, 'localidx'>;
26
+ export type globalidx = Brand<Bytes, 'globalidx'>;
27
+ export type tableidx = Brand<Bytes, 'tableidx'>;
28
+ export type labelidx = Brand<Bytes, 'labelidx'>;
29
+ export type memidx = Brand<Bytes, 'memidx'>;
30
+ export type idx =
31
+ | typeidx
32
+ | funcidx
33
+ | localidx
34
+ | globalidx
35
+ | tableidx
36
+ | labelidx
37
+ | memidx;
38
+
39
+ export function stringToBytes(s: string): Bytes;
40
+
41
+ export function magic(): Bytes;
42
+ export function version(): Bytes;
43
+
44
+ export function u32(v: number): Bytes;
45
+ export function i32(v: number): Bytes;
46
+
47
+ export function section(id: SectionId, contents: Fragment): Fragment;
48
+ export function vec(elements: Fragment): Fragment;
49
+
50
+ // Type section
51
+ // ------------
52
+
53
+ export const SECTION_ID_TYPE: 1;
54
+
55
+ export type valtype = Brand<number, 'valtype'>;
56
+
57
+ export const valtype: {
58
+ i32: valtype;
59
+ i64: valtype;
60
+ f32: valtype;
61
+ f64: valtype;
62
+ };
63
+
64
+ export function functype(
65
+ paramTypes: readonly valtype[],
66
+ resultTypes: readonly valtype[],
67
+ ): Fragment;
68
+
69
+ export function typesec(functypes: readonly Fragment[]): Fragment;
70
+
71
+ // Function section and indices
72
+ // ----------------------------
73
+
74
+ export const SECTION_ID_FUNCTION: 3;
75
+
76
+ export function typeidx(x: number): typeidx;
77
+ export function funcidx(x: number): funcidx;
78
+ export function localidx(x: number): localidx;
79
+ export function labelidx(x: number): labelidx;
80
+ export function tableidx(x: number): tableidx;
81
+ export function globalidx(x: number): globalidx;
82
+ export function memidx(x: number): memidx;
83
+
84
+ export function funcsec(typeidxs: readonly typeidx[]): Fragment;
85
+
86
+ // Code section
87
+ // ------------
88
+
89
+ export const SECTION_ID_CODE: 10;
90
+
91
+ export function code(func: Fragment): Fragment;
92
+
93
+ export function func(locals: readonly Fragment[], body: Fragment): Fragment;
94
+
95
+ export function expr(instrs: readonly Fragment[]): Fragment;
96
+
97
+ export function codesec(codes: readonly Fragment[]): Fragment;
98
+
99
+ // Instructions etc.
100
+ // -----------------
101
+
102
+ // Autogenerated by scripts/gen_instr_type.js. Do not edit manually.
103
+ export const instr: {
104
+ readonly end: 0x0b;
105
+ i32: {
106
+ readonly const: 0x41;
107
+ readonly add: 0x6a;
108
+ readonly sub: 0x6b;
109
+ readonly mul: 0x6c;
110
+ readonly div_s: 0x6d;
111
+ readonly eq: 0x46;
112
+ readonly ne: 0x47;
113
+ readonly lt_s: 0x48;
114
+ readonly lt_u: 0x49;
115
+ readonly gt_s: 0x4a;
116
+ readonly gt_u: 0x4b;
117
+ readonly le_s: 0x4c;
118
+ readonly le_u: 0x4d;
119
+ readonly ge_s: 0x4e;
120
+ readonly ge_u: 0x4f;
121
+ readonly eqz: 0x45;
122
+ readonly and: 0x71;
123
+ readonly or: 0x72;
124
+ readonly load: 0x28;
125
+ readonly store: 0x36;
126
+ readonly load8_s: 0x2c;
127
+ readonly load8_u: 0x2d;
128
+ readonly load16_s: 0x2e;
129
+ readonly load16_u: 0x2f;
130
+ readonly store8: 0x3a;
131
+ readonly store16: 0x3b;
132
+ readonly clz: 0x67;
133
+ readonly ctz: 0x68;
134
+ readonly popcnt: 0x69;
135
+ readonly div_u: 0x6e;
136
+ readonly rem_s: 0x6f;
137
+ readonly rem_u: 0x70;
138
+ readonly xor: 0x73;
139
+ readonly shl: 0x74;
140
+ readonly shr_s: 0x75;
141
+ readonly shr_u: 0x76;
142
+ readonly rotl: 0x77;
143
+ readonly rotr: 0x78;
144
+ readonly wrap_i64: 0xa7;
145
+ readonly trunc_f32_s: 0xa8;
146
+ readonly trunc_f32_u: 0xa9;
147
+ readonly trunc_f64_s: 0xaa;
148
+ readonly trunc_f64_u: 0xab;
149
+ readonly reinterpret_f32: 0xbc;
150
+ };
151
+ i64: {
152
+ readonly const: 0x42;
153
+ readonly load: 0x29;
154
+ readonly load8_s: 0x30;
155
+ readonly load8_u: 0x31;
156
+ readonly load16_s: 0x32;
157
+ readonly load16_u: 0x33;
158
+ readonly load32_s: 0x34;
159
+ readonly load32_u: 0x35;
160
+ readonly store: 0x37;
161
+ readonly store8: 0x3c;
162
+ readonly store16: 0x3d;
163
+ readonly store32: 0x3e;
164
+ readonly eqz: 0x50;
165
+ readonly eq: 0x51;
166
+ readonly ne: 0x52;
167
+ readonly lt_s: 0x53;
168
+ readonly lt_u: 0x54;
169
+ readonly gt_s: 0x55;
170
+ readonly gt_u: 0x56;
171
+ readonly le_s: 0x57;
172
+ readonly le_u: 0x58;
173
+ readonly ge_s: 0x59;
174
+ readonly ge_u: 0x5a;
175
+ readonly clz: 0x79;
176
+ readonly ctz: 0x7a;
177
+ readonly popcnt: 0x7b;
178
+ readonly add: 0x7c;
179
+ readonly sub: 0x7d;
180
+ readonly mul: 0x7e;
181
+ readonly div_s: 0x7f;
182
+ readonly div_u: 0x80;
183
+ readonly rem_s: 0x81;
184
+ readonly rem_u: 0x82;
185
+ readonly and: 0x83;
186
+ readonly or: 0x84;
187
+ readonly xor: 0x85;
188
+ readonly shl: 0x86;
189
+ readonly shr_s: 0x87;
190
+ readonly shr_u: 0x88;
191
+ readonly rotl: 0x89;
192
+ readonly rotr: 0x8a;
193
+ readonly extend_i32_s: 0xac;
194
+ readonly extend_i32_u: 0xad;
195
+ readonly trunc_f32_s: 0xae;
196
+ readonly trunc_f32_u: 0xaf;
197
+ readonly trunc_f64_s: 0xb0;
198
+ readonly trunc_f64_u: 0xb1;
199
+ readonly reinterpret_f64: 0xbd;
200
+ };
201
+ f32: {
202
+ readonly const: 0x43;
203
+ readonly load: 0x2a;
204
+ readonly store: 0x38;
205
+ readonly eq: 0x5b;
206
+ readonly ne: 0x5c;
207
+ readonly lt: 0x5d;
208
+ readonly gt: 0x5e;
209
+ readonly le: 0x5f;
210
+ readonly ge: 0x60;
211
+ readonly abs: 0x8b;
212
+ readonly neg: 0x8c;
213
+ readonly ceil: 0x8d;
214
+ readonly floor: 0x8e;
215
+ readonly trunc: 0x8f;
216
+ readonly nearest: 0x90;
217
+ readonly sqrt: 0x91;
218
+ readonly add: 0x92;
219
+ readonly sub: 0x93;
220
+ readonly mul: 0x94;
221
+ readonly div: 0x95;
222
+ readonly min: 0x96;
223
+ readonly max: 0x97;
224
+ readonly copysign: 0x98;
225
+ readonly convert_i32_s: 0xb2;
226
+ readonly convert_i32_u: 0xb3;
227
+ readonly convert_i64_s: 0xb4;
228
+ readonly convert_i64_u: 0xb5;
229
+ readonly demote_f64: 0xb6;
230
+ readonly reinterpret_i32: 0xbe;
231
+ };
232
+ f64: {
233
+ readonly const: 0x44;
234
+ readonly load: 0x2b;
235
+ readonly store: 0x39;
236
+ readonly eq: 0x61;
237
+ readonly ne: 0x62;
238
+ readonly lt: 0x63;
239
+ readonly gt: 0x64;
240
+ readonly le: 0x65;
241
+ readonly ge: 0x66;
242
+ readonly abs: 0x99;
243
+ readonly neg: 0x9a;
244
+ readonly ceil: 0x9b;
245
+ readonly floor: 0x9c;
246
+ readonly trunc: 0x9d;
247
+ readonly nearest: 0x9e;
248
+ readonly sqrt: 0x9f;
249
+ readonly add: 0xa0;
250
+ readonly sub: 0xa1;
251
+ readonly mul: 0xa2;
252
+ readonly div: 0xa3;
253
+ readonly min: 0xa4;
254
+ readonly max: 0xa5;
255
+ readonly copysign: 0xa6;
256
+ readonly convert_i32_s: 0xb7;
257
+ readonly convert_i32_u: 0xb8;
258
+ readonly convert_i64_s: 0xb9;
259
+ readonly convert_i64_u: 0xba;
260
+ readonly promote_f32: 0xbb;
261
+ readonly reinterpret_i64: 0xbf;
262
+ };
263
+ local: {
264
+ readonly get: 0x20;
265
+ readonly set: 0x21;
266
+ readonly tee: 0x22;
267
+ };
268
+ readonly drop: 0x1a;
269
+ readonly call: 0x10;
270
+ readonly if: 0x04;
271
+ readonly else: 0x05;
272
+ readonly block: 0x02;
273
+ readonly loop: 0x03;
274
+ readonly br: 0x0c;
275
+ readonly br_if: 0x0d;
276
+ memory: {
277
+ readonly size: 0x3f;
278
+ readonly grow: 0x40;
279
+ };
280
+ readonly unreachable: 0x00;
281
+ global: {
282
+ readonly get: 0x23;
283
+ readonly set: 0x24;
284
+ };
285
+ readonly call_indirect: 0x11;
286
+ readonly nop: 0x01;
287
+ readonly br_table: 0x0e;
288
+ readonly return: 0x0f;
289
+ readonly select: 0x1b;
290
+ };
291
+ // End of autogenerated instruction types.
292
+
293
+ export const blocktype: {readonly empty: 0x40} & typeof valtype;
294
+
295
+ export type blocktype = typeof blocktype.empty | valtype | Fragment;
296
+
297
+ // Export section
298
+ // --------------
299
+
300
+ export const SECTION_ID_EXPORT: 7;
301
+
302
+ export function name(s: string): Fragment;
303
+
304
+ export function export_(nm: string, exportdesc: Fragment): Fragment;
305
+
306
+ export function exportsec(exports: readonly Fragment[]): Fragment;
307
+
308
+ export const exportdesc: {
309
+ func(idx: funcidx): Fragment;
310
+ mem(idx: memidx): Fragment;
311
+ };
312
+
313
+ // Module
314
+ // ------
315
+
316
+ export type WasmModule = Fragment;
317
+
318
+ export function module(sections: readonly Fragment[]): WasmModule;
319
+
320
+ export function flatten(fragment: Fragment): Uint8Array<ArrayBuffer>;
321
+
322
+ // Locals
323
+ // ------
324
+
325
+ export function locals(n: number, type: valtype): Fragment;
326
+
327
+ // Imports
328
+ // -------
329
+
330
+ export const SECTION_ID_IMPORT: 2;
331
+
332
+ export function import_(mod: string, nm: string, d: Fragment): Fragment;
333
+
334
+ export function importsec(ims: readonly Fragment[]): Fragment;
335
+
336
+ export const importdesc: {
337
+ func(x: typeidx): Fragment;
338
+ };
339
+
340
+ // Memory
341
+ // ------
342
+
343
+ export const SECTION_ID_MEMORY: 5;
344
+
345
+ export function memsec(mems: readonly Fragment[]): Fragment;
346
+
347
+ export function mem(memtype: Fragment): Fragment;
348
+
349
+ export function memtype(limits: Fragment): Fragment;
350
+
351
+ export const limits: {
352
+ min(n: number): Fragment;
353
+ minmax(n: number, m: number): Fragment;
354
+ };
355
+
356
+ export function memarg(align: number, offset: number): Fragment;
357
+
358
+ // Data / custom / names
359
+ // ---------------------
360
+
361
+ export const SECTION_ID_DATA: 11;
362
+
363
+ export function data(x: memidx, e: Fragment, bs: Bytes): Fragment;
364
+
365
+ export function datasec(segs: readonly Fragment[]): Fragment;
366
+
367
+ export const SECTION_ID_CUSTOM: 0;
368
+
369
+ export function custom(nameBytes: Fragment, payload: Fragment): Fragment;
370
+ export function customsec(custom: Fragment): Fragment;
371
+
372
+ export function namesec(namedata: Fragment): Fragment;
373
+
374
+ export function namedata(
375
+ modulenamesubsec: Fragment,
376
+ funcnamesubsec: Fragment,
377
+ localnamesubsec: Fragment,
378
+ ): Fragment;
379
+
380
+ export type NameSubsectionId =
381
+ | typeof CUSTOM_NAME_SUB_SEC_MODULE
382
+ | typeof CUSTOM_NAME_SUB_SEC_FUNC
383
+ | typeof CUSTOM_NAME_SUB_SEC_LOCAL;
384
+
385
+ export const CUSTOM_NAME_SUB_SEC_MODULE: 0;
386
+ export function modulenamesubsec(n: string): Fragment;
387
+
388
+ export const CUSTOM_NAME_SUB_SEC_FUNC: 1;
389
+ export function funcnamesubsec(namemap: Fragment): Fragment;
390
+
391
+ export function namesubsection(N: NameSubsectionId, B: Fragment): Fragment;
392
+
393
+ export function namemap(nameassocs: readonly Fragment[]): Fragment;
394
+
395
+ export function nameassoc(idx: idx, n: string): Fragment;
396
+
397
+ export const CUSTOM_NAME_SUB_SEC_LOCAL: 2;
398
+ export function localnamesubsec(indirectnamemap: Fragment): Fragment;
399
+
400
+ export function indirectnamemap(
401
+ indirectnameassocs: readonly Fragment[],
402
+ ): Fragment;
403
+
404
+ export function indirectnameassoc(idx: funcidx, namemap: Fragment): Fragment;
405
+
406
+ // Start section
407
+ // -------------
408
+
409
+ export const SECTION_ID_START: 8;
410
+
411
+ export function start(x: number): funcidx;
412
+
413
+ export function startsec(st: funcidx): Fragment;
414
+
415
+ // Globals
416
+ // -------
417
+
418
+ export const SECTION_ID_GLOBAL: 6;
419
+
420
+ export type mut = Brand<number, 'mut'>;
421
+
422
+ export const mut: {
423
+ const: mut;
424
+ var: mut;
425
+ };
426
+
427
+ export function globaltype(t: valtype, m: mut): Fragment;
428
+
429
+ export function global(gt: Fragment, e: Fragment): Fragment;
430
+
431
+ export function globalsec(globs: readonly Fragment[]): Fragment;
432
+
433
+ // Tables / elements
434
+ // -----------------
435
+
436
+ export const SECTION_ID_TABLE: 4;
437
+
438
+ export const elemtype: {
439
+ readonly funcref: 0x70;
440
+ };
441
+
442
+ export function tabletype(et: typeof elemtype.funcref, lim: Fragment): Fragment;
443
+
444
+ export function table(tt: Fragment): Fragment;
445
+
446
+ export function tablesec(tables: readonly Fragment[]): Fragment;
447
+
448
+ export const SECTION_ID_ELEMENT: 9;
449
+
450
+ export function elem(
451
+ x: tableidx,
452
+ e: Fragment,
453
+ ys: readonly funcidx[],
454
+ ): Fragment;
455
+
456
+ export function elemsec(segs: readonly Fragment[]): Fragment;
package/index.js CHANGED
@@ -1,5 +1,26 @@
1
1
  // WebAssembly 1.0 Module Builder
2
2
  // https://wasmgroundup.com/
3
+
4
+ function byteLength(fragment) {
5
+ let n = 0;
6
+ for (const item of fragment) {
7
+ if (Array.isArray(item)) n += byteLength(item);
8
+ else n += 1;
9
+ }
10
+ return n;
11
+ }
12
+
13
+ function writeInto(fragment, out, offset) {
14
+ for (const item of fragment) {
15
+ if (Array.isArray(item)) {
16
+ offset = writeInto(item, out, offset);
17
+ } else {
18
+ out[offset++] = item;
19
+ }
20
+ }
21
+ return offset;
22
+ }
23
+
3
24
  export function stringToBytes(s) {
4
25
  const bytes = new TextEncoder().encode(s);
5
26
  return Array.from(bytes);
@@ -86,7 +107,7 @@ export function i32(v) {
86
107
  }
87
108
 
88
109
  export function section(id, contents) {
89
- const sizeInBytes = contents.flat(Infinity).length;
110
+ const sizeInBytes = byteLength(contents);
90
111
  return [id, u32(sizeInBytes), contents];
91
112
  }
92
113
 
@@ -115,12 +136,16 @@ export function funcsec(typeidxs) {
115
136
  export const SECTION_ID_CODE = 10;
116
137
 
117
138
  export function code(func) {
118
- const sizeInBytes = func.flat(Infinity).length;
139
+ const sizeInBytes = byteLength(func);
119
140
  return [u32(sizeInBytes), func];
120
141
  }
121
142
 
122
- export function func(locals, body) {
123
- return [vec(locals), body];
143
+ export function func(locals, e) {
144
+ return [vec(locals), e];
145
+ }
146
+
147
+ export function expr(instrs) {
148
+ return [...instrs, instr.end];
124
149
  }
125
150
 
126
151
  export function codesec(codes) {
@@ -149,13 +174,19 @@ export const funcidx = (x) => u32(x);
149
174
 
150
175
  export const exportdesc = {
151
176
  func(idx) {
152
- return [0x00, funcidx(idx)];
177
+ return [0x00, idx];
153
178
  },
154
179
  };
155
180
 
156
181
  export function module(sections) {
157
182
  return [magic(), version(), sections];
158
183
  }
184
+
185
+ export function flatten(fragment) {
186
+ const out = new Uint8Array(byteLength(fragment));
187
+ writeInto(fragment, out, 0);
188
+ return out;
189
+ }
159
190
  export const valtype = {
160
191
  i32: 0x7f,
161
192
  i64: 0x7e,
@@ -226,7 +257,7 @@ export function importsec(ims) {
226
257
  export const importdesc = {
227
258
  // x:typeidx
228
259
  func(x) {
229
- return [0x00, typeidx(x)];
260
+ return [0x00, x];
230
261
  },
231
262
  };
232
263
  export const SECTION_ID_MEMORY = 5;
@@ -256,7 +287,7 @@ export const limits = {
256
287
 
257
288
  export const memidx = u32;
258
289
 
259
- exportdesc.mem = (idx) => [0x02, memidx(idx)];
290
+ exportdesc.mem = (idx) => [0x02, idx];
260
291
 
261
292
  instr.memory = {
262
293
  size: 0x3f, // [] -> [i32]
@@ -317,9 +348,8 @@ export function funcnamesubsec(namemap) {
317
348
 
318
349
  // N:byte
319
350
  export function namesubsection(N, B) {
320
- const flatB = B.flat(Infinity);
321
- const size = u32(flatB.length);
322
- return [N, size, flatB];
351
+ const size = u32(byteLength(B));
352
+ return [N, size, B];
323
353
  }
324
354
 
325
355
  export function namemap(nameassocs) {
package/package.json CHANGED
@@ -1,9 +1,20 @@
1
1
  {
2
2
  "name": "@wasmgroundup/emit",
3
3
  "description": "A library for creating binary-encoded WebAssembly modules",
4
- "version": "1.0.2",
4
+ "version": "2.1.0",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./index.d.ts",
11
+ "default": "./index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "index.js",
16
+ "index.d.ts"
17
+ ],
7
18
  "repository": {
8
19
  "type": "git",
9
20
  "url": "git+https://github.com/wasmgroundup/emit.git"
@@ -17,5 +28,16 @@
17
28
  "bugs": {
18
29
  "url": "https://github.com/wasmgroundup/emit/issues"
19
30
  },
20
- "homepage": "https://github.com/wasmgroundup/emit#readme"
21
- }
31
+ "homepage": "https://github.com/wasmgroundup/emit#readme",
32
+ "devDependencies": {
33
+ "@types/node": "^24.10.1",
34
+ "prettier": "^3.6.2",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "format": "npx prettier '**/*.{ts,js,json}' --write",
40
+ "test": "node --test",
41
+ "test:watch": "node --test --watch"
42
+ }
43
+ }
package/index.test.ts DELETED
@@ -1,229 +0,0 @@
1
- import { expect, test } from "bun:test";
2
-
3
- import {
4
- blocktype,
5
- code,
6
- codesec,
7
- export_,
8
- exportdesc,
9
- exportsec,
10
- func,
11
- funcidx,
12
- funcsec,
13
- functype,
14
- global,
15
- globalsec,
16
- globaltype,
17
- i32,
18
- import_,
19
- importdesc,
20
- importsec,
21
- instr,
22
- module,
23
- mut,
24
- typeidx,
25
- typesec,
26
- u32,
27
- valtype,
28
- } from "./index.js";
29
-
30
- function blocktype(t?: valtype): number {
31
- return t ?? 0x40;
32
- }
33
-
34
- function f64(v: number): number[] {
35
- var buf = new ArrayBuffer(8);
36
- new Float64Array(buf)[0] = v;
37
- return Array.from(new Uint8Array(buf));
38
- }
39
-
40
- const PI = 3.141592653589793115997963468544185161590576171875;
41
-
42
- function fragmentToUInt8Array(frag): Uint8Array {
43
- return Uint8Array.from((frag as any).flat(Infinity));
44
- }
45
-
46
- test("u32", () => {
47
- expect(u32(32768)).toEqual([128, 128, 2]);
48
- expect(u32(2 ** 32 - 1)).toEqual([255, 255, 255, 255, 15]);
49
- });
50
-
51
- test("i32", () => {
52
- expect(i32(32768)).toEqual([128, 128, 2]);
53
- expect(i32(2 ** 31 - 1)).toEqual([255, 255, 255, 255, 7]);
54
- expect(i32(-(2 ** 31 - 1))).toEqual([129, 128, 128, 128, 120]);
55
- });
56
-
57
- test("simple modules", async () => {
58
- const makeModule = (paramTypes, resultTypes, body) => {
59
- const mod = module([
60
- typesec([functype(paramTypes, resultTypes)]),
61
- funcsec([typeidx(0)]),
62
- exportsec([export_("main", exportdesc.func(0))]),
63
- codesec([code(func([], body))]),
64
- ]);
65
- return fragmentToUInt8Array(mod);
66
- };
67
- const runMain = async (bytes, args) => {
68
- const { instance } = await WebAssembly.instantiate(bytes);
69
- return instance.exports.main(...args);
70
- };
71
-
72
- // () => ()
73
- expect(await runMain(makeModule([], [], [instr.end]), [])).toBe(undefined);
74
-
75
- // () => i32
76
- expect(
77
- await runMain(
78
- makeModule([], [valtype.i32], [instr.i32.const, 1, instr.end]),
79
- [],
80
- ),
81
- ).toBe(1);
82
-
83
- // (i32) => i32
84
- expect(
85
- await runMain(
86
- makeModule([valtype.i32], [valtype.i32], [instr.local.get, 0, instr.end]),
87
- [1],
88
- ),
89
- ).toBe(1);
90
- expect(
91
- await runMain(
92
- makeModule([valtype.i32], [valtype.i32], [instr.local.get, 0, instr.end]),
93
- [99],
94
- ),
95
- ).toBe(99);
96
- });
97
-
98
- test("imports", async () => {
99
- const makeModule = () => {
100
- const mod = module([
101
- typesec([functype([valtype.i32], [valtype.i32])]),
102
- importsec([import_("builtins", "addOne", importdesc.func(0))]),
103
- funcsec([typeidx(0)]),
104
- exportsec([export_("main", exportdesc.func(1))]),
105
- codesec([
106
- code(func([], [instr.local.get, 0, instr.call, funcidx(0), instr.end])),
107
- ]),
108
- ]);
109
- return fragmentToUInt8Array(mod);
110
- };
111
-
112
- const { instance } = await WebAssembly.instantiate(makeModule(), {
113
- builtins: {
114
- addOne(x) {
115
- return x + 1;
116
- },
117
- },
118
- });
119
-
120
- expect(instance.exports.main(1)).toBe(2);
121
- expect(instance.exports.main(2)).toBe(3);
122
- });
123
-
124
- test("f64", async () => {
125
- const makeModule = () => {
126
- const mod = module([
127
- typesec([functype([], [valtype.f64])]),
128
- funcsec([typeidx(0), typeidx(0), typeidx(0)]),
129
- exportsec([
130
- export_("pi", exportdesc.func(0)),
131
- export_("nan", exportdesc.func(1)),
132
- export_("one", exportdesc.func(2)),
133
- ]),
134
- codesec([
135
- code(func([], [instr.f64.const, f64(PI), instr.end])),
136
- code(func([], [instr.f64.const, f64(Number.NaN), instr.end])),
137
- code(func([], [instr.f64.const, f64(1), instr.end])),
138
- ]),
139
- ]);
140
- return fragmentToUInt8Array(mod);
141
- };
142
- const { instance } = await WebAssembly.instantiate(makeModule());
143
- expect(instance.exports.pi()).toBe(PI);
144
- expect(instance.exports.nan()).toBe(Number.NaN);
145
- expect(instance.exports.one()).toBe(1);
146
- });
147
-
148
- test("globals", async () => {
149
- const makeModule = () => {
150
- const mod = module([
151
- typesec([
152
- functype([], [valtype.f64]), // pi
153
- functype([], [valtype.i32]), // getVar
154
- functype([], []), // incVar
155
- ]),
156
- funcsec([typeidx(0), typeidx(1), typeidx(2)]),
157
- globalsec([
158
- global(globaltype(valtype.f64, mut.const), [
159
- instr.f64.const,
160
- f64(PI),
161
- instr.end,
162
- ]),
163
- global(globaltype(valtype.i32, mut.var), [
164
- instr.i32.const,
165
- i32(0),
166
- instr.end,
167
- ]),
168
- ]),
169
- exportsec([
170
- export_("pi", exportdesc.func(0)),
171
- export_("getVar", exportdesc.func(1)),
172
- export_("incVar", exportdesc.func(2)),
173
- ]),
174
- codesec([
175
- code(func([], [instr.global.get, 0, instr.end])), // pi
176
- code(func([], [instr.global.get, 1, instr.end])), // getVar
177
- code(
178
- // prettier-ignore
179
- func([], [
180
- instr.global.get, 1,
181
- instr.i32.const, 1,
182
- instr.i32.add,
183
- instr.global.set, 1,
184
- instr.end,
185
- ],
186
- ),
187
- ), // incVar
188
- ]),
189
- ]);
190
- return fragmentToUInt8Array(mod);
191
- };
192
-
193
- const { exports } = (await WebAssembly.instantiate(makeModule())).instance;
194
- expect(exports.pi()).toBe(PI);
195
- expect(exports.getVar()).toBe(0);
196
- exports.incVar();
197
- expect(exports.getVar()).toBe(1);
198
- });
199
-
200
- test("if", async () => {
201
- const makeModule = () => {
202
- const mod = module([
203
- typesec([functype([valtype.i32], [valtype.f64])]),
204
- funcsec([typeidx(0)]),
205
- exportsec([export_("maybePi", exportdesc.func(0))]),
206
- codesec([
207
- code(
208
- func(
209
- [],
210
- // prettier-ignore
211
- [
212
- instr.local.get, 0,
213
- instr.if, blocktype(valtype.f64),
214
- instr.f64.const, f64(PI),
215
- instr.else,
216
- instr.f64.const, f64(0),
217
- instr.end,
218
- instr.end,
219
- ],
220
- ),
221
- ),
222
- ]),
223
- ]);
224
- return fragmentToUInt8Array(mod);
225
- };
226
- const { exports } = (await WebAssembly.instantiate(makeModule())).instance;
227
- expect(exports.maybePi(1)).toBe(PI);
228
- expect(exports.maybePi(0)).toBe(0);
229
- });