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.
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/examples/01-text/module-output.wat +228 -0
- package/examples/01-text/module.wat +9 -0
- package/examples/02-include/module-output.wat +22 -0
- package/examples/02-include/module.wat +3 -0
- package/examples/02-include/used-folder/included-file.wat +4 -0
- package/examples/03-ref.extern/module-output.wat +1537 -0
- package/examples/03-ref.extern/module.wat +33 -0
- package/examples/04-ref.func/module-output.wat +25 -0
- package/examples/04-ref.func/module.wat +8 -0
- package/examples/05-global.get/module-output.wat +991 -0
- package/examples/05-global.get/module.wat +26 -0
- package/examples/06-async/module-output.wat +661 -0
- package/examples/06-async/module.wat +15 -0
- package/examples/07-data/module-output.wasm +0 -0
- package/examples/07-data/module.wat +29 -0
- package/examples/07-data/used-folder/clear-text.txt +1 -0
- package/examples/07-data/used-folder/compile-this.wat +8 -0
- package/examples/08-reflectors/how-to/README.md +0 -0
- package/examples/08-reflectors/how-to/output-01-command.sh +0 -0
- package/examples/08-reflectors/how-to/output-02-command.sh +0 -0
- package/examples/08-reflectors/how-to/output-03-command.sh +0 -0
- package/examples/08-reflectors/how-to/output-04-command.sh +0 -0
- package/examples/08-reflectors/how-to/wat4wasm-outputs/01-module.wat +3 -0
- package/examples/08-reflectors/how-to/wat4wasm-outputs/02-module.wasm +3 -0
- package/examples/08-reflectors/how-to/wat4wasm-outputs/03-module.js +0 -0
- package/examples/08-reflectors/how-to/wat4wasm-outputs/04-module.html +0 -0
- package/examples/08-reflectors/module-output.wat +995 -0
- package/examples/08-reflectors/module.wat +108 -0
- package/examples/09-replaceAll/module-output.wat +347 -0
- package/examples/09-replaceAll/module.wat +68 -0
- package/examples/99-complex/module.wat +8 -0
- package/examples/99-complex/output.html +1 -0
- package/examples/99-complex/sub/worker.wat +2 -0
- package/examples/shell-usages.sh +60 -0
- package/lib/build +33 -0
- package/lib/clean.js +91 -0
- package/lib/cli.js +273 -0
- package/lib/helpers.js +567 -0
- package/lib/index.js +95 -0
- package/lib/processors/async.js +53 -0
- package/lib/processors/data.js +188 -0
- package/lib/processors/import.js +178 -0
- package/lib/processors/include.js +17 -0
- package/lib/processors/new.js +21 -0
- package/lib/processors/ref_extern.js +64 -0
- package/lib/processors/ref_func.js +44 -0
- package/lib/processors/replace_all.js +56 -0
- package/lib/processors/start.js +42 -0
- package/lib/processors/string.js +57 -0
- package/lib/processors/text.js +115 -0
- package/lib/processors/wat4wasm.js +285 -0
- package/lib/wat4beauty.js +320 -0
- package/package.json +30 -0
- package/ss-console.png +0 -0
- package/ss-terminal.png +0 -0
- package/test/boot.wat +5 -0
- package/test/test-output.html +1 -0
- package/test/test-output.js +27 -0
- package/test/test-output.wasm +0 -0
- package/test/test-sub.wat +4 -0
- package/test/test.wat +73 -0
- package/test/test_worker.js +1 -0
- package/wat4wasm +1998 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const DATA_BLOCK_NAME = "data";
|
|
4
|
+
export const SIZE_BLOCK_NAME = "data.size";
|
|
5
|
+
export const VIEW_BLOCK_NAME = "data.view";
|
|
6
|
+
|
|
7
|
+
const GENERATE_DATA_VIEWER = (size, $name) => {
|
|
8
|
+
return `
|
|
9
|
+
(block ${$name}>
|
|
10
|
+
(result externref)
|
|
11
|
+
|
|
12
|
+
(global.set $wat4wasm (call $self.Array<>ext))
|
|
13
|
+
|
|
14
|
+
(call $self.Reflect.set<ext.i32.i32>
|
|
15
|
+
(global.get $wat4wasm) (i32.const 0) (i32.const ${size})
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
(global.set $wat4wasm
|
|
19
|
+
(call $self.Reflect.construct<ext.ext>ext
|
|
20
|
+
(ref.extern $self.Uint8Array<ext>)
|
|
21
|
+
(global.get $wat4wasm)
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
(if (i32.const ${size})
|
|
26
|
+
(then
|
|
27
|
+
(i32.const 0)
|
|
28
|
+
(i64.load (i32.const 0))
|
|
29
|
+
|
|
30
|
+
(block $copy
|
|
31
|
+
(i32.store (i32.const 0) (i32.const ${size}))
|
|
32
|
+
(loop $i--
|
|
33
|
+
(if (i32.load (i32.const 0))
|
|
34
|
+
(then
|
|
35
|
+
(i32.store
|
|
36
|
+
(i32.const 0)
|
|
37
|
+
(i32.sub (i32.load (i32.const 0)) (i32.const 1))
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
(memory.init ${$name}
|
|
41
|
+
(i32.const 4)
|
|
42
|
+
(i32.load (i32.const 0))
|
|
43
|
+
(i32.const 1)
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
(call $self.Reflect.set<ext.i32.i32>
|
|
47
|
+
(global.get $wat4wasm)
|
|
48
|
+
(i32.load (i32.const 0))
|
|
49
|
+
(i32.load8_u (i32.const 4))
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
(br $i--)
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
(i64.store (; stack stack ;))
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
(global.get $wat4wasm)
|
|
63
|
+
(global.set $wat4wasm (null))
|
|
64
|
+
)
|
|
65
|
+
`;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export default function (wat, WAT4WASM) {
|
|
69
|
+
|
|
70
|
+
const maskSet = new helpers.MaskSet(wat);
|
|
71
|
+
|
|
72
|
+
const externgetter = new Map();
|
|
73
|
+
const segmentSizes = new Map();
|
|
74
|
+
const sizeRequests = new Set();
|
|
75
|
+
const viewRequests = new Set();
|
|
76
|
+
|
|
77
|
+
while (maskSet.hasBlock(VIEW_BLOCK_NAME)) {
|
|
78
|
+
const block = maskSet.lastBlockOf(VIEW_BLOCK_NAME);
|
|
79
|
+
viewRequests.add(block);
|
|
80
|
+
maskSet.mask(block);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
while (maskSet.hasBlock(SIZE_BLOCK_NAME)) {
|
|
84
|
+
const block = maskSet.lastBlockOf(SIZE_BLOCK_NAME);
|
|
85
|
+
sizeRequests.add(block);
|
|
86
|
+
maskSet.mask(block);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
while (maskSet.hasBlock(DATA_BLOCK_NAME)) {
|
|
90
|
+
|
|
91
|
+
const block = maskSet.lastBlockOf(DATA_BLOCK_NAME);
|
|
92
|
+
const content = helpers.findQuotedText(block);
|
|
93
|
+
|
|
94
|
+
maskSet.mask(block);
|
|
95
|
+
if (helpers.hasProtocol(content) === false) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let {
|
|
100
|
+
protocol, fullpath, directory,
|
|
101
|
+
filename, basename, extension
|
|
102
|
+
} = helpers.parseProtoPath(content);
|
|
103
|
+
|
|
104
|
+
if (protocol === "wasm://") {
|
|
105
|
+
|
|
106
|
+
const module_wat = `wat4wasm-${basename}.wat`;
|
|
107
|
+
const wasm_output = `wat4wasm-${basename}.wasm`;
|
|
108
|
+
const wat4wasm_out = `wat4wasm-${basename}.wasm.wat`;
|
|
109
|
+
|
|
110
|
+
const params = process.argv
|
|
111
|
+
.filter(a => a.startsWith("--"))
|
|
112
|
+
.filter(a => !a.startsWith("--input="))
|
|
113
|
+
.filter(a => !a.startsWith("--output="))
|
|
114
|
+
;
|
|
115
|
+
|
|
116
|
+
helpers.copyFile(fullpath, module_wat)
|
|
117
|
+
|
|
118
|
+
const wat4wasm = process.argv[1];
|
|
119
|
+
const nodejs = process.argv[0];
|
|
120
|
+
const argv = Array.of(
|
|
121
|
+
wat4wasm,
|
|
122
|
+
`--input=${module_wat}`,
|
|
123
|
+
`--output=${wasm_output}`,
|
|
124
|
+
`--no-unlink`
|
|
125
|
+
).concat(params);
|
|
126
|
+
|
|
127
|
+
helpers.spawnSync(nodejs, argv);
|
|
128
|
+
|
|
129
|
+
const { data, size } = helpers.readFileAsHex(wasm_output);
|
|
130
|
+
|
|
131
|
+
segmentSizes.set(block.$name, size);
|
|
132
|
+
maskSet.update(block, block.replace(content, data));
|
|
133
|
+
|
|
134
|
+
helpers.unlinkFile(module_wat);
|
|
135
|
+
helpers.unlinkFile(wasm_output);
|
|
136
|
+
helpers.unlinkFile(wat4wasm_out);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
else if (protocol === "file://") {
|
|
140
|
+
const { data, size } = helpers.readFileAsHex(fullpath);
|
|
141
|
+
segmentSizes.set(block.$name, size);
|
|
142
|
+
maskSet.update(block, block.replace(content, data));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
sizeRequests.forEach(block => {
|
|
147
|
+
const size = segmentSizes.get(block.$name);
|
|
148
|
+
const code = `(i32.const ${size})`;
|
|
149
|
+
|
|
150
|
+
maskSet.update(block, code);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
viewRequests.forEach(block => {
|
|
154
|
+
block.id = helpers.referenceId();
|
|
155
|
+
maskSet.update(block, block.id);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
wat = maskSet.restore();
|
|
159
|
+
|
|
160
|
+
let oninit = String();
|
|
161
|
+
viewRequests.forEach(block => {
|
|
162
|
+
if (externgetter.has(block.$name) === false) {
|
|
163
|
+
const size = segmentSizes.get(block.$name);
|
|
164
|
+
const code = GENERATE_DATA_VIEWER(size, block.$name);
|
|
165
|
+
|
|
166
|
+
const growRequest = WAT4WASM_GROW_EXTERN_TABLE(wat);
|
|
167
|
+
block.tableSetter = growRequest.generateSetter(code);
|
|
168
|
+
|
|
169
|
+
wat = growRequest.modifiedRaw;
|
|
170
|
+
oninit = `${oninit}\n\n${block.tableSetter}\n\n`;
|
|
171
|
+
|
|
172
|
+
externgetter.set(
|
|
173
|
+
block.$name,
|
|
174
|
+
growRequest.getter.concat(` ;; ${block.$name}\n`)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
viewRequests.forEach(block => {
|
|
180
|
+
wat = wat.replaceAll(
|
|
181
|
+
block.id, externgetter.get(block.$name)
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
wat = APPEND_ON_EXTERN_READY(wat, oninit);
|
|
186
|
+
|
|
187
|
+
return wat;
|
|
188
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const IMPORT_BLOCK_NAME = "import";
|
|
4
|
+
|
|
5
|
+
const RAWBLOCK_IMPORT_CODE = (pathName, rawBlock) => `(import "${pathName.split(".").at(-2) || 'self'}" "${pathName.split(".").at(-1)}" \t${rawBlock})`.replaceAll(" )", ")");
|
|
6
|
+
const FUNCTION_IMPORT_CODE = ($name) => {
|
|
7
|
+
const namesig = $name.match(/\$(.[^<]*)<(.[^>]*)?>(.[^\s]*)?/).slice(1);
|
|
8
|
+
const [pathName, inputs = "", outputs = ""] = namesig;
|
|
9
|
+
|
|
10
|
+
const tagName = `func`;
|
|
11
|
+
const longType = t => ({ ext: 'externref', fun: 'funcref' })[t] || t;
|
|
12
|
+
const paramBlock = `(param${`.${inputs}`.split('.').map(longType).join(' ')})`;
|
|
13
|
+
const resultBlock = `(result${`.${outputs}`.split('.').map(longType).join(' ')})`;
|
|
14
|
+
|
|
15
|
+
return RAWBLOCK_IMPORT_CODE(pathName, `(${tagName} ${$name} ${paramBlock} ${resultBlock})`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const GLOBAL_IMPORT_CODE = ($name) => {
|
|
19
|
+
const namesig = $name.match(/\$(.[^<]*)(?:\<(.[^>]*)\>)?/)?.slice(1) || [];
|
|
20
|
+
const [pathName = "self", type = "ext"] = namesig;
|
|
21
|
+
|
|
22
|
+
const tagName = "global";
|
|
23
|
+
const typeName = type.replace(`ext`, `externref`);
|
|
24
|
+
|
|
25
|
+
return RAWBLOCK_IMPORT_CODE(pathName, `(${tagName} ${$name} ${typeName})`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const GLOBAL_DEFINE_CODE = ($name) => {
|
|
29
|
+
const [pathName = "self", type = "ext"] = helpers.nameSignatureofGlobal($name);
|
|
30
|
+
|
|
31
|
+
const tagName = "global";
|
|
32
|
+
const mutValue = t => `(mut ${({ ext: 'externref', fun: 'funcref' })[t] || t})`;
|
|
33
|
+
const nilValue = t => `(${({ ext: 'ref.null extern', fun: 'ref.null func' })[t] || `${t}.const 0`})`;
|
|
34
|
+
|
|
35
|
+
return `(${tagName} ${$name} ${mutValue(type)} ${nilValue(type)})`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const PATH_WALKER_CODE = ($name) => {
|
|
39
|
+
|
|
40
|
+
let descriptorKey;
|
|
41
|
+
[$name, descriptorKey = "value"] = $name.split("/")
|
|
42
|
+
const nameparts = $name.split("<").at(0).split("$").pop().split(".");
|
|
43
|
+
const stepType = new Array(nameparts.length - 1).fill("ext");
|
|
44
|
+
const type = $name.split(">").at(0).split("<").pop() || "ext";
|
|
45
|
+
|
|
46
|
+
let pathWalker = `(global.get $${nameparts[0]})`;
|
|
47
|
+
let currentKey;
|
|
48
|
+
|
|
49
|
+
stepType.push(type);
|
|
50
|
+
stepType.reverse().pop();
|
|
51
|
+
nameparts.reverse().pop();
|
|
52
|
+
|
|
53
|
+
let stepCount = nameparts.length;
|
|
54
|
+
if (descriptorKey !== "value") {
|
|
55
|
+
stepCount = stepCount - 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
while (stepCount--) {
|
|
59
|
+
currentKey = nameparts.pop();
|
|
60
|
+
pathWalker = String(`
|
|
61
|
+
(call $self.Reflect.get<ext.ext>${stepType.pop()}
|
|
62
|
+
${pathWalker}
|
|
63
|
+
(text "${currentKey}") ;; ${currentKey}
|
|
64
|
+
)`).trim();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (descriptorKey !== "value") {
|
|
68
|
+
currentKey = nameparts.pop();
|
|
69
|
+
pathWalker = String(`
|
|
70
|
+
(call $self.Reflect.get<ext.ext>ext
|
|
71
|
+
(call $self.Reflect.getOwnPropertyDescriptor<ext.ext>ext
|
|
72
|
+
${pathWalker}
|
|
73
|
+
(text "${currentKey}") ;; ${currentKey}
|
|
74
|
+
)
|
|
75
|
+
(text "${descriptorKey}") ;; ${descriptorKey}
|
|
76
|
+
)`).trim();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return String(`
|
|
80
|
+
${pathWalker}
|
|
81
|
+
`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default function (wat, WAT4WASM) {
|
|
85
|
+
|
|
86
|
+
const maskSet = new helpers.MaskSet(wat);
|
|
87
|
+
const selfSet = new Set();
|
|
88
|
+
const imports = new Array();
|
|
89
|
+
const globals = new Array();
|
|
90
|
+
const oninits = new Array();
|
|
91
|
+
|
|
92
|
+
while (maskSet.hasBlock(IMPORT_BLOCK_NAME)) {
|
|
93
|
+
const wrapper = maskSet.lastBlockOf(IMPORT_BLOCK_NAME);
|
|
94
|
+
const $name = helpers.parseFirstBlock(wrapper).$name;
|
|
95
|
+
|
|
96
|
+
if ($name && $name.startsWith("$self")) {
|
|
97
|
+
if (selfSet.has($name) === false) {
|
|
98
|
+
selfSet.add($name);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
maskSet.mask(wrapper);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
while (maskSet.hasBlock("global.get")) {
|
|
106
|
+
const global = maskSet.lastBlockOf("global.get");
|
|
107
|
+
const $name = global.$name;
|
|
108
|
+
|
|
109
|
+
maskSet.mask(global);
|
|
110
|
+
maskSet.update(global, `(global.get ${$name})`);
|
|
111
|
+
|
|
112
|
+
if ($name && $name.startsWith("$self")) {
|
|
113
|
+
if (selfSet.has($name) === false) {
|
|
114
|
+
selfSet.add($name);
|
|
115
|
+
|
|
116
|
+
const [pathName = "self", type = "ext"
|
|
117
|
+
] = helpers.nameSignatureofGlobal($name);
|
|
118
|
+
|
|
119
|
+
const nameparts = pathName.split(".");
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* previous logic is based on direct import for
|
|
123
|
+
* short paths but this is unnecessary.. just set
|
|
124
|
+
* global value in the start function to gathering
|
|
125
|
+
* more simple import segment.
|
|
126
|
+
*/
|
|
127
|
+
//if (nameparts.length <= 3) {
|
|
128
|
+
if (["$self", "$self.String.fromCharCode"].includes($name)) {
|
|
129
|
+
imports.push(GLOBAL_IMPORT_CODE($name));
|
|
130
|
+
}
|
|
131
|
+
else if (globals.includes($name) === false) {
|
|
132
|
+
globals.push(GLOBAL_DEFINE_CODE($name));
|
|
133
|
+
const walker = PATH_WALKER_CODE($name, global.descriptorKey);
|
|
134
|
+
const setter = `(global.set ${$name} ${walker})`;
|
|
135
|
+
oninits.push({ setter, name: $name.substring(1), type: 'global' });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
while (maskSet.hasBlock("call")) {
|
|
142
|
+
const caller = maskSet.lastBlockOf("call");
|
|
143
|
+
const $name = caller.$name;
|
|
144
|
+
|
|
145
|
+
if ($name && $name.startsWith("$self")) {
|
|
146
|
+
if (selfSet.has($name) === false) {
|
|
147
|
+
selfSet.add($name);
|
|
148
|
+
imports.push(FUNCTION_IMPORT_CODE($name));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
maskSet.mask(caller);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
wat = maskSet.restore();
|
|
156
|
+
|
|
157
|
+
imports.forEach(code => {
|
|
158
|
+
if (wat.includes(code) === false) {
|
|
159
|
+
wat = helpers.prepend(wat, code);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
globals.forEach(code => {
|
|
164
|
+
if (wat.includes(code) === false) {
|
|
165
|
+
wat = helpers.append(wat, code);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
oninits.forEach(init => {
|
|
170
|
+
const header = `block $${init.type}/${init.name}`;
|
|
171
|
+
if (wat.includes(header) === false) {
|
|
172
|
+
const code = String(`(${header}\n${init.setter}\n)`);
|
|
173
|
+
wat = APPEND_ON_TEXT_READY(wat, code);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return wat;
|
|
178
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const INCLUDE_BLOCK_NAME = "include";
|
|
4
|
+
|
|
5
|
+
export default function (wat, WAT4WASM) {
|
|
6
|
+
|
|
7
|
+
while (helpers.hasBlock(wat, INCLUDE_BLOCK_NAME)) {
|
|
8
|
+
const block = helpers.lastBlockOf(wat, INCLUDE_BLOCK_NAME);
|
|
9
|
+
const path = helpers.findQuotedText(block);
|
|
10
|
+
|
|
11
|
+
wat = block.replacedRaw(
|
|
12
|
+
helpers.readFileAsText(path)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return wat;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const NEW_BLOCK_NAME = "new";
|
|
4
|
+
|
|
5
|
+
export default function (wat) {
|
|
6
|
+
|
|
7
|
+
while (helpers.hasBlock(wat, NEW_BLOCK_NAME)) {
|
|
8
|
+
|
|
9
|
+
const block = helpers.lastBlockOf(wat, NEW_BLOCK_NAME);
|
|
10
|
+
const $name = block.$name;
|
|
11
|
+
const param = $name.split(">").at(0).split("<").at(1) || "";
|
|
12
|
+
|
|
13
|
+
const $constructor = `(ref.extern $self.${$name.substring(1)}<ext>)`;
|
|
14
|
+
const $arguments = block.replace(`(new ${$name}`, `(array $of<${param}>ext`);
|
|
15
|
+
const $reflect = `(reflect $construct<ext.ext>ext\n${$constructor}\n${$arguments}\n)`;
|
|
16
|
+
|
|
17
|
+
wat = block.replacedRaw($reflect);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return wat;
|
|
21
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
import { PATH_WALKER_CODE } from "./import.js";
|
|
3
|
+
|
|
4
|
+
export const REF_EXTERN_BLOCK_NAME = "ref.extern";
|
|
5
|
+
|
|
6
|
+
const FIXNAME_SELF_PATH = ($name, descriptorKey) => {
|
|
7
|
+
|
|
8
|
+
if ($name.startsWith("$self") === false) {
|
|
9
|
+
$name = `$self.${$name.substring(1)}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if ($name.endsWith(">") === false) {
|
|
13
|
+
if (descriptorKey === "value") {
|
|
14
|
+
$name = `${$name}<ext>`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return $name;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function (wat, WAT4WASM) {
|
|
22
|
+
|
|
23
|
+
const externs = new Map();
|
|
24
|
+
const getters = new Map();
|
|
25
|
+
const maskSet = new helpers.MaskSet(wat);
|
|
26
|
+
|
|
27
|
+
while (maskSet.hasBlock(REF_EXTERN_BLOCK_NAME)) {
|
|
28
|
+
const block = maskSet.lastBlockOf(REF_EXTERN_BLOCK_NAME);
|
|
29
|
+
const $name = FIXNAME_SELF_PATH(block.$name, block.descriptorKey);
|
|
30
|
+
|
|
31
|
+
if (externs.has($name) === false) {
|
|
32
|
+
externs.set($name, block.descriptorKey);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
maskSet.mask(block);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
wat = maskSet.restore();
|
|
39
|
+
|
|
40
|
+
let oninit = String();
|
|
41
|
+
externs.forEach((dKey, $name) => {
|
|
42
|
+
const pathWalker = PATH_WALKER_CODE($name);
|
|
43
|
+
const growExtern = WAT4WASM_GROW_EXTERN_TABLE(wat);
|
|
44
|
+
|
|
45
|
+
const __getter__ = growExtern.getter.concat(` ;; ${$name}\n`);
|
|
46
|
+
const __setter__ = growExtern.generateSetter(pathWalker);
|
|
47
|
+
|
|
48
|
+
wat = growExtern.modifiedRaw;
|
|
49
|
+
oninit = `${oninit}\n\n(block ${$name}\n${__setter__})\n`;
|
|
50
|
+
getters.set($name, __getter__);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
while (helpers.hasBlock(wat, REF_EXTERN_BLOCK_NAME)) {
|
|
54
|
+
const block = helpers.lastBlockOf(wat, REF_EXTERN_BLOCK_NAME);
|
|
55
|
+
const $name = FIXNAME_SELF_PATH(block.$name, block.descriptorKey);
|
|
56
|
+
wat = block.replacedRaw(getters.get($name));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (oninit.trim()) {
|
|
60
|
+
wat = APPEND_ON_TEXT_READY(wat, oninit);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return wat;
|
|
64
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const REF_FUNC_BLOCK_NAME = "ref.func";
|
|
4
|
+
|
|
5
|
+
export default function (wat, WAT4WASM) {
|
|
6
|
+
|
|
7
|
+
const maskSetElem = new helpers.MaskSet(wat);
|
|
8
|
+
const elemSegments = new Array();
|
|
9
|
+
const needReference = new Set();
|
|
10
|
+
|
|
11
|
+
while (maskSetElem.hasBlock("elem")) {
|
|
12
|
+
const block = maskSetElem.lastBlockOf("elem");
|
|
13
|
+
const $name = block.$name;
|
|
14
|
+
if (WAT4WASM.WAT4WASM_$NAME !== $name) {
|
|
15
|
+
elemSegments.push(block.toString());
|
|
16
|
+
}
|
|
17
|
+
maskSetElem.mask(block);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const maskSetRef = new helpers.MaskSet(wat);
|
|
21
|
+
|
|
22
|
+
while (maskSetRef.hasBlock(REF_FUNC_BLOCK_NAME)) {
|
|
23
|
+
const block = maskSetRef.lastBlockOf(REF_FUNC_BLOCK_NAME);
|
|
24
|
+
const $name = block.$name
|
|
25
|
+
|
|
26
|
+
if (WAT4WASM.WAT4WASM_$NAME !== $name) {
|
|
27
|
+
if (elemSegments.some(seg => seg.includes($name)) === false) {
|
|
28
|
+
if (needReference.has($name) === false) {
|
|
29
|
+
needReference.add($name);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
maskSetRef.mask(block);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
wat = maskSetRef.restore();
|
|
38
|
+
|
|
39
|
+
needReference.forEach($name => {
|
|
40
|
+
wat = WAT4WASM_REFERENCE_FUNC_ELEMENT(wat, $name);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return wat;
|
|
44
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
export default function (wat) {
|
|
3
|
+
return wat
|
|
4
|
+
.replaceAll("(self)", "(global.get $self)")
|
|
5
|
+
.replaceAll("(null)", "(ref.null extern)")
|
|
6
|
+
.replaceAll("(func)", "(ref.null func)")
|
|
7
|
+
.replaceAll("(this)", "(local.get 0)")
|
|
8
|
+
.replaceAll("(array)", "(call $self.Array<>ext)")
|
|
9
|
+
.replaceAll("(NaN)", "(ref.extern $self.NaN<ext>)")
|
|
10
|
+
.replaceAll("(nan)", "(f32.const nan)")
|
|
11
|
+
.replaceAll("(true)", "(i32.const 1)")
|
|
12
|
+
.replaceAll("(false)", "(i32.const 0)")
|
|
13
|
+
.replaceAll("(undefined)", "(ref.extern $self.undefined<ext>)")
|
|
14
|
+
.replaceAll("(object)", "(call $self.Object<>ext)")
|
|
15
|
+
.replaceAll("(string)", "(call $self.String<>ext)")
|
|
16
|
+
.replaceAll("(console $", "(call $self.console.")
|
|
17
|
+
.replaceAll("(reflect $", "(call $self.Reflect.")
|
|
18
|
+
.replaceAll("(bigint $", "(call $self.BigInt.")
|
|
19
|
+
.replaceAll("(number $", "(call $self.Number.")
|
|
20
|
+
.replaceAll("(math $", "(call $self.Math.")
|
|
21
|
+
.replaceAll("(string $", "(call $self.String.")
|
|
22
|
+
.replaceAll("(object $", "(call $self.Object.")
|
|
23
|
+
.replaceAll("(array $", "(call $self.Array.")
|
|
24
|
+
.replaceAll("(grow $", "(table.grow $")
|
|
25
|
+
.replaceAll("(url $", "(call $self.URL.")
|
|
26
|
+
.replaceAll("(self $", "(ref.extern $self.")
|
|
27
|
+
.replaceAll(" mut ext)", " (mut externref) (null))")
|
|
28
|
+
.replaceAll(" mut fun)", " (mut funcref) (func))")
|
|
29
|
+
.replaceAll(" mut vec)", " (mut v128) (v128.const i32x4 0 0 0 0))")
|
|
30
|
+
.replaceAll(" fun)", " funcref)")
|
|
31
|
+
.replaceAll(" ext)", " externref)")
|
|
32
|
+
.replaceAll(" != null)", ") (ref.is_null) (i32.eqz)")
|
|
33
|
+
.replaceAll(" == null)", ") (ref.is_null)")
|
|
34
|
+
.replaceAll(" == 0)", ") (i32.eqz)")
|
|
35
|
+
.replaceAll(" != 0)", ") (i32.const 0) (i32.ne)")
|
|
36
|
+
.replaceAll(" == 1)", ") (i32.const 1) (i32.eq)")
|
|
37
|
+
.replaceAll(" != 1)", ") (i32.const 1) (i32.ne)")
|
|
38
|
+
.replaceAll(" == true)", ") (i32.const 1) (i32.eq)")
|
|
39
|
+
.replaceAll(" == false)", ") (i32.eqz)")
|
|
40
|
+
.replaceAll(" == nan)", ") (f32.const nan) (f32.eq)")
|
|
41
|
+
.replaceAll(" != nan)", ") (f32.const nan) (f32.ne)")
|
|
42
|
+
.replaceAll(" != NaN)", ") (NaN) (object $is<ext.ext>i32) (i32.eqz)")
|
|
43
|
+
.replaceAll(" == NaN)", ") (NaN) (object $is<ext.ext>i32)")
|
|
44
|
+
.replaceAll(" != undefined)", ") (undefined) (object $is<ext.ext>i32) (i32.eqz)")
|
|
45
|
+
.replaceAll(" == undefined)", ") (undefined) (object $is<ext.ext>i32)")
|
|
46
|
+
.replaceAll(/ mut\s+(i32|f32|i64|f64)\)/g, ` (mut $1) ($1.const 0))`)
|
|
47
|
+
.replaceAll(/\<[A-Z](.[^>]*)\>/g, "externref")
|
|
48
|
+
.replaceAll(/\(l(get|set|tee)(\s)/g, `(local.$1$2`)
|
|
49
|
+
.replaceAll(/\(g(get|set)(\s)/g, `(global.$1$2`)
|
|
50
|
+
.replaceAll(/\(t(get|set)(\s)/g, `(table.$1$2`)
|
|
51
|
+
.replaceAll(/(i32|f32|i64|f64|fun|ext)\((\+|\-|)\s*([0-9\.]+)\)/g, `($1.const $2$3)`)
|
|
52
|
+
.replaceAll(/\((.*)\.(set|tee)\s+([\+|\-])+\s+(\$.*)\s*\)/g, "($1.$2 $4 (i32.add ($1.get $4) (i32.const $31)))")
|
|
53
|
+
.replaceAll(/\(apply(?:\.*)(i32|f32|i64|f64|fun|ext|)(\s*)/g, `(call $self.Reflect.apply<ext.ext.ext>$1 $2`)
|
|
54
|
+
.replaceAll(/\(main(\s+)(\$.[^\s]*)(\s)/g, `(start$1$2)\n\n(func$1$2$3`)
|
|
55
|
+
;
|
|
56
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const START_BLOCK_NAME = "start";
|
|
4
|
+
|
|
5
|
+
export default function (wat, WAT4WASM) {
|
|
6
|
+
let startCalls = [];
|
|
7
|
+
let removedWat = wat;
|
|
8
|
+
|
|
9
|
+
while (helpers.hasBlock(removedWat, START_BLOCK_NAME)) {
|
|
10
|
+
let block = helpers.lastBlockOf(removedWat, START_BLOCK_NAME);
|
|
11
|
+
removedWat = block.removedRaw();
|
|
12
|
+
|
|
13
|
+
if (block.includes(WAT4WASM.WAT4WASM_$NAME) === false) {
|
|
14
|
+
startCalls.push(block);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (startCalls.length > 0) {
|
|
19
|
+
wat = removedWat;
|
|
20
|
+
|
|
21
|
+
let $wat4func = helpers.lastBlockOf(wat, "func", { $name: WAT4WASM.WAT4WASM_$NAME });
|
|
22
|
+
let funcblock = $wat4func.toString();
|
|
23
|
+
|
|
24
|
+
const appends = startCalls.filter(start => {
|
|
25
|
+
let $name = `${start.$name}`;
|
|
26
|
+
let $call = `(call ${$name})`;
|
|
27
|
+
|
|
28
|
+
if (helpers.hasBlock(funcblock, "call", { $name }) === false) {
|
|
29
|
+
funcblock = helpers.append(funcblock, $call);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (appends.length) {
|
|
35
|
+
wat = $wat4func.replacedRaw(funcblock);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
wat = helpers.append(wat, WAT4WASM.WAT4WASM_START);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return wat;
|
|
42
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import helpers from "../helpers.js"
|
|
2
|
+
|
|
3
|
+
export const STRING_BLOCK_NAME = "string";
|
|
4
|
+
|
|
5
|
+
export default function (wat) {
|
|
6
|
+
|
|
7
|
+
while (helpers.hasBlock(wat, STRING_BLOCK_NAME)) {
|
|
8
|
+
|
|
9
|
+
let oldBlock = helpers.lastBlockOf(wat, STRING_BLOCK_NAME);
|
|
10
|
+
const string = helpers.findQuotedText(oldBlock);
|
|
11
|
+
const ccodes = helpers.encodeString(string);
|
|
12
|
+
|
|
13
|
+
if (ccodes.length === 0) {
|
|
14
|
+
wat = oldBlock.replacedRaw(`
|
|
15
|
+
(reflect $apply<ext.ext.ext>ext
|
|
16
|
+
(global.get $self.String.fromCharCode)
|
|
17
|
+
(self)
|
|
18
|
+
(self)
|
|
19
|
+
)
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
else if (ccodes.length === 1) {
|
|
23
|
+
wat = oldBlock.replacedRaw(`
|
|
24
|
+
(reflect $apply<ext.ext.ext>ext
|
|
25
|
+
(global.get $self.String.fromCharCode)
|
|
26
|
+
(self)
|
|
27
|
+
(array $of<i32>ext (i32.const ${string.charCodeAt(0)})) ;; "${string}"
|
|
28
|
+
)
|
|
29
|
+
`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
wat = oldBlock.replacedRaw(`
|
|
33
|
+
(block (; "${helpers.abstract(string)}" ;)
|
|
34
|
+
(result externref)
|
|
35
|
+
(global.set $wat4wasm (call $self.Array<>ext))
|
|
36
|
+
|
|
37
|
+
${ccodes
|
|
38
|
+
.map((c, i) => `(global.get $wat4wasm) (i32.const ${i}) (i32.const ${c})`)
|
|
39
|
+
.map((args) => `(call $self.Reflect.set<ext.i32.i32> ${args})`)
|
|
40
|
+
.join("\n")}
|
|
41
|
+
|
|
42
|
+
(call $self.Reflect.apply<ext.ext.ext>ext
|
|
43
|
+
(global.get $self.String.fromCharCode)
|
|
44
|
+
(ref.null extern)
|
|
45
|
+
(global.get $wat4wasm)
|
|
46
|
+
)
|
|
47
|
+
;; stacked
|
|
48
|
+
|
|
49
|
+
(global.set $wat4wasm (null))
|
|
50
|
+
;; cleared
|
|
51
|
+
)
|
|
52
|
+
`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return wat;
|
|
57
|
+
}
|