porffor 0.14.0-f67c123a1 β†’ 0.16.0-a2e115b05

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/CONTRIBUTING.md CHANGED
@@ -98,7 +98,7 @@ Loads the character code at the pointer `pointer` **for a String**.[^1]
98
98
  Porffor.wasm.i32.store(pointer, length, 0, 0)
99
99
  ```
100
100
 
101
- Stores the length `length` at pointer `pointer`, setting the length of an object. This is mostly unneeded today as you can just do `obj.length = length`. [^2]
101
+ Stores the length `length` at pointer `pointer`, setting the length of an object. This is mostly unneeded today as you can just do `obj.length = length`. (The `0, 4` args are necessary for the Wasm instruction, but you don't need to worry about them (`0` alignment, `0` byte offset).
102
102
 
103
103
  <br>
104
104
 
@@ -198,11 +198,15 @@ Store the character code into the `out` pointer variable, and increment it.
198
198
 
199
199
  ## Porffor-specific TS notes
200
200
 
201
- - For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`)
201
+ - For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`).
202
202
  - You might spot `Porffor.fastOr`/`Porffor.fastAnd`, these are non-short circuiting versions of `||`/`&&`, taking any number of conditions as arguments. You shouldn't don't need to use or worry about these.
203
- - **There are ~no objects, you cannot use them/literals.**
203
+ - **There are ~no objects, you cannot use them.**
204
204
  - Attempt to avoid string/array-heavy code and use more variables instead if possible, easier on memory and CPU/perf.
205
205
  - Do not set a return type for prototype methods, it can cause errors/unexpected results.
206
+ - You cannot use other functions in the file not exported, or variables not inside the current function.
207
+ - `if (...)` uses a fast truthy implementation which is not spec-compliant as most conditions should be strictly checked. To use spec-compliant behavior, use `if (Boolean(...))`.
208
+ - For object (string/array/etc) literals, you must use a variable eg `const out: bytestring = 'foobar'; console.log(out);` instead of `console.log('foobar')` due to precompile's allocator constraints.
209
+ - Generally prefer/use non-strict equality ops (`==`/`!=`).
206
210
 
207
211
  <br>
208
212
 
@@ -229,9 +233,13 @@ builtins/tostring_number: impl radix
229
233
 
230
234
  ## Test262
231
235
 
232
- Make sure you have Test262 cloned already **inside of `test262/`** (`git clone https://github.com/tc39/test262.git test262/test262`) and run `npm install` inside `test262/` too.
236
+ For the first time, ensure you run `./test262/setup.sh`.
233
237
 
234
- Run `node test262` to run all the tests and get an output of total overall test results. The main thing you want to pay attention to is the emoji summary (lol):
238
+ Run `node test262` to run all the tests and get an output of total overall test results.
239
+
240
+ Warning: this will consume 1-6GB of memory and ~90% of all CPU cores while running (depending on thread count), it should take 15-120s depending on machine. You can specify how many threads with `--threads=N`, it will use the number of CPU threads by default.
241
+
242
+ The main thing you want to pay attention to is the emoji summary (lol):
235
243
  ```
236
244
  πŸ§ͺ 50005 | 🀠 7007 (-89) | ❌ 1914 (-32) | πŸ’€ 13904 (-61) | πŸ“ 23477 (-120) | ⏰ 2 | πŸ— 2073 (+302) | πŸ’₯ 1628
237
245
  ```
@@ -239,7 +247,7 @@ Run `node test262` to run all the tests and get an output of total overall test
239
247
  To break this down:
240
248
  πŸ§ͺ total 🀠 pass ❌ fail πŸ’€ runtime error πŸ“ todo (error) ⏰ timeout πŸ—οΈ wasm compile error πŸ’₯ compile error
241
249
 
