porffor 0.14.0-c6edfd328 → 0.14.0-c6f2015a7
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 +7 -6
- package/README.md +9 -13
- package/compiler/2c.js +68 -3
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +71 -1
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +2 -0
- package/compiler/builtins/console.ts +4 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/set.ts +14 -1
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +2 -1
- package/compiler/builtins.js +15 -4
- package/compiler/codegen.js +158 -140
- package/compiler/decompile.js +4 -0
- package/compiler/generated_builtins.js +305 -9
- package/compiler/index.js +2 -1
- package/compiler/parse.js +1 -1
- package/compiler/precompile.js +2 -2
- package/package.json +1 -1
- package/runner/index.js +4 -3
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`.
|
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,14 @@ 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
|
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.
|
206
209
|
|
207
210
|
<br>
|
208
211
|
|
@@ -255,6 +258,4 @@ It will also log new passes/fails. Be careful as sometimes the overall passes ca
|
|
255
258
|
|
256
259
|
<br>
|
257
260
|
|
258
|
-
[^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).
|
259
|
-
|
260
|
-
[^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).
|
261
|
+
[^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 (
|
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
|
-
|
342
|
-
|
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/compiler/2c.js
CHANGED
@@ -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;
|
@@ -156,6 +159,11 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
156
159
|
prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
|
157
160
|
}
|
158
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;`);
|
165
|
+
}
|
166
|
+
|
159
167
|
if (out) out += '\n';
|
160
168
|
|
161
169
|
let depth = 1;
|
@@ -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,8 +217,9 @@ 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
|
-
|
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 ? CValtype.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
225
|
out += [...prependMain.values()].join('\n');
|
@@ -459,6 +470,60 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
459
470
|
winIncludes.set('windows.h', true);
|
460
471
|
break;
|
461
472
|
|
473
|
+
case '__Porffor_readArgv':
|
474
|
+
includes.set('stdlib.h', true);
|
475
|
+
|
476
|
+
prepend.set('__Porffor_readArgv',
|
477
|
+
`void __Porffor_readArgv(u32 index, u32 outPtr) {
|
478
|
+
if (index >= _argc) {
|
479
|
+
printf("expected %d arguments\\n", index);
|
480
|
+
exit(1);
|
481
|
+
}
|
482
|
+
|
483
|
+
char* arg = _argv[index];
|
484
|
+
|
485
|
+
u32 read = 0;
|
486
|
+
char* out = _memory + outPtr + 4;
|
487
|
+
char ch;
|
488
|
+
while ((ch = *(arg++)) != 0) {
|
489
|
+
out[read++] = ch;
|
490
|
+
}
|
491
|
+
|
492
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
493
|
+
}`);
|
494
|
+
|
495
|
+
line(`__Porffor_readArgv((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
496
|
+
vals.pop();
|
497
|
+
break;
|
498
|
+
|
499
|
+
case '__Porffor_readFile':
|
500
|
+
includes.set('stdio.h', true);
|
501
|
+
includes.set('stdlib.h', true);
|
502
|
+
|
503
|
+
prepend.set('__Porffor_readFile',
|
504
|
+
`void __Porffor_readFile(u32 pathPtr, u32 outPtr) {
|
505
|
+
char* path = _memory + pathPtr + 4;
|
506
|
+
FILE* fp = fopen(path, "r");
|
507
|
+
if (fp == NULL) {
|
508
|
+
printf("failed to open file: %s\\n", path);
|
509
|
+
exit(1);
|
510
|
+
}
|
511
|
+
|
512
|
+
u32 read = 0;
|
513
|
+
char* out = _memory + outPtr + 4;
|
514
|
+
char ch;
|
515
|
+
while ((ch = fgetc(fp)) != EOF) {
|
516
|
+
out[read++] = ch;
|
517
|
+
}
|
518
|
+
|
519
|
+
fclose(fp);
|
520
|
+
|
521
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
522
|
+
}`);
|
523
|
+
line(`__Porffor_readFile((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
524
|
+
vals.pop();
|
525
|
+
break;
|
526
|
+
|
462
527
|
default:
|
463
528
|
log.warning('2c', `unimplemented import: ${importFunc.name}`);
|
464
529
|
break;
|
@@ -474,7 +539,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
474
539
|
if (func.internal) {
|
475
540
|
vals.push(`${sanitize(func.name)}(${args.join(', ')})`);
|
476
541
|
} else {
|
477
|
-
line(`const struct ReturnValue _ = ${sanitize(func.name)}(${args.join(', ')})`);
|
542
|
+
line(`const struct ReturnValue _${retTmpId++} = ${sanitize(func.name)}(${args.join(', ')})`);
|
478
543
|
vals.push(`_.value`);
|
479
544
|
vals.push(`_.type`);
|
480
545
|
}
|
@@ -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;
|
@@ -146,10 +148,78 @@ export const __Array_prototype_valueOf = (_this: any[]) => {
|
|
146
148
|
return _this;
|
147
149
|
};
|
148
150
|
|
149
|
-
|
151
|
+
|
152
|
+
export const __Array_prototype_forEach = (_this: any[], callbackFn: any) => {
|
150
153
|
const len: i32 = _this.length;
|
151
154
|
let i: i32 = 0;
|
152
155
|
while (i < len) {
|
153
156
|
callbackFn(_this[i], i++, _this);
|
154
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;
|
155
225
|
};
|
package/compiler/builtins/int.ts
CHANGED