wat4wasm 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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/examples/01-text/module-output.wat +228 -0
  4. package/examples/01-text/module.wat +9 -0
  5. package/examples/02-include/module-output.wat +22 -0
  6. package/examples/02-include/module.wat +3 -0
  7. package/examples/02-include/used-folder/included-file.wat +4 -0
  8. package/examples/03-ref.extern/module-output.wat +1537 -0
  9. package/examples/03-ref.extern/module.wat +33 -0
  10. package/examples/04-ref.func/module-output.wat +25 -0
  11. package/examples/04-ref.func/module.wat +8 -0
  12. package/examples/05-global.get/module-output.wat +991 -0
  13. package/examples/05-global.get/module.wat +26 -0
  14. package/examples/06-async/module-output.wat +661 -0
  15. package/examples/06-async/module.wat +15 -0
  16. package/examples/07-data/module-output.wasm +0 -0
  17. package/examples/07-data/module.wat +29 -0
  18. package/examples/07-data/used-folder/clear-text.txt +1 -0
  19. package/examples/07-data/used-folder/compile-this.wat +8 -0
  20. package/examples/08-reflectors/how-to/README.md +0 -0
  21. package/examples/08-reflectors/how-to/output-01-command.sh +0 -0
  22. package/examples/08-reflectors/how-to/output-02-command.sh +0 -0
  23. package/examples/08-reflectors/how-to/output-03-command.sh +0 -0
  24. package/examples/08-reflectors/how-to/output-04-command.sh +0 -0
  25. package/examples/08-reflectors/how-to/wat4wasm-outputs/01-module.wat +3 -0
  26. package/examples/08-reflectors/how-to/wat4wasm-outputs/02-module.wasm +3 -0
  27. package/examples/08-reflectors/how-to/wat4wasm-outputs/03-module.js +0 -0
  28. package/examples/08-reflectors/how-to/wat4wasm-outputs/04-module.html +0 -0
  29. package/examples/08-reflectors/module-output.wat +995 -0
  30. package/examples/08-reflectors/module.wat +108 -0
  31. package/examples/09-replaceAll/module-output.wat +347 -0
  32. package/examples/09-replaceAll/module.wat +68 -0
  33. package/examples/99-complex/module.wat +8 -0
  34. package/examples/99-complex/output.html +1 -0
  35. package/examples/99-complex/sub/worker.wat +2 -0
  36. package/examples/shell-usages.sh +60 -0
  37. package/lib/build +33 -0
  38. package/lib/clean.js +91 -0
  39. package/lib/cli.js +273 -0
  40. package/lib/helpers.js +567 -0
  41. package/lib/index.js +95 -0
  42. package/lib/processors/async.js +53 -0
  43. package/lib/processors/data.js +188 -0
  44. package/lib/processors/import.js +178 -0
  45. package/lib/processors/include.js +17 -0
  46. package/lib/processors/new.js +21 -0
  47. package/lib/processors/ref_extern.js +64 -0
  48. package/lib/processors/ref_func.js +44 -0
  49. package/lib/processors/replace_all.js +56 -0
  50. package/lib/processors/start.js +42 -0
  51. package/lib/processors/string.js +57 -0
  52. package/lib/processors/text.js +115 -0
  53. package/lib/processors/wat4wasm.js +285 -0
  54. package/lib/wat4beauty.js +320 -0
  55. package/package.json +30 -0
  56. package/ss-console.png +0 -0
  57. package/ss-terminal.png +0 -0
  58. package/test/boot.wat +5 -0
  59. package/test/test-output.html +1 -0
  60. package/test/test-output.js +27 -0
  61. package/test/test-output.wasm +0 -0
  62. package/test/test-sub.wat +4 -0
  63. package/test/test.wat +73 -0
  64. package/test/test_worker.js +1 -0
  65. package/wat4wasm +1998 -0
