porffor 0.2.0-6aff0fa → 0.2.0-6bc63ef

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 (54) hide show
  1. package/CONTRIBUTING.md +256 -0
  2. package/LICENSE +20 -20
  3. package/README.md +115 -82
  4. package/asur/index.js +624 -340
  5. package/byg/index.js +216 -0
  6. package/compiler/2c.js +2 -53
  7. package/compiler/{sections.js → assemble.js} +60 -14
  8. package/compiler/builtins/annexb_string.js +72 -0
  9. package/compiler/builtins/annexb_string.ts +18 -0
  10. package/compiler/builtins/array.ts +145 -0
  11. package/compiler/builtins/base64.ts +7 -84
  12. package/compiler/builtins/boolean.ts +18 -0
  13. package/compiler/builtins/crypto.ts +120 -0
  14. package/compiler/builtins/date.ts +2067 -0
  15. package/compiler/builtins/escape.ts +141 -0
  16. package/compiler/builtins/function.ts +5 -0
  17. package/compiler/builtins/int.ts +145 -0
  18. package/compiler/builtins/number.ts +529 -0
  19. package/compiler/builtins/object.ts +4 -0
  20. package/compiler/builtins/porffor.d.ts +44 -7
  21. package/compiler/builtins/set.ts +187 -0
  22. package/compiler/builtins/string.ts +1080 -0
  23. package/compiler/builtins.js +400 -120
  24. package/compiler/{codeGen.js → codegen.js} +850 -402
  25. package/compiler/decompile.js +2 -3
  26. package/compiler/embedding.js +22 -22
  27. package/compiler/encoding.js +94 -10
  28. package/compiler/expression.js +1 -1
  29. package/compiler/generated_builtins.js +1613 -3
  30. package/compiler/index.js +16 -16
  31. package/compiler/log.js +2 -2
  32. package/compiler/opt.js +28 -27
  33. package/compiler/parse.js +36 -30
  34. package/compiler/precompile.js +37 -46
  35. package/compiler/prefs.js +7 -6
  36. package/compiler/prototype.js +20 -36
  37. package/compiler/types.js +38 -0
  38. package/compiler/wasmSpec.js +14 -1
  39. package/compiler/wrap.js +79 -69
  40. package/package.json +9 -5
  41. package/porf +2 -0
  42. package/rhemyn/compile.js +44 -26
  43. package/rhemyn/parse.js +322 -320
  44. package/rhemyn/test/parse.js +58 -58
  45. package/runner/compare.js +33 -34
  46. package/runner/debug.js +117 -0
  47. package/runner/index.js +69 -12
  48. package/runner/profiler.js +22 -30
  49. package/runner/repl.js +40 -13
  50. package/runner/sizes.js +37 -37
  51. package/runner/version.js +3 -3
  52. package/runner/info.js +0 -89
  53. package/runner/transform.js +0 -15
  54. package/util/enum.js +0 -20