242
- The diff compared to the last commit (with test262 data) is shown in brackets. Basically, you can passes 🀠 up, and errors πŸ’€πŸ“πŸ—πŸ’₯ down. It is fine if some errors change balance/etc, as long as they are not new failures.
250
+ The diff compared to the last commit (with test262 data) is shown in brackets. Basically, you want passes 🀠 up, and errors πŸ’€πŸ“πŸ—πŸ’₯ down. It is fine if some errors change balance/etc, as long as they are not new failures.
243
251
 
244
252
  It will also log new passes/fails. Be careful as sometimes the overall passes can increase, but other files have also regressed into failures which you might miss. Also keep in mind some tests may have been false positives before, but we can investigate the diff together :)
245
253
 
@@ -251,6 +259,4 @@ It will also log new passes/fails. Be careful as sometimes the overall passes ca
251
259
 
252
260
  <br>
253
261
 
254
- [^1]: The `0, 4` args are necessary for the Wasm instruction, but you don't need to worry about them (`0` alignment, `4` byte offset for length).
255
-
256
- [^2]: The `0, 4` args are necessary for the Wasm instruction, but you don't need to worry about them (`0` alignment, `0` byte offset).
262
+ [^1]: The `0, 4` args are necessary for the Wasm instruction, but you don't need to worry about them (`0` alignment, `4` byte offset for length).
package/README.md CHANGED
@@ -14,7 +14,7 @@ Porffor is primarily built from scratch, the only thing that is not is the parse
14
14
  Expect nothing to work! Only very limited JS is currently supported. See files in `bench` for examples.
15
15
 
16
16
  ### Install
17
- **`npm install -g porffor`**. It's that easy (hopefully) :)
17
+ **`npm install -g porffor@latest`**. It's that easy (hopefully) :)
18
18
 
19
19
  ### Trying a REPL
20
20
  **`porf`**. Just run it with no script file argument.
@@ -266,8 +266,6 @@ Basically none right now (other than giving people headaches). Potential ideas:
266
266
  No particular order and no guarentees, just what could happen soonβ„’
267
267
 
268
268
  - Arrays
269
- - More of `Array` prototype
270
- - Arrays/strings inside arrays
271
269
  - Destructuring
272
270
  - Objects
273
271
  - Basic object expressions (eg `{}`, `{ a: 0 }`)
@@ -315,16 +313,10 @@ Porffor intentionally does not use Wasm proposals which are not commonly impleme
315
313
 
316
314
  - Multi-value **(required)**
317
315
  - Non-trapping float-to-int conversions **(required)**
318
- - Bulk memory operations (required, but uncommonly used)
319
- - Exception handling (optional, for errors)
316
+ - Bulk memory operations (optional, can get away without sometimes)
317
+ - Exception handling (optional, only for errors)
320
318
  - Tail calls (opt-in, off by default)
321
319
 