package/lib/helpers.js ADDED
@@ -0,0 +1,567 @@
1
+ import fs from "fs";
2
+ import cp from "child_process";
3
+
4
+ const helpers = {
5
+
6
+ hasProtocol(str) {
7
+ return str?.includes("://");
8
+ },
9
+
10
+ parseProtoPath(path) {
11
+ const [protocol, fullpath, filename, basename, extension] = path.match(/([a-z0-9]+\:\/\/)((?:(?:.*)\/)*((.[^\/]*)\.(.[^\.]*)))/).slice(1);
12
+ const directory = fullpath.substring(0, fullpath.length - filename.length)
13
+ return { protocol, fullpath, directory, filename, basename, extension };
14
+ },
15
+
16
+ readFileAsText(fullpath) {
17
+ return fs.readFileSync(fullpath, "utf8");
18
+ },
19
+
20
+ readFileAsHex(fullpath) {
21
+ const data = fs.readFileSync(fullpath, "hex").replaceAll(/(..)/g, `\\$1`);
22
+ const size = data.length / 3;
23
+ return { data, size };
24
+ },
25
+
26
+ unlinkFile(path) {
27
+ return fs.unlinkSync(path);
28
+ },
29
+
30
+ copyFile(path, topath) {
31
+ return fs.cpSync(path, topath);
32
+ },
33
+
34
+ spawnSync(command, argv) {
35
+ return cp.spawnSync(command, argv, { stdio: "inherit" });
36
+ },
37
+
38
+ blockAt(raw, begin) {
39
+ raw = raw.toString();
40
+
41
+ if ((begin === -1) || !(raw = raw.substring(begin))) {
42
+ return "";
43
+ }
44
+
45
+ let maskUsed = raw.includes("\\)");
46
+ if (maskUsed) {
47
+ maskUsed = `__RAND${Math.random()}__`;
48
+ raw = raw.replaceAll("\\)", maskUsed);
49
+ }
50
+
51
+ let end = begin = 0, block = raw;
52
+
53
+ end = raw.indexOf(")", end);
54
+ block = raw.substring(begin, ++end);
55
+
56
+ while (block && (
57
+ block.split("(").length !==
58
+ block.split(")").length)
59
+ ) {
60
+ end = raw.indexOf(")", end);
61
+ block = raw.substring(begin, ++end);
62
+ }
63
+
64
+ if (maskUsed && block) {
65
+ block = block.replaceAll(maskUsed, "\\)");
66
+ }
67
+
68
+ return block;
69
+ },
70
+
71
+
72
+ rawContent(block) {
73
+ let raw = block.toString().trim();
74
+ let begin;
75
+
76
+ if (raw.startsWith("(")) {
77
+ raw = raw.substring(1);
78
+
79
+ while (raw && raw.at(0).match(/[a-z0-9\.\_\(\)]/)) {
80
+ raw = raw.substring(1);
81
+ }
82
+
83
+ raw = raw.trim();
84
+
85
+ if (raw.startsWith("$")) {
86
+ while (raw && raw.at(0).match(/[a-z0-9A-Z\:\.\<\>\/\_\+\-\`\[\]\$\=\#\!]/)) {
87
+ raw = raw.substring(1)
88
+ }
89
+ }
90
+
91
+ raw = raw.trim();
92
+ }
93
+
94
+ raw = raw.trim();
95
+
96
+ if (raw.endsWith(")")) {
97
+ raw = raw.substring(0, raw.length - 1)
98
+
99
+ while (raw && !raw.at(-1).trim()) {
100
+ raw = raw.substring(0, raw.length - 1)
101
+ }
102
+ }
103
+
104
+ raw = raw.trim();
105
+
106
+ return raw;
107
+ },
108
+
109
+ blockContent(block) {
110
+ let raw = this.rawContent(block);
111
+
112
+ while (raw.startsWith("(type")) { raw = raw.substring(raw.indexOf(")") + 1).trim(); }
113
+ while (raw.startsWith("(param")) { raw = raw.substring(raw.indexOf(")") + 1).trim(); }
114
+ while (raw.startsWith("(result")) { raw = raw.substring(raw.indexOf(")") + 1).trim(); }
115
+ while (raw.startsWith("(local")) { raw = raw.substring(raw.indexOf(")") + 1).trim(); }
116
+
117
+ raw = raw.trim();
118
+
119
+ return raw;
120
+ },
121
+
122
+ containsMemoryOperation(raw) {
123
+ return raw.toString().split(/(memory|i32|f32|i64|f64|v128)(\.)(init|load|store|atomic|fill|drop)/).length > 1;
124
+ },
125
+
126
+ prepend(raw, block) {
127
+ raw = raw.toString();
128
+ block = block.toString().trim().concat("\n\n");
129
+
130
+ if (raw.startsWith("(module")) {
131
+ return String(`(module\n${block}\n`).concat(
132
+ raw.substring("(module".length).trimStart()
133
+ )
134
+ }
135
+
136
+ if (raw.replaceAll(/\s+/g, '').match(/\(([a-z0-9\.\_]+)\)/)) {
137
+ return raw.substring(0, raw.length - 1).concat(block).concat(`)`);
138
+ }
139
+
140
+ let begin;
141
+ begin = raw.indexOf("(", 1);
142
+
143
+ let headmatch = true;
144
+ while (headmatch) {
145
+ if (headmatch = raw.substring(begin).startsWith("(param")) { begin = raw.indexOf("(", ++begin); continue; }
146
+ if (headmatch = raw.substring(begin).startsWith("(result")) { begin = raw.indexOf("(", ++begin); continue; }
147
+ if (headmatch = raw.substring(begin).startsWith("(local")) { begin = raw.indexOf("(", ++begin); continue; }
148
+ if (headmatch = raw.substring(begin).startsWith("(type")) { begin = raw.indexOf("(", ++begin); continue; }
149
+ }
150
+
151
+ if (begin !== -1) {
152
+ return raw.substring(0, begin).concat(block).concat(raw.substring(begin))
153
+ }
154
+
155
+ const blockparts = raw.split(/\s+/).filter(Boolean);
156
+ if (blockparts.length === 1) {
157
+ return this.append(raw, block);
158
+ }
159
+
160
+ const maybe$name = blockparts.at(1);
161
+ if (maybe$name.startsWith("$")) {
162
+ if (maybe$name.endsWith(")")) {
163
+ return this.append(raw, block);
164
+ }
165
+ }
166
+
167
+ const [firstLine, ...restLines] = raw.split(/\n/g);
168
+ return [firstLine, block, ...restLines].join("\n");
169
+ },
170
+
171
+
172
+ append(raw, block) {
173
+ raw = raw.toString();
174
+ return raw.substring(0, raw.lastIndexOf(")")).concat(`\n${block || ''}\n)`);
175
+ },
176
+
177
+ findQuotedTexts(rawBlock, maxcount = -1) {
178
+ let maskUsed = rawBlock.includes('\\"');
179
+ if (maskUsed) {
180
+ maskUsed = `__RAND${Math.random()}__`;
181
+ rawBlock = rawBlock.replaceAll('\\"', maskUsed);
182
+ }
183
+
184
+ let texts = [];
185
+ let begin = rawBlock.indexOf(`"`);
186
+ let end = rawBlock.indexOf(`"`, begin + 1);
187
+
188
+ while (maxcount-- && begin !== -1) {
189
+ texts.push(rawBlock.substring(begin + 1, end));
190
+ begin = rawBlock.indexOf('"', end + 1);
191
+ end = rawBlock.indexOf(`"`, begin + 1);
192
+ }
193
+
194
+ if (maskUsed) {
195
+ texts = texts.map(t => t.replaceAll(maskUsed, "\\)"));
196
+ }
197
+
198
+ return texts;
199
+ },
200
+
201
+ findQuotedText(rawBlock) {
202
+ return this.findQuotedTexts(rawBlock, 1).at(0);
203
+ },
204
+
205
+ encodeText: TextEncoder.prototype.encode.bind(new TextEncoder),
206
+ encodeString: str => Array.from(str || '').map(c => c.charCodeAt()),
207
+
208
+ fix$Name(keyword, self = false) {
209
+ if (keyword.startsWith("$") === false) {
210
+ return `$${keyword}`;
211
+ }
212
+
213
+ if (self && keyword.startsWith("$self") === false) {
214
+ return `$self.${keyword.substring(1)}`;
215
+ }
216
+
217
+ return keyword;
218
+ },
219
+
220
+ fixBlockKeyword(keyword, filter = {}) {
221
+ if (keyword.split(/\s/).length > 1) {
222
+ throw new Error(`Given keyword is wrong: ${keyword}`)
223
+ }
224
+
225
+ if (filter.$name) {
226
+ keyword = `${keyword} ${filter.$name}`;
227
+ }
228
+
229
+ if (filter.name) {
230
+ keyword = `${keyword} $${filter.name}`;
231
+ }
232
+
233
+ if (keyword.startsWith("(") === false) {
234
+ return `(${keyword}`;
235
+ }
236
+ return keyword;
237
+ },
238
+
239
+ getBlockKeyword(block) {
240
+ let keyword = block;
241
+
242
+ if (keyword.startsWith("(") === true) {
243
+ keyword = keyword.substring(1);
244
+ }
245
+
246
+ let i = 0;
247
+ while (keyword.at(i++).match(/[a-z0-9\_\.]/));;
248
+ return keyword.substring(0, i);
249
+ },
250
+
251
+ getBlockRootTag(block) {
252
+ return this.getBlockKeyword(block).split(".").at(0);
253
+ },
254
+
255
+ getBlockRootTagType(block) {
256
+ return this.getBlockRootTag(block).match(/(i32|f32|i64|f64)/)?.at(0) || "ext";
257
+ },
258
+
259
+ getTableOperator(block) {
260
+ let [match, $name = "", initial = "", maximum = "", kindof = "externref"] = block.toString().match(/\(table(?:\s*(.[^\s]*)?)\s+(\d+)(?:\s*(\d+)?)\s+(externref|funcref)\)/) ?? [];
261
+
262
+ initial = parseInt(initial);
263
+ maximum = parseInt(maximum);
264
+
265
+ return {
266
+ $name, initial, maximum, kindof,
267
+ grow: function (count = 1) {
268
+ return {
269
+ newTableBlock: `(table ${[$name, initial + count, maximum, kindof].filter(Boolean).join(" ").trim()})`,
270
+ getTableBlock: `(table.get ${[$name, `(i32.const ${initial})`].join(" ").trim()})`
271
+ };
272
+ }
273
+ };
274
+ },
275
+
276
+ clearExceptKnown(raw) {
277
+ return `${raw || ''}`.trim().split(/\n/)
278
+ .map(l => l.replaceAll(/\s+/g, " "))
279
+ .map(l => l.replace(/;;.*/g, ""))
280
+ .map(l => l.replaceAll(/\(;(.*);\)/g, ""))
281
+ .filter(l => l.replaceAll(/\s+/g, "").trim())
282
+ .join(" ").replaceAll(/\s+(\)|\()/g, `$1`)
283
+ ;
284
+ },
285
+
286
+ generateId(raw) {
287
+ let sum = 0;
288
+
289
+ this.clearExceptKnown(raw)
290
+ .split("").map((c, i) => sum += c.charCodeAt() * i);
291
+
292
+ return sum;
293
+ },
294
+
295
+ abstract(str, max = 15) {
296
+ str = `${str || ''}`.replaceAll(/\s+/g, ' ').replaceAll(/\s+\)/g, ")");
297
+ if (str.length < max) return str;
298
+ return `${str.substring(0, max / 3)} ... ${str.substring(str.length - max / 3)}`
299
+ },
300
+
301
+ createTableGetter(index, kindof = "extern") {
302
+ return `(ref.null (;${index};) ${kindof})`;
303
+ },
304
+
305
+ referenceId() {
306
+ return "0x" + crypto.randomUUID().replace(/\-/g, "");
307
+ },
308
+
309
+ hasBlock(raw, keyword, filter) {
310
+ if (!keyword) { return raw.indexOf("(", 1) !== -1; };
311
+ keyword = this.fixBlockKeyword(keyword, filter);
312
+ return raw.includes(keyword);
313
+ },
314
+
315
+ hasAnyBlock(raw) {
316
+ return this.hasBlock(raw);
317
+ },
318
+
319
+ MaskSet: class MaskSet extends Map {
320
+
321
+ constructor(raw) {
322
+ raw = (raw || '').toString().trim();
323
+ Reflect.defineProperty(super(), "input", { value: raw, writable: true })
324
+ }
325
+
326
+ remove(block) {
327
+ if (!block || !block?.uuid) { return this.input; };
328
+
329
+ if (this.has(block.uuid) !== false) {
330
+ this.delete(block.uuid);
331
+ }
332
+
333
+ return this.mask(block, "");
334
+ }
335
+
336
+ mask(block, maskWith = block.uuid) {
337
+ if (!block.uuid) {
338
+ throw new Error(`Raw block needs uuid: ${block}`);
339
+ };
340
+
341
+ if (this.has(block.uuid) === false) {
342
+ this.set(block.uuid, block);
343
+ }
344
+
345
+ const rawRange = this.input.substring(
346
+ block.begin, block.end
347
+ );
348
+
349
+ if (block.toString() !== rawRange) {
350
+ console.error({ block, rawRange })
351
+ throw new Error(`Raw block pointer range is not matched!`);
352
+ };
353
+
354
+ this.input = this.input
355
+ .substring(0, block.begin)
356
+ .concat(block.maskWith = maskWith)
357
+ .concat(this.input.substring(block.end))
358
+ ;
359
+ }
360
+
361
+ unmask(block) {
362
+ this.input = this.input.replaceAll(block.uuid, block.toString());
363
+ return this;
364
+ }
365
+
366
+ lastBlockOf(keyword, filter) {
367
+ return helpers.lastBlockOf(this.input, keyword, filter);
368
+ }
369
+
370
+ hasBlock(keyword, filter) {
371
+ return helpers.hasBlock(this.input, keyword, filter);
372
+ }
373
+
374
+ update(oldBlock, newBlock) {
375
+ this.set(oldBlock.uuid, newBlock);
376
+ }
377
+
378
+ get hasAnyBlock() {
379
+ return this.input.trim().indexOf("(", 1) !== -1;
380
+ }
381
+
382
+ parseFirstBlock() {
383
+ return helpers.parseFirstBlock(this.input);
384
+ }
385
+
386
+ refresh() {
387
+ this.input = this.restoreInto(this.input);
388
+ return this;
389
+ }
390
+
391
+ restore() {
392
+ return this.refresh().restoreInto();
393
+ }
394
+
395
+ toString() {
396
+ return this.input;
397
+ }
398
+
399
+ [Symbol.toPrimitive]() {
400
+ return this.toString();
401
+ }
402
+
403
+ get rawContent() {
404
+ return helpers.rawContent(this.restore())
405
+ }
406
+
407
+ get blockContent() {
408
+ return helpers.blockContent(this.restore())
409
+ }
410
+
411
+ restoreInto(raw = this.input) {
412
+ const masks = Array.from(this.keys());
413
+ const uuid = masks.find(uuid => raw.includes(uuid));
414
+
415
+ if (uuid) {
416
+ const block = this.get(uuid);
417
+ raw = raw.replaceAll(uuid, block.toString());
418
+ return this.restoreInto(raw);
419
+ }
420
+
421
+ return raw;
422
+ }
423
+
424
+ generateId() {
425
+ return helpers.generateId(this.restore())
426
+ }
427
+ },
428
+
429
+ nameSignatureofGlobal($name) {
430
+ return String($name || '')
431
+ .match(/\$(.[^<]*)(?:\<(.[^>]*)\>)?/)?.slice(1) || [];
432
+ },
433
+
434
+ assignBlockProperties(raw, block, begin) {
435
+ if (begin === -1) return null;
436
+
437
+ let $name = block.split(/[^a-z0-9A-Z\:\.\<\>\/\_\+\-\`\[\]\$\=\#\!\*]/g).filter(Boolean).at(1) || "";
438
+
439
+ let isGetter = false;
440
+ let isSetter = false;
441
+ let descriptorKey = "value";
442
+
443
+ if ($name.startsWith("$") === false) {
444
+ $name = "";
445
+ }
446
+
447
+ if ($name.includes("[")) {
448
+ descriptorKey = $name.substring(
449
+ $name.indexOf("[") + 1,
450
+ $name.indexOf("]")
451
+ );
452
+ $name = $name.substring(0, $name.indexOf("[")).concat("/").concat(descriptorKey);
453
+ }
454
+
455
+ isGetter = descriptorKey === "get";
456
+ isSetter = descriptorKey === "set";
457
+
458
+ $name = $name
459
+ .replaceAll(":", ".prototype.")
460
+ .replaceAll(".TypedArray", ".Uint8Array.__proto__")
461
+ ;
462
+
463
+ return block && Object.defineProperties({
464
+ block: `${block}`,
465
+ begin,
466
+ uuid: crypto.randomUUID(),
467
+ end: begin + block.length,
468
+ $name: $name || "",
469
+ toString: function () { return this.block; },
470
+ wrappedRaws: function () {
471
+ return {
472
+ before: this.input.substring(0, this.begin),
473
+ after: this.input.substring(this.end)
474
+ }
475
+ },
476
+ maskedRaw: function () { return this.replacedRaw(this.uuid); },
477
+ removedRaw: function () { return this.replacedRaw(""); },
478
+ replacedRaw: function (str) {
479
+ const { before, after } = this.wrappedRaws();
480
+ return before.concat(str.toString()).concat(after);
481
+ },
482
+ }, {
483
+ isGetter: { value: isGetter },
484
+ isSetter: { value: isSetter },
485
+ descriptorKey: { value: descriptorKey },
486
+ input: { value: raw },
487
+ hasBlock: { value: function (keyword, filter) { return helpers.hasBlock(this.toString(), keyword, filter); } },
488
+ blockName: {
489
+ get: function () {
490
+ let rawContent = this.toString().trim();
491
+ let begin;
492
+ let blockName = ``;
493
+
494
+ if (rawContent.startsWith("(")) {
495
+ rawContent = rawContent.substring(1);
496
+ while (rawContent && rawContent.at(0).match(/[a-z0-9\.\_]/)) {
497
+ blockName = blockName + rawContent.at(0)
498
+ rawContent = rawContent.substring(1);
499
+ }
500
+ }
501
+
502
+ return blockName;
503
+ }
504
+ },
505
+ generateId: { value: function () { return helpers.generateId(this.toString()) } },
506
+ name: { get: function () { return `${this.$name}`.substring(1); } },
507
+ rawContent: { get: function () { return helpers.rawContent(this.toString()) } },
508
+ blockContent: { get: function () { return helpers.blockContent(this.toString()) } },
509
+ hasAnyBlock: { get: function () { return helpers.hasAnyBlock(this.toString()) } },
510
+ indexOf: { value: function () { return this.block.indexOf(...arguments) } },
511
+ includes: { value: function () { return this.block.includes(...arguments) } },
512
+ lastIndexOf: { value: function () { return this.block.lastIndexOf(...arguments) } },
513
+ split: { value: function () { return this.block.split(...arguments) } },
514
+ at: { value: function () { return this.block.at(...arguments) } },
515
+ length: { get: function () { return this.block.length } },
516
+ charCodeAt: { value: function () { return this.block.charCodeAt(...arguments) } },
517
+ concat: { value: function () { return this.block.concat(...arguments) } },
518
+ startsWith: { value: function () { return this.block.startsWith(...arguments) } },
519
+ endsWith: { value: function () { return this.block.endsWith(...arguments) } },
520
+ substring: { value: function () { return this.block.substring(...arguments) } },
521
+ replace: { value: function () { return this.block.replace(...arguments) } },
522
+ replaceAll: { value: function () { return this.block.replaceAll(...arguments) } },
523
+ lastBlockOf: { value: function () { return helpers.lastBlockOf(this.block, ...arguments) } },
524
+ [Symbol.toPrimitive]: { value: function () { return this.block; } },
525
+ })
526
+ },
527
+
528
+ lastBlockOf(raw, keyword, filter) {
529
+ if (!raw) throw new Error(`no raw for block: ${keyword}`);
530
+
531
+ keyword = this.fixBlockKeyword(keyword, filter);
532
+ raw = raw.toString();
533
+
534
+ let begin = raw.lastIndexOf(keyword);
535
+ const block = this.parseBlockAt(raw, begin);
536
+
537
+ return block;
538
+ },
539
+
540
+ firstBlockOf(raw, keyword, filter) {
541
+ if (!raw) throw new Error(`no raw for block: ${keyword}`);
542
+
543
+ keyword = this.fixBlockKeyword(keyword, filter);
544
+ raw = raw.toString();
545
+
546
+ let begin = raw.indexOf(keyword);
547
+ const block = this.parseBlockAt(raw, begin);
548
+
549
+ return block;
550
+ },
551
+
552
+
553
+ parseBlockAt(raw, begin) {
554
+ return this.assignBlockProperties(raw, this.blockAt(raw, begin), begin);
555
+ },
556
+
557
+ parseBlock(raw) {
558
+ return this.parseFirstBlock(raw);
559
+ },
560
+
561
+ parseFirstBlock(raw) {
562
+ raw = raw.toString();
563
+ return this.parseBlockAt(raw, raw.indexOf("(", 1));
564
+ }
565
+ };
566
+
567
+ export default helpers;
package/lib/index.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "fs";
4
+ import wat4beauty from "./wat4beauty.js"
5
+
6
+ import { processCLI } from "./cli.js";
7
+ import clean from "./clean.js";
8
+
9
+ import ASYNC from "./processors/async.js"
10
+ import DATA from "./processors/data.js"
11
+ import IMPORT from "./processors/import.js"
12
+ import INCLUDE from "./processors/include.js"
13
+ import NEW from "./processors/new.js"
14
+ import REF_EXTERN from "./processors/ref_extern.js"
15
+ import REF_FUNC from "./processors/ref_func.js"
16
+ import REPLACE_ALL from "./processors/replace_all.js"
17
+ import START from "./processors/start.js"
18
+ import STRING from "./processors/string.js"
19
+ import TEXT from "./processors/text.js"
20
+ import W4W from "./processors/wat4wasm.js"
21
+
22
+ const processors = [
23
+ W4W,
24
+ TEXT,
25
+ ASYNC,
26
+ DATA,
27
+ IMPORT,
28
+ INCLUDE,
29
+ NEW,
30
+ REF_EXTERN,
31
+ REF_FUNC,
32
+ START,
33
+ STRING,
34
+ REPLACE_ALL,
35
+ ];
36
+
37
+
38
+ processCLI(async wat4 => {
39
+ let wat2 = wat4, f, i = -1, llen, m = -1, c = 0, ci = 0;
40
+
41
+ while (f = processors[++i]) {
42
+ wat4 = f(wat2, W4W).toString();
43
+
44
+ const input = wat2;
45
+ const output = wat4;
46
+ const inLines = input.split("\n").map(l => l.trim()).filter(Boolean);
47
+ const outLines = output.split("\n").map(l => l.trim()).filter(Boolean);
48
+
49
+ let startCommon = 0;
50
+ while (
51
+ startCommon < inLines.length &&
52
+ startCommon < outLines.length &&
53
+ inLines[startCommon] === outLines[startCommon]
54
+ ) { startCommon++; }
55
+
56
+ let endCommon = 0;
57
+ while (
58
+ endCommon < inLines.length - startCommon &&
59
+ endCommon < outLines.length - startCommon &&
60
+ inLines[inLines.length - 1 - endCommon] === outLines[outLines.length - 1 - endCommon]
61
+ ) { endCommon++; }
62
+
63
+ const commonLines = startCommon + endCommon;
64
+ const removedLines = inLines.length - commonLines;
65
+ const addedLines = outLines.length - commonLines;
66
+ const netChange = outLines.length - inLines.length;
67
+
68
+ const stat = [
69
+ `\x1b[32m+${addedLines}\x1b[0m`.padStart(15, " "),
70
+ `\x1b[34m-${removedLines}\x1b[0m`.padStart(15, " "),
71
+ `\x1b[${netChange && 36 || 33}m\u0394\x1b[0m`.padStart(12, " "),
72
+ `\x1b[${netChange && 36 || 33}m${netChange}\x1b[0m`.padStart(12, " "),
73
+ ` byte(\u03B4) :`,
74
+ `\x1b[33m${wat2.length}\x1b[0m`.padStart(14, " "),
75
+ `-->`,
76
+ `\x1b[33m${wat4.length}\x1b[0m`,
77
+ ];
78
+
79
+ if (wat2 !== wat4) {
80
+ c++;
81
+ wat2 = wat4;
82
+ console.log(`👀 ƒ( ${f.name.padEnd(12, " ")} )`.padStart(12, " "), ...stat);
83
+ }
84
+
85
+ if (!processors[i + 1]) {
86
+ if (c) { i = -1; c = 0; }
87
+ else { console.log("☘️ untouched raw \x1b[32m-->\x1b[0m finalizing..") }
88
+ }
89
+ }
90
+
91
+ wat2 = clean(wat2);
92
+ wat2 = wat4beauty(wat2, " ");
93
+
94
+ return wat2;
95
+ });
@@ -0,0 +1,53 @@
1
+ import helpers from "../helpers.js"
2
+
3
+ export const ASYNC_BLOCK_NAME = "async";
4
+
5
+ export default function (wat, WAT4WASM) {
6
+
7
+ const maskSet = new helpers.MaskSet(wat);
8
+ const inlineFunctions = new Array();
9
+
10
+ while (maskSet.hasBlock(ASYNC_BLOCK_NAME)) {
11
+ const block = maskSet.lastBlockOf(ASYNC_BLOCK_NAME);
12
+ const result = block.blockName.split(".").at(1) || "";
13
+
14
+ let chain, step, $exit, $name, $prop, $func,
15
+ steps = new helpers.MaskSet(block);
16
+
17
+ steps.mask(chain = steps.parseFirstBlock());
18
+ maskSet.mask(block);
19
+
20
+ while (steps.hasAnyBlock) {
21
+ steps.mask(step = steps.parseFirstBlock());
22
+
23
+ $prop = step.blockName;
24
+ $func = step.rawContent;
25
+ $exit = steps.hasAnyBlock && "ext" || result;
26
+
27
+ if ($func.startsWith("ref.func")) {
28
+ $name = `$${$func.split("ref.func").pop().trim()}`;
29
+ } else {
30
+ $name = `$${$prop}_${block.begin}_${step.begin}`;
31
+ inlineFunctions.push(`(func ${$name}\n${$func}\n)`);
32
+ }
33
+
34
+ chain = String(`
35
+ (call $self.Reflect.apply<ext.ext.ext>${$exit}
36
+ (ref.extern $self.Promise.prototype.${$prop}<ext>)
37
+ ${chain.toString()}
38
+ (call $self.Array.of<fun>ext (ref.func ${$name}))
39
+ )`);
40
+ }
41
+
42
+ maskSet.update(block, chain);
43
+ }
44
+
45
+
46
+ wat = maskSet.restore();
47
+
48
+ if (inlineFunctions.length) {
49
+ wat = helpers.append(wat, inlineFunctions.join("\n\n"));
50
+ }
51
+
52
+ return wat;
53
+ }