package/byg/index.js ADDED
@@ -0,0 +1,216 @@
1
+ import fs from 'node:fs';
2
+
3
+ const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
4
+ const printLine = (line, number, breakpoint = false, current = false, selected = false) => {
5
+ console.log(`\x1b[${breakpoint ? (selected ? '43' : '103') : (selected ? '47' : '100')}m\x1b[${selected || breakpoint ? '30' : '97'}m${number.toFixed(0).padStart(4, ' ')}\x1b[${breakpoint ? (selected ? '33' : '93') : (selected ? '37' : '90')}m\x1b[${current ? '47' : '40'}m▌ \x1b[${current ? '47' : '40'}m\x1b[${current ? '30' : '37'}m${current ? noAnsi(line) : line}\x1b[0K`);
6
+ };
7
+
8
+ const box = (x, y, width, height, title = '', content = [], color = ['90', '100', '37', '35', '45'], padding = true) => {
9
+ if (padding) {
10
+ width += 1;
11
+ height += 1;
12
+
13
+ // top
14
+ process.stdout.write(`\x1b[48m\x1b[${y + 1};${x + 1}H\x1b[${color[0]}m` + '▄'.repeat(width));
15
+ // bottom
16
+ process.stdout.write(`\x1b[${y + height + 1};${x + 1}H▝` + '▀'.repeat(width - 1) + '▘');
17
+ // left
18
+ process.stdout.write(`\x1b[${y + 1};${x + 1}H▗` + '\x1b[1B\x1b[1D▐'.repeat(height - 1));
19
+ // right
20
+ process.stdout.write(`\x1b[${y + 1};${x + width + 1}H▖` + '\x1b[1B\x1b[1D▌'.repeat(height - 1));
21
+
22
+ x += 1;
23
+ y += 1;
24
+ width -= 1;
25
+ height -= 1;
26
+ }
27
+
28
+ // bg
29
+ process.stdout.write(`\x1b[${y + 1};${x + 1}H\x1b[${color[1]}m` + ' '.repeat(width) + (`\x1b[1B\x1b[${width}D` + ' '.repeat(width)).repeat(Math.max(0, height - 1)));
30
+
31
+ // title
32
+ if (title) process.stdout.write(`\x1b[${y};${x}H\x1b[0m\x1b[${color[3]}m▐\x1b[${color[4]}m\x1b[${color[2]}m\x1b[1m${' '.repeat((width - title.length) / 2 | 0)}${title}${' '.repeat(width - (((width - title.length) / 2 | 0)) - title.length)}\x1b[0m\x1b[${color[3]}m▌`);
33
+
34
+ // content
35
+ process.stdout.write(`\x1b[${y + (title ? 1 : 1)};${x + 1}H\x1b[${color[1]}m\x1b[${color[2]}m${content.join(`\x1b[1B\x1b[${x + 1}G`)}`);
36
+ };
37
+
38
+ const controls = {
39
+ 'ret': 'resume ',
40
+ 'b': 'breakpoint ',
41
+ 's': 'step over',
42
+ 'i': 'step in',
43
+ 'o': 'step out ',
44
+ };
45
+
46
+ const controlInfo = Object.keys(controls).reduce((acc, x, i) => acc + `\x1B[45m\x1B[97m${x}\x1b[105m\x1b[37m ${controls[x]} `, '');
47
+ const plainControlInfo = noAnsi(controlInfo);
48
+
49
+ globalThis.termWidth = process.stdout.columns || 80;
50
+ globalThis.termHeight = process.stdout.rows || 24;
51
+
52
+ export default ({ lines, pause, breakpoint }) => {
53
+ process.stdin.setRawMode(true);
54
+ process.stdin.resume();
55
+ process.stdin.setEncoding('utf8');
56
+
57
+ process.stdin.on('data', s => {
58
+ // ctrl c
59
+ if (s === '\u0003') {
60
+ process.exit();
61
+ }
62
+
63
+ if (!paused) pause();
64
+ });
65
+
66
+ const stdin = fs.openSync('/dev/stdin', 'r+');
67
+ const readCharSync = () => {
68
+ const buffer = Buffer.alloc(1);
69
+ fs.readSync(stdin, buffer, 0, 1);
70
+ return buffer.toString('utf8');
71
+ };
72
+
73
+ const tooManyLines = lines.length > (termHeight - 1);
74
+ const breakpoints = {};
75
+
76
+ process.on('exit', () => {
77
+ process.stdout.write('\x1b[0m');
78
+ });
79
+
80
+ console.clear();
81
+
82
+ let paused = true;
83
+ return (_paused, currentLine, text, boxes = []) => {
84
+ paused = _paused;
85
+
86
+ let scrollOffset = 0;
87
+ let currentLinePos = currentLine;
88
+
89
+ const draw = () => {
90
+ console.clear();
91
+ process.stdout.write(`\x1b[1;1H`);
92
+
93
+ if (tooManyLines) {
94
+ const edgePadding = (termHeight / 2) - 1;
95
+ let beforePadding = currentLine - edgePadding;
96
+ let afterPadding = currentLine + edgePadding + 1;
97
+
98
+ if (beforePadding < 0) {
99
+ afterPadding += Math.abs(beforePadding);
100
+ beforePadding = 0;
101
+ }
102
+
103
+ beforePadding += scrollOffset;
104
+ afterPadding += scrollOffset;
105
+
106
+ if (afterPadding > lines.length) {
107
+ beforePadding -= afterPadding - lines.length;
108
+ afterPadding = lines.length;
109
+ }
110
+
111
+ for (let i = Math.max(0, beforePadding); i < Math.max(0, beforePadding) + (termHeight - 1); i++) {
112
+ printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
113
+ }
114
+
115
+ currentLinePos = currentLine - beforePadding;
116
+ } else {
117
+ for (let i = 0; i < lines.length; i++) {
118
+ printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
119
+ }
120
+ }
121
+
122
+ for (const x of boxes) {
123
+ const y = x.y({ currentLinePos });
124
+ if (y < 0 || y >= termHeight) continue;
125
+
126
+ box(x.x, y, x.width, x.height, x.title, x.content);
127
+ }
128
+
129
+ // text += ` | rss: ${(process.memoryUsage.rss() / 1024 / 1024).toFixed(2)}mb`;
130
+
131
+ process.stdout.write(`\x1b[${termHeight};1H\x1b[105m\x1b[37m${text}${' '.repeat(termWidth - plainControlInfo.length - noAnsi(text).length - 1)}${controlInfo} \x1b[0m`);
132
+ };
133
+
134
+ draw();
135
+
136
+ let lastSpecial = false;
137
+ while (true) {
138
+ const char = readCharSync();
139
+
140
+ if (char === '[') {
141
+ lastSpecial = true;
142
+ continue;
143
+ }
144
+
145
+ switch (char.toLowerCase()) {
146
+ case '\r': {
147
+ paused = false;
148
+ return 'resume';
149
+ }
150
+
151
+ case 's': {
152
+ return 'stepOver';
153
+ }
154
+
155
+ case 'i': {
156
+ return 'stepIn';
157
+ }
158
+
159
+ case 'o': {
160
+ return 'stepOut';
161
+ }
162
+
163
+ case 'b': {
164
+ if (!lastSpecial) {
165
+ // b pressed normally
166
+ breakpoints[currentLine + scrollOffset] = !breakpoints[currentLine + scrollOffset];
167
+ draw();
168
+
169
+ breakpoint(currentLine + scrollOffset, breakpoints[currentLine + scrollOffset]);
170
+ break;
171
+ }
172
+
173
+ // arrow down
174
+ if (scrollOffset < lines.length - currentLine - 1) scrollOffset++;
175
+ draw();
176
+ break;
177
+ }
178
+
179
+ case 'a': {
180
+ if (!lastSpecial) break;
181
+
182
+ // arrow up
183
+ if (scrollOffset > -currentLine) scrollOffset--;
184
+ draw();
185
+
186
+ break;
187
+ }
188
+
189
+ case '5': {
190
+ if (!lastSpecial) break;
191
+
192
+ // page up
193
+ scrollOffset -= Math.min(scrollOffset + currentLine, termHeight - 1);
194
+ draw();
195
+ break;
196
+ }
197
+
198
+ case '6': {
199
+ if (!lastSpecial) break;
200
+
201
+ // page down
202
+ scrollOffset += Math.min(lines.length - (scrollOffset + currentLine) - 1, termHeight - 1);
203
+ draw();
204
+ break;
205
+ }
206
+
207
+ case 'q':
208
+ case '\u0003': {
209
+ process.exit();
210
+ }
211
+ }
212
+
213
+ lastSpecial = false;
214
+ }
215
+ };
216
+ };
package/compiler/2c.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
2
2
  import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
3
3
  import { operatorOpcode } from './expression.js';
4
- import { log } from "./log.js";
4
+ import { log } from './log.js';
5
5
 
6
6
  const CValtype = {
7
7
  i8: 'i8',
@@ -106,17 +106,6 @@ for (const x in CValtype) {
106
106
  if (Valtype[x]) CValtype[Valtype[x]] = CValtype[x];
107
107
  }
108
108
 
109
- const todo = msg => {
110
- class TodoError extends Error {
111
- constructor(message) {
112
- super(message);
113
- this.name = 'TodoError';
114
- }
115
- }
116
-
117
- throw new TodoError(`todo: ${msg}`);
118
- };
119
-
120
109
  const removeBrackets = str => {
121
110
  // return str;
122
111
  // if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
@@ -167,11 +156,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
167
156
  prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
168
157
  }
169
158
 
170
- // for (const [ x, p ] of pages) {
171
- // out += `${CValtype[p.type]} ${x.replace(': ', '_').replace(/[^0-9a-zA-Z_]/g, '')}[100]`;
172
- // out += ';\n';
173
- // }
174
-
175
159
  if (out) out += '\n';
176
160
 
177
161
  let depth = 1;
@@ -213,9 +197,9 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
213
197
 
214
198
  for (const f of funcs) {
215
199
  depth = 1;
200
+ brDepth = 0;
216
201
 
217
202
  const invLocals = inv(f.locals, x => x.idx);
218
- // if (f.returns.length > 1) todo('funcs returning >1 value unsupported');
219
203
 
220
204
  for (const x in invLocals) {
221
205
  invLocals[x] = sanitize(invLocals[x]);
@@ -247,12 +231,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
247
231
  const brs = [];
248
232
  let lastCond = false;
249
233
 
250
- // let brDepth = 0;
251
-
252
234
  const blockStart = (i, loop) => {
253
- // reset "stack"
254
- // vals = [];
255
-
256
235
  rets.push(i[1]);
257
236
 
258
237
  const br = brId++;
@@ -269,25 +248,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
269
248
  brDepth++;
270
249
  };
271
250
 
272
- const highlight = i => {
273
- const surrounding = 6;
274
-
275
- const decomp = decompile(f.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, f.locals, f.params, f.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
276
-
277
- const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
278
- let longest = 0;
279
- for (let j = 0; j < decomp.length; j++) {
280
- longest = Math.max(longest, noAnsi(decomp[j]).length);
281
- }
282
-
283
- const middle = Math.floor(decomp.length / 2);
284
- decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
285
-
286
- console.log('\x1B[90m...\x1B[0m');
287
- console.log(decomp.join('\n'));
288
- console.log('\x1B[90m...\x1B[0m\n');
289
- };
290
-
291
251
  for (let _ = 0; _ < f.wasm.length; _++) {
292
252
  const i = f.wasm[_];
293
253
  if (!i || !i[0]) continue;
@@ -415,8 +375,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
415
375
  const br = brs.at(-1);
416
376
  const ret = rets.at(-1);
417
377
  if (ret && ret !== Blocktype.void) {
418
- // console.log(vals, ret);
419
- // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
420
378
  if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
421
379
  // vals.push(`_r${br}`);
422
380
  }
@@ -425,8 +383,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
425
383
  line(`} else {`, false);
426
384
  depth++;
427
385
 
428
- // reset "stack"
429
- // vals = [];
430
386
  break;
431
387
  }
432
388
 
@@ -441,8 +397,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
441
397
  const br = brs.pop();
442
398
  const ret = rets.pop();
443
399
  if (ret && ret !== Blocktype.void) {
444
- // console.log(vals, ret);
445
- // console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
446
400
  if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
447
401
  vals.push(`_r${br}`);
448
402
  }
@@ -541,18 +495,14 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
541
495
 
542
496
  case Opcodes.br: {
543
497
  const ret = rets[brDepth - i[1] - 1];
544
- // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
545
498
  if (ret !== Blocktype.void) line(`_r${brs[brDepth - i[1] - 1]} = ${removeBrackets(vals.pop())}`);
546
499
  line(`goto j${brs[brDepth - i[1] - 1]}`);
547
500
 
548
- // // reset "stack"
549
- // vals = [];
550
501
  break;
551
502
  }
552
503
 
553
504
  case Opcodes.br_if: {
554
505
  const ret = rets[brDepth - i[1] - 1];
555
- // console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
556
506
 
557
507
  let cond = removeBrackets(vals.pop());
558
508
  if (!lastCond) {
@@ -602,7 +552,6 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
602
552
  }
603
553
 
604
554
  log.warning('2c', `unimplemented op: ${invOpcodes[i[0]]}`);
605
- // todo(`unimplemented op: ${invOpcodes[i[0]]}`);
606
555
  }
607
556
 
608
557
  lastCond = false;
@@ -1,8 +1,7 @@
1
- import { Valtype, FuncType, Empty, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize } from './wasmSpec.js';
2
- import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 } from './encoding.js';
3
- import { number } from './embedding.js';
1
+ import { Valtype, FuncType, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize } from './wasmSpec.js';
2
+ import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64_into } from './encoding.js';
4
3
  import { importedFuncs } from './builtins.js';
5
- import { log } from "./log.js";
4
+ import { log } from './log.js';
6
5
  import Prefs from './prefs.js';
7
6
 
8
7
  const createSection = (type, data) => [
@@ -28,11 +27,11 @@ export default (funcs, globals, tags, pages, data, flags) => {
28
27
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
29
28
 
30
29
  const compileHints = Prefs.compileHints;
31
- if (compileHints) log.warning('sections', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
30
+ if (compileHints) log.warning('assemble', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
32
31
 
33
32
  const getType = (params, returns) => {
34
33
  const hash = `${params.join(',')}_${returns.join(',')}`;
35
- if (Prefs.optLog) log('sections', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
34
+ if (Prefs.optLog) log('assemble', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
36
35
  if (optLevel >= 1 && typeCache[hash] !== undefined) return typeCache[hash];
37
36
 
38
37
  const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
@@ -45,7 +44,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
45
44
 
46
45
  let importFuncs = [];
47
46
 
48
- if (optLevel < 1) {
47
+ if (optLevel < 1 || !Prefs.treeshakeWasmImports) {
49
48
  importFuncs = importedFuncs;
50
49
  } else {
51
50
  let imports = new Map();
@@ -80,11 +79,11 @@ export default (funcs, globals, tags, pages, data, flags) => {
80
79
  }
81
80
  globalThis.importFuncs = importFuncs;
82
81
 
83
- if (Prefs.optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
82
+ if (Prefs.optLog) log('assemble', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
84
83
 
85
84
  const importSection = importFuncs.length === 0 ? [] : createSection(
86
85
  Section.import,
87
- encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
86
+ encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(x.name.startsWith('profile') ? Valtype.i32 : valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
88
87
  );
89
88
 
90
89
  const funcSection = createSection(
@@ -100,14 +99,61 @@ export default (funcs, globals, tags, pages, data, flags) => {
100
99
  encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
101
100
  );
102
101
 
103
- const globalSection = Object.keys(globals).length === 0 ? [] : createSection(
104
- Section.global,
105
- encodeVector(Object.keys(globals).map(x => [ globals[x].type, 0x01, ...number(globals[x].init ?? 0, globals[x].type).flat(), Opcodes.end ]))
106
- );
102
+ // const t0 = performance.now();
103
+
104
+ // specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
105
+ const globalsValues = Object.values(globals);
106
+
107
+ let globalSection = [];
108
+ if (globalsValues.length > 0) {
109
+ let data = unsignedLEB128(globalsValues.length);
110
+ for (let i = 0; i < globalsValues.length; i++) {
111
+ const global = globalsValues[i];
112
+
113
+ switch (global.type) {
114
+ case Valtype.i32:
115
+ if (i > 0) data.push(Opcodes.end, Valtype.i32, 0x01, Opcodes.i32_const);
116
+ else data.push(Valtype.i32, 0x01, Opcodes.i32_const);
117
+
118
+ signedLEB128_into(global.init ?? 0, data);
119
+ break;
120
+
121
+ case Valtype.i64:
122
+ if (i > 0) data.push(Opcodes.end, Valtype.i64, 0x01, Opcodes.i64_const);
123
+ else data.push(Valtype.i64, 0x01, Opcodes.i64_const);
124
+
125
+ signedLEB128_into(global.init ?? 0, data);
126
+ break;
127
+
128
+ case Valtype.f64:
129
+ if (i > 0) data.push(Opcodes.end, Valtype.f64, 0x01, Opcodes.f64_const);
130
+ else data.push(Valtype.f64, 0x01, Opcodes.f64_const);
131
+
132
+ ieee754_binary64_into(global.init ?? 0, data);
133
+ break;
134
+ }
135
+ }
136
+
137
+ data.push(Opcodes.end);
138
+
139
+ globalSection.push(Section.global);
140
+
141
+ unsignedLEB128_into(data.length, globalSection);
142
+ globalSection = globalSection.concat(data);
143
+ }
144
+
145
+ // if (Prefs.profileCompiler) {
146
+ // const log = console.log;
147
+ // console.log = function () {
148
+ // log.apply(this, arguments);
149
+ // console.log = log;
150
+ // console.log(` a. assembled global section in ${(performance.now() - t0).toFixed(2)}ms\n`);
151
+ // };
152
+ // }
107
153
 
108
154
  const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
109
155
 
110
- if (Prefs.alwaysMemory && pages.size === 0) pages.set('-always-memory', 0);
156
+ if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
111
157
  if (optLevel === 0) pages.set('O0 precaution', 0);
112
158
 
113
159
  const usesMemory = pages.size > 0;
@@ -0,0 +1,72 @@
1
+ export default () => {
2
+ let out = `// @porf --funsafe-no-unlikely-proto-checks --valtype=i32
3
+ `;
4
+
5
+ const noArgs = (a0, a1) => out += `
6
+ export const __String_prototype_${a0} = (_this: string) => {
7
+ let out: string = Porffor.s\`<${a1}>\`;
8
+
9
+ let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${(2 + a1.length) * 2};
10
+
11
+ let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
12
+ let thisLen: i32 = _this.length;
13
+ let endPtr: i32 = thisPtr + thisLen * 2;
14
+
15
+ while (thisPtr < endPtr) {
16
+ let chr: i32 = Porffor.wasm.i32.load16_u(thisPtr, 0, 4);
17
+ Porffor.wasm.i32.store16(outPtr, chr, 0, 4);
18
+
19
+ thisPtr += 2;
20
+ outPtr += 2;
21
+ }
22
+
23
+ Porffor.wasm.i32.store16(outPtr, 60, 0, 4); // <
24
+ Porffor.wasm.i32.store16(outPtr, 47, 0, 6); // /
25
+
26
+ ${[...a1].map((x, i) => ` Porffor.wasm.i32.store16(outPtr, ${x.charCodeAt(0)}, 0, ${8 + i * 2}); // ${x}`).join('\n')}
27
+
28
+ Porffor.wasm.i32.store16(outPtr, 62, 0, ${8 + a1.length * 2}); // >
29
+
30
+ out.length = thisLen + ${a1.length * 2 + 2 + 3};
31
+
32
+ return out;
33
+ };
34
+ export const __ByteString_prototype_${a0} = (_this: bytestring) => {
35
+ let out: bytestring = Porffor.bs\`<${a1}>\`;
36
+
37
+ let outPtr: i32 = Porffor.wasm\`local.get \${out}\` + ${2 + a1.length};
38
+
39
+ let thisPtr: i32 = Porffor.wasm\`local.get \${_this}\`;
40
+ let thisLen: i32 = _this.length;
41
+ let endPtr: i32 = thisPtr + thisLen;
42
+
43
+ while (thisPtr < endPtr) {
44
+ let chr: i32 = Porffor.wasm.i32.load8_u(thisPtr++, 0, 4);
45
+ Porffor.wasm.i32.store8(outPtr++, chr, 0, 4);
46
+ }
47
+
48
+ Porffor.wasm.i32.store8(outPtr, 60, 0, 4); // <
49
+ Porffor.wasm.i32.store8(outPtr, 47, 0, 5); // /
50
+
51
+ ${[...a1].map((x, i) => ` Porffor.wasm.i32.store8(outPtr, ${x.charCodeAt(0)}, 0, ${6 + i}); // ${x}`).join('\n')}
52
+
53
+ Porffor.wasm.i32.store8(outPtr, 62, 0, ${6 + a1.length}); // >
54
+
55
+ out.length = thisLen + ${a1.length * 2 + 2 + 3};
56
+
57
+ return out;
58
+ };
59
+ `;
60
+
61
+ noArgs('big', 'big');
62
+ noArgs('blink', 'blink');
63
+ noArgs('bold', 'b');
64
+ noArgs('fixed', 'tt');
65
+ noArgs('italics', 'i');
66
+ noArgs('small', 'small');
67
+ noArgs('strike', 'strike');
68
+ noArgs('sub', 'sub');
69
+ noArgs('sup', 'sup');
70
+
71
+ return out;
72
+ };
@@ -0,0 +1,18 @@
1
+ // @porf --valtype=i32
2
+
3
+ export const __String_prototype_trimLeft = (_this: string) => {
4
+ return __String_prototype_trimStart(_this);
5
+ };
6
+
7
+ export const __ByteString_prototype_trimLeft = (_this: string) => {
8
+ return __ByteString_prototype_trimStart(_this);
9
+ };
10
+
11
+
12
+ export const __String_prototype_trimRight = (_this: string) => {
13
+ return __String_prototype_trimEnd(_this);
14
+ };
15
+
16
+ export const __ByteString_prototype_trimRight = (_this: string) => {
17
+ return __ByteString_prototype_trimEnd(_this);
18
+ };