322
- ## Isn't this the same as AssemblyScript/other Wasm langs?
323
- No. they are not alike at all internally and have very different goals/ideals:
324
- - Porffor is made as a generic JS engine, not for Wasm stuff specifically
325
- - Porffor primarily consumes JS
326
- - Porffor is written in pure JS and compiles itself, not using Binaryen/etc
327
- - (Also I didn't know it existed when I started this, lol)
328
320
 
329
321
  ## FAQ
330
322
 
@@ -338,5 +330,9 @@ No. they are not alike at all internally and have very different goals/ideals:
338
330
  ### 2. Why at all?
339
331
  Yes!
340
332
 
341
- ### 3. But what about spec compliance?
342
- Lol, no. (sorry.)
333
+ ## 3. Isn't this the same as AssemblyScript/other Wasm langs?
334
+ No. they are not alike at all internally and have very different goals/ideals:
335
+ - Porffor is made as a generic JS engine, not for Wasm stuff specifically
336
+ - Porffor primarily consumes JS
337
+ - Porffor is written in pure JS and compiles itself, not using Binaryen/etc
338
+ - (Also I didn't know it existed when I started this, lol)
package/asur/index.js CHANGED
@@ -1155,7 +1155,7 @@ if (bc.porfFunc && paused && op) {
1155
1155
  switch (byg(
1156
1156
  paused,
1157
1157
  funcLines[currentFunc] + currentLine,
1158
- '\x1b[1masur\x1b[22m: ' + callStack.join(' -> ') + (parents.length > 1 ? \` | \${parents.slice(1).map(x => invOpcodes[x.opcode]).join(' -> ')}\` : ''),
1158
+ '\x1b[1masur debugger\x1b[22m: ' + callStack.join(' -> ') + (parents.length > 1 ? \` | \${parents.slice(1).map(x => invOpcodes[x.opcode]).join(' -> ')}\` : ''),
1159
1159
  [
1160
1160
  {
1161
1161
  x: termWidth - 1 - width - 6,
package/compiler/2c.js CHANGED
@@ -29,8 +29,8 @@ typedef double f64;
29
29
  f64 NAN = 0e+0/0e+0;
30
30
 
31
31
  struct ReturnValue {
32
- ${CValtype.f64} value;
33
- ${CValtype.i32} type;
32
+ f64 value;
33
+ i32 type;
34
34
  };\n\n`;
35
35
 
36
36
  // todo: is memcpy/etc safe with host endianness?
@@ -41,60 +41,60 @@ const CMemFuncs = {
41
41
  [Opcodes.i32_store]: {
42
42
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
43
43
  args: ['pointer', 'value'],
44
- argTypes: [CValtype.i32, CValtype.i32],
44
+ argTypes: ['i32', 'i32'],
45
45
  returns: false
46
46
  },
47
47
  [Opcodes.i32_store16]: {
48
48
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
49
49
  args: ['pointer', 'value'],
50
- argTypes: [CValtype.i32, CValtype.i16],
50
+ argTypes: ['i32', 'i16'],
51
51
  returns: false
52
52
  },
53
53
  [Opcodes.i32_store8]: {
54
54
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
55
55
  args: ['pointer', 'value'],
56
- argTypes: [CValtype.i32, CValtype.i8],
56
+ argTypes: ['i32', 'i8'],
57
57
  returns: false
58
58
  },
59
59
 
60
60
  [Opcodes.i32_load]: {
61
- c: `${CValtype.i32} out;
61
+ c: `i32 out;
62
62
  memcpy(&out, _memory + offset + pointer, sizeof(out));
63
63
  return out;`,
64
64
  args: ['pointer'],
65
- argTypes: [CValtype.i32],
66
- returns: CValtype.i32
65
+ argTypes: ['i32'],
66
+ returns: 'i32'
67
67
  },
68
68
  [Opcodes.i32_load16_u]: {
69
- c: `${CValtype.i16} out;
69
+ c: `i16 out;
70
70
  memcpy(&out, _memory + offset + pointer, sizeof(out));
71
71
  return out;`,
72
72
  args: ['pointer'],
73
- argTypes: [CValtype.i32],
74
- returns: CValtype.i32
73
+ argTypes: ['i32'],
74
+ returns: 'i32'
75
75
  },
76
76
  [Opcodes.i32_load8_u]: {
77
- c: `${CValtype.i8} out;
77
+ c: `i8 out;
78
78
  memcpy(&out, _memory + offset + pointer, sizeof(out));
79
79
  return out;`,
80
80
  args: ['pointer'],
81
- argTypes: [CValtype.i32],
82
- returns: CValtype.i32
81
+ argTypes: ['i32'],
82
+ returns: 'i32'
83
83
  },
84
84
 
85
85
  [Opcodes.f64_store]: {
86
86
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
87
87
  args: ['pointer', 'value'],
88
- argTypes: [CValtype.i32, CValtype.f64],
88
+ argTypes: ['i32', 'f64'],
89
89
  returns: false
90
90
  },
91
91
  [Opcodes.f64_load]: {
92
- c: `${CValtype.f64} out;
92
+ c: `f64 out;
93
93
  memcpy(&out, _memory + offset + pointer, sizeof(out));
94
94
  return out;`,
95
95
  args: ['pointer'],
96
- argTypes: [CValtype.i32],
97
- returns: CValtype.f64
96
+ argTypes: ['i32'],
97
+ returns: 'f64'
98
98
  },
99
99
  };
100
100
 
@@ -108,7 +108,7 @@ for (const x in CValtype) {
108
108
 
109
109
  const removeBrackets = str => {
110
110
  // return str;
111
- // if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
111
+ // if (str.startsWith('(i32)(u32)')) return '(i32)(u32)(' + removeBrackets(str.slice(22, -1)) + ')';
112
112
 
113
113
  for (const x in CValtype) {
114
114
  const p = `(${x})`;
@@ -119,6 +119,9 @@ const removeBrackets = str => {
119
119
  };
120
120
 
121
121
  export default ({ funcs, globals, tags, data, exceptions, pages }) => {
122
+ // fix declaring order for c
123
+ funcs.reverse();
124
+
122
125
  const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
123
126
  for (const k in x) {
124
127
  acc[x[k]] = k;
@@ -153,17 +156,22 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
153
156
  }
154
157
 
155
158
  if (data.length > 0) {
156
- prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
159
+ prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n '));
160
+ }
161
+
162
+ if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
163
+ prepend.set('argv', `int _argc; char** _argv;`);
164
+ prependMain.set('argv', `_argc = argc; _argv = argv;`);
157
165
  }
158
166
 
159
167
  if (out) out += '\n';
160
168
 
161
169
  let depth = 1;
162
170
  let brDepth = 0;
163
- const line = (str, semi = true) => out += `${' '.repeat(depth * 2 + brDepth * 2)}${str}${semi ? ';' : ''}\n`;
171
+ const line = (str, semi = true) => out += `${' '.repeat((depth + brDepth) * 2)}${str}${semi ? ';' : ''}\n`;
164
172
  const lines = lines => {
165
173
  for (const x of lines) {
166
- out += `${' '.repeat(depth * 2)}${x}\n`;
174
+ out += `${' '.repeat((depth + brDepth) * 2)}${x}\n`;
167
175
  }
168
176
  };
169
177
 
@@ -199,6 +207,8 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
199
207
  depth = 1;
200
208
  brDepth = 0;
201
209
 
210
+ let retTmpId = 0;
211
+
202
212
  const invLocals = inv(f.locals, x => x.idx);
203
213
 
204
214
  for (const x in invLocals) {
@@ -207,11 +217,12 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
207
217
 
208
218
  const returns = f.returns.length > 0;
209
219
 
210
- const shouldInline = f.internal;
211
- out += `${f.name === 'main' ? 'int' : (f.internal ? (returns ? CValtype.f64 : 'void') : 'struct ReturnValue')} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
220
+ const shouldInline = false; // f.internal;
221
+ if (f.name === 'main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
222
+ else out += `${f.internal ? (returns ? 'f64' : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
212
223
 
213
224
  if (f.name === 'main') {
214
- out += [...prependMain.values()].join('\n');
225
+ out += ' ' + [...prependMain.values()].join('\n ');
215
226
  if (prependMain.size > 0) out += '\n\n';
216
227
  }
217
228
 
@@ -272,12 +283,12 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
272
283
  switch (i[1]) {
273
284
  // i32_trunc_sat_f64_s
274
285
  case 0x02:
275
- vals.push(`(${CValtype.i32})(${vals.pop()})`);
286
+ vals.push(`(i32)(${vals.pop()})`);
276
287
  break;
277
288
 
278
289
  // i32_trunc_sat_f64_u
279
290
  case 0x03:
280
- vals.push(`(${CValtype.u32})(${vals.pop()})`);
291
+ vals.push(`(u32)(${vals.pop()})`);
281
292
  break;
282
293
  }
283
294
 
@@ -326,7 +337,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
326
337
 
327
338
  case Opcodes.f64_trunc:
328
339
  // vals.push(`trunc(${vals.pop()})`);
329
- vals.push(`(${CValtype.i32})(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
340
+ vals.push(`(i32)(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
330
341
  break;
331
342
 
332
343
  case Opcodes.f64_convert_i32_u:
@@ -334,7 +345,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
334
345
  case Opcodes.f64_convert_i64_u:
335
346
  case Opcodes.f64_convert_i64_s:
336
347
  // int to f64
337
- vals.push(`(${CValtype.f64})(${removeBrackets(vals.pop())})`);
348
+ vals.push(`(f64)(${removeBrackets(vals.pop())})`);
338
349
  break;
339
350
 
340
351
  case Opcodes.i32_eqz:
@@ -342,7 +353,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
342
353
  vals.push(`!(${removeBrackets(vals.pop())})`);
343
354
  } else {
344
355
  let cond = '(' + removeBrackets(vals.pop());
345
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `${cond.slice(`(${CValtype.i32})`.length)}) == 0e+0`;
356
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} == 0e+0`;
346
357
  else cond += ') == 0';
347
358
  vals.push(cond);
348
359
  }
@@ -357,7 +368,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
357
368
  case Opcodes.if: {
358
369
  let cond = removeBrackets(vals.pop());
359
370
  if (!lastCond) {
360
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
371
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} != 0e+0`;
361
372
  else cond = `(${cond}) != 0`;
362
373
  }
363
374
 
@@ -423,28 +434,16 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
423
434
  const importFunc = importFuncs[i[1]];
424
435
  switch (importFunc.name) {
425
436
  case 'print':
426
- // line(`printf("%f\\n", ${vals.pop()})`);
427
437
  line(`printf("${valtype === 'f64' ? '%g' : '%i'}\\n", ${vals.pop()})`);
428
438
  includes.set('stdio.h', true);
429
439
  break;
430
440
  case 'printChar':
431
- line(`printf("%c", (int)(${vals.pop()}))`);
441
+ line(`putchar((int)(${vals.pop()}))`);
432
442
  includes.set('stdio.h', true);
433
443
  break;
434
444
 
435
445
  case 'time':
436
446
  line(`double _time_out`);
437
- /* platformSpecific(
438
- `FILETIME _time_filetime;
439
- GetSystemTimeAsFileTime(&_time_filetime);
440
-
441
- ULARGE_INTEGER _time_ularge;
442
- _time_ularge.LowPart = _time_filetime.dwLowDateTime;
443
- _time_ularge.HighPart = _time_filetime.dwHighDateTime;
444
- _time_out = (_time_ularge.QuadPart - 116444736000000000i64) / 10000.;`,
445
- `struct timespec _time;
446
- clock_gettime(CLOCK_MONOTONIC, &_time);
447
- _time_out = _time.tv_nsec / 1000000.;`); */
448
447
  platformSpecific(
449
448
  `LARGE_INTEGER _time_freq, _time_t;
450
449
  QueryPerformanceFrequency(&_time_freq);
@@ -459,6 +458,61 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
459
458
  winIncludes.set('windows.h', true);
460
459
  break;
461
460
 
461
+ case '__Porffor_readArgv': {
462
+ prepend.set('__Porffor_readArgv',
463
+ `i32 __Porffor_readArgv(u32 index, u32 outPtr) {
464
+ if (index >= _argc) {
465
+ return -1;
466
+ }
467
+
468
+ char* arg = _argv[index];
469
+
470
+ u32 read = 0;
471
+ char* out = _memory + outPtr + 4;
472
+ char ch;
473
+ while ((ch = *(arg++)) != 0) {
474
+ out[read++] = ch;
475
+ }
476
+
477
+ memcpy(_memory + outPtr, &read, sizeof(read));
478
+ return read;
479
+ }`);
480
+
481
+ const outPtr = vals.pop();
482
+ const index = vals.pop();
483
+ vals.push(`(f64)__Porffor_readArgv((u32)(${index}), (u32)(${outPtr}))`);
484
+ break;
485
+ }
486
+
487
+ case '__Porffor_readFile': {
488
+ includes.set('stdio.h', true);
489
+
490
+ prepend.set('__Porffor_readFile',
491
+ `i32 __Porffor_readFile(u32 pathPtr, u32 outPtr) {
492
+ char* path = _memory + pathPtr + 4;
493
+ FILE* fp = fopen(path, "r");
494
+ if (fp == NULL) {
495
+ return -1;
496
+ }
497
+
498
+ u32 read = 0;
499
+ char* out = _memory + outPtr + 4;
500
+ char ch;
501
+ while ((ch = fgetc(fp)) != EOF) {
502
+ out[read++] = ch;
503
+ }
504
+
505
+ fclose(fp);
506
+
507
+ memcpy(_memory + outPtr, &read, sizeof(read));
508
+ return read;
509
+ }`);
510
+ const outPtr = vals.pop();
511
+ const pathPtr = vals.pop();
512
+ vals.push(`(f64)__Porffor_readFile((u32)(${pathPtr}), (u32)(${outPtr}))`);
513
+ break;
514
+ }
515
+
462
516
  default:
463
517
  log.warning('2c', `unimplemented import: ${importFunc.name}`);
464
518
  break;
@@ -474,9 +528,10 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
474
528
  if (func.internal) {
475
529
  vals.push(`${sanitize(func.name)}(${args.join(', ')})`);
476
530
  } else {
477
- line(`const struct ReturnValue _ = ${sanitize(func.name)}(${args.join(', ')})`);
478
- vals.push(`_.value`);
479
- vals.push(`_.type`);
531
+ const id = retTmpId++;
532
+ line(`const struct ReturnValue _${id} = ${sanitize(func.name)}(${args.join(', ')})`);
533
+ vals.push(`_${id}.value`);
534
+ vals.push(`_${id}.type`);
480
535
  }
481
536
  } else line(`${sanitize(func.name)}(${args.join(', ')})`);
482
537
 
@@ -506,7 +561,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
506
561
 
507
562
  let cond = removeBrackets(vals.pop());
508
563
  if (!lastCond) {
509
- if (cond.startsWith(`(${CValtype.i32})`)) cond = `(${cond.slice(`(${CValtype.i32})`.length)}) != 0e+0`;
564
+ if (cond.startsWith(`(i32)`)) cond = `${cond.slice(5)} != 0e+0`;
510
565
  else cond = `(${cond}) != 0`;
511
566
  }
512
567
 
@@ -536,8 +591,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
536
591
  const name = invOpcodes[i[0]];
537
592
  const func = CMemFuncs[i[0]];
538
593
  if (!prepend.has(name)) {
539
- prepend.set(name, `${func.returns || 'void'} ${name}(${CValtype.i32} align, ${CValtype.i32} offset, ${func.args.map((x, i) => `${func.argTypes[i]} ${x}`).join(', ')}) {\n ${func.c.replaceAll('\n', '\n ')}\n}\n`);
540
- // generate func c and prepend
594
+ prepend.set(name, `${func.returns || 'void'} ${name}(i32 align, i32 offset, ${func.args.map((x, i) => `${func.argTypes[i]} ${x}`).join(', ')}) {\n ${func.c.replaceAll('\n', '\n ')}\n}\n`);
541
595
  }
542
596
 
543
597
  const immediates = [ i[1], read_unsignedLEB128(i.slice(2)) ];
@@ -572,7 +626,6 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
572
626
  depth = 0;
573
627
 
574
628
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
575
-
576
629
  out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + alwaysPreface + [...prepend.values()].join('\n') + '\n\n' + out;
577
630
 
578
631
  return out.trim();
@@ -65,6 +65,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
65
65
  importFuncs = [...imports.values()];
66
66
 
67
67
  // fix call indexes for non-imports
68
+ // also fix call_indirect types
68
69
  const delta = importedFuncs.length - importFuncs.length;
69
70
  for (const f of funcs) {
70
71
  f.originalIndex = f.index;
@@ -74,6 +75,16 @@ export default (funcs, globals, tags, pages, data, flags) => {
74
75
  if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] >= importedFuncs.length) {
75
76
  inst[1] -= delta;
76
77
  }
78
+
79
+ if (inst[0] === Opcodes.call_indirect) {
80
+ const params = [];
81
+ for (let i = 0; i < inst[1]; i++) {
82
+ params.push(valtypeBinary, Valtype.i32);
83
+ }
84
+
85
+ const returns = [ valtypeBinary, Valtype.i32 ];
86
+ inst[1] = getType(params, returns);
87
+ }
77
88
  }
78
89
  }
79
90
  }
@@ -101,10 +112,24 @@ export default (funcs, globals, tags, pages, data, flags) => {
101
112
  encodeVector([ [
102
113
  0x00,
103
114
  Opcodes.i32_const, 0, Opcodes.end,
104
- encodeVector(funcs.map(x => x.index))
115
+ ...encodeVector(funcs.map(x => x.index))
105
116
  ] ])
106
117
  );
107
118
 
119
+ if (pages.has('func argc lut')) {
120
+ // generate func argc lut data
121
+ const bytes = [];
122
+ for (let i = 0; i < funcs.length; i++) {
123
+ const argc = Math.floor(funcs[i].params.length / 2);
124
+ bytes.push(argc % 256, (argc / 256 | 0) % 256);
125
+ }
126
+
127
+ data.push({
128
+ offset: pages.get('func argc lut').ind * pageSize,
129
+ bytes
130
+ });
131
+ }
132
+
108
133
  // const t0 = performance.now();
109
134
 
110
135
  // specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
@@ -1,4 +1,5 @@
1
1
  // @porf --valtype=i32
2
+ import type {} from './porffor.d.ts';
2
3
 
3
4
  export const __String_prototype_trimLeft = (_this: string) => {
4
5
  return __String_prototype_trimStart(_this);
@@ -1,3 +1,5 @@
1
+ import type {} from './porffor.d.ts';
2
+
1
3
  export const __Array_isArray = (x: unknown): boolean =>
2
4
  // Porffor.wasm`local.get ${x+1}` == Porffor.TYPES.array;
3
5
  Porffor.rawType(x) == Porffor.TYPES.array;
@@ -27,14 +29,16 @@ export const __Array_prototype_slice = (_this: any[], start: number, end: number
27
29
  let outPtr: i32 = Porffor.wasm`local.get ${out}`;
28
30
  let thisPtr: i32 = Porffor.wasm`local.get ${_this}`;
29
31
 
30
- const thisPtrEnd: i32 = thisPtr + end * 8;
32
+ const thisPtrEnd: i32 = thisPtr + end * 9;
31
33
 
32
- thisPtr += start * 8;
34
+ thisPtr += start * 9;
33
35
 
34
36
  while (thisPtr < thisPtrEnd) {
35
37
  Porffor.wasm.f64.store(outPtr, Porffor.wasm.f64.load(thisPtr, 0, 4), 0, 4);
36
- thisPtr += 8;
37
- outPtr += 8;
38
+ Porffor.wasm.i32.store8(outPtr + 8, Porffor.wasm.i32.load8_u(thisPtr + 8, 0, 4), 0, 4);
39
+
40
+ thisPtr += 9;
41
+ outPtr += 9;
38
42
  }
39
43
 
40
44
  out.length = end - start;
@@ -142,4 +146,80 @@ export const __Array_prototype_toReversed = (_this: any[]) => {
142
146
 
143
147
  export const __Array_prototype_valueOf = (_this: any[]) => {
144
148
  return _this;
149
+ };
150
+
151
+
152
+ export const __Array_prototype_forEach = (_this: any[], callbackFn: any) => {
153
+ const len: i32 = _this.length;
154
+ let i: i32 = 0;
155
+ while (i < len) {
156
+ callbackFn(_this[i], i++, _this);
157
+ }
158
+ };
159
+
160
+ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
161
+ const out: any[] = [];
162
+
163
+ const len: i32 = _this.length;
164
+ let i: i32 = 0;
165
+ while (i < len) {
166
+ const el: any = _this[i];
167
+ if (Boolean(callbackFn(el, i++, _this))) out.push(el);
168
+ }
169
+
170
+ return out;
171
+ };
172
+
173
+ export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
174
+ const out: any[] = [];
175
+
176
+ const len: i32 = _this.length;
177
+ let i: i32 = 0;
178
+ while (i < len) {
179
+ out.push(callbackFn(_this[i], i++, _this));
180
+ }
181
+
182
+ return out;
183
+ };
184
+
185
+ export const __Array_prototype_find = (_this: any[], callbackFn: any) => {
186
+ const len: i32 = _this.length;
187
+ let i: i32 = 0;
188
+ while (i < len) {
189
+ const el: any = _this[i];
190
+ if (Boolean(callbackFn(el, i++, _this))) return el;
191
+ }
192
+ };
193
+
194
+ export const __Array_prototype_findLast = (_this: any[], callbackFn: any) => {
195
+ let i: i32 = _this.length;
196
+ while (i > 0) {
197
+ const el: any = _this[--i];
198
+ if (Boolean(callbackFn(el, i, _this))) return el;
199
+ }
200
+ };
201
+
202
+ export const __Array_prototype_findIndex = (_this: any[], callbackFn: any) => {
203
+ const len: i32 = _this.length;
204
+ let i: i32 = 0;
205
+ while (i < len) {
206
+ if (Boolean(callbackFn(_this[i], i++, _this))) return i;
207
+ }
208
+ };
209
+
210
+ export const __Array_prototype_findLastIndex = (_this: any[], callbackFn: any) => {
211
+ let i: i32 = _this.length;
212
+ while (i > 0) {
213
+ if (Boolean(callbackFn(_this[--i], i, _this))) return i;
214
+ }
215
+ };
216
+
217
+ export const __Array_prototype_every = (_this: any[], callbackFn: any) => {
218
+ const len: i32 = _this.length;
219
+ let i: i32 = 0;
220
+ while (i < len) {
221
+ if (!Boolean(callbackFn(_this[i], i++, _this))) return false;
222
+ }
223
+
224
+ return true;
145
225
  };
@@ -1,4 +1,5 @@
1
1
  // @porf --valtype=i32
2
+ import type {} from './porffor.d.ts';
2
3
 
3
4
  export const btoa = (input: bytestring): bytestring => {
4
5
  const keyStr: bytestring = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
@@ -1,3 +1,5 @@
1
+ import type {} from './porffor.d.ts';
2
+
1
3
  // 20.3.3.2 Boolean.prototype.toString ()
2
4
  // https://tc39.es/ecma262/#sec-boolean.prototype.tostring
3
5
  export const __Boolean_prototype_toString = (_this: boolean) => {
@@ -15,4 +17,4 @@ export const __Boolean_prototype_toString = (_this: boolean) => {
15
17
  export const __Boolean_prototype_valueOf = (_this: boolean) => {
16
18
  // 1. Return ? ThisBooleanValue(this value).
17
19
  return _this;
18
- };
20
+ };
@@ -0,0 +1,6 @@
1
+ import type {} from './porffor.d.ts';
2
+
3
+ export const __console_clear = () => {
4
+ const clear: bytestring = '\x1b[1;1H\x1b[J';
5
+ Porffor.print(clear);
6
+ };
@@ -1,4 +1,5 @@
1
1
  // @porf --valtype=i32
2
+ import type {} from './porffor.d.ts';
2
3
 
3
4
  export const __crypto_randomUUID = (): bytestring => {
4
5
  let bytes: bytestring = '................';
@@ -1,3 +1,5 @@
1
+ import type {} from './porffor.d.ts';
2
+
1
3
  // 21.4.1.3 Day (t)
2
4
  // https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-day
3
5
  // 1. Return 𝔽(floor(ℝ(t / msPerDay))).