porffor 0.30.0 → 0.30.2
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/compiler/builtins/object.ts +17 -0
- package/compiler/builtins_precompiled.js +6 -0
- package/compiler/codegen.js +100 -32
- package/package.json +1 -1
- package/runner/index.js +8 -3
@@ -665,4 +665,21 @@ export const __Object_prototype_toLocaleString = (_this: any) => __Object_protot
|
|
665
665
|
export const __Object_prototype_valueOf = (_this: any) => {
|
666
666
|
// todo: ToObject
|
667
667
|
return _this;
|
668
|
+
};
|
669
|
+
|
670
|
+
|
671
|
+
export const __Porffor_object_spread = (dst: object, src: any): object => {
|
672
|
+
if (src == null) return;
|
673
|
+
|
674
|
+
// todo/perf: optimize this (and assign) for object instead of reading over object 2x
|
675
|
+
const keys: any[] = __Object_keys(src);
|
676
|
+
const vals: any[] = __Object_values(src);
|
677
|
+
|
678
|
+
const len: i32 = keys.length;
|
679
|
+
for (let i: i32 = 0; i < len; i++) {
|
680
|
+
// target[keys[i]] = vals[i];
|
681
|
+
Porffor.object.expr.init(dst, keys[i], vals[i]);
|
682
|
+
}
|
683
|
+
|
684
|
+
return dst;
|
668
685
|
};
|
@@ -1914,6 +1914,12 @@ export const BuiltinFuncs = function() {
|
|
1914
1914
|
returns: [124,127], typedReturns: 1,
|
1915
1915
|
locals: [], localNames: ["_this","_this#type"],
|
1916
1916
|
};
|
1917
|
+
this.__Porffor_object_spread = {
|
1918
|
+
wasm: (scope, {builtin}) => [[32,2],[33,4],[32,3],[33,5],[2,127],[32,5],[65,0],[70],[4,64,"TYPESWITCH|empty"],[65,1],[12,1],[11],[32,5],[65,7],[70],[4,64,"TYPESWITCH|Object"],[32,4],[68,0,0,0,0,0,0,0,0],[97],[12,1],[11],[32,5],[65,128,1],[70],[4,64,"TYPESWITCH|undefined"],[65,1],[12,1],[11],[65,0],[11,"TYPESWITCH_end"],[4,64],[68,0,0,0,0,0,0,0,0],[65,128,1],[15],[11],[32,2],[32,3],[16, builtin('__Object_keys')],[26],[33,6],[32,2],[32,3],[16, builtin('__Object_values')],[26],[33,8],[32,6],[252,3],[40,1,0],[184],[33,9],[68,0,0,0,0,0,0,0,0],[33,10],[3,64],[32,10],[32,9],[99],[4,64],[32,0],[252,2],[65,7],[32,6],[33,11],[32,10],[34,12],[252,3],[65,9],[108],[32,11],[252,3],[106],[34,13],[43,0,4],[32,13],[45,0,12],[33,7],[252,2],[32,7],[32,8],[33,11],[32,10],[34,12],[252,3],[65,9],[108],[32,11],[252,3],[106],[34,13],[43,0,4],[32,13],[45,0,12],[34,7],[16, builtin('__Porffor_object_expr_init')],[33,7],[183],[26],[32,10],[68,0,0,0,0,0,0,240,63],[160],[33,10],[12,1],[11],[11],[32,0],[65,7],[15]],
|
1919
|
+
params: [124,127,124,127], typedParams: 1,
|
1920
|
+
returns: [124,127], typedReturns: 1,
|
1921
|
+
locals: [124,127,124,127,124,124,124,124,124,127,127,127], localNames: ["dst","dst#type","src","src#type","#logicinner_tmp","#typeswitch_tmp1","keys","#last_type","vals","len","i","#member_obj","#member_prop","#loadArray_offset","#member_allocd","#swap"],
|
1922
|
+
};
|
1917
1923
|
this.__ecma262_NewPromiseReactionJob = {
|
1918
1924
|
wasm: (scope, {builtin}) => [[65,22],[16, builtin('__Porffor_allocateBytes')],[183],[34,4],[33,7],[68,0,0,0,0,0,0,0,0],[33,8],[32,7],[252,3],[32,8],[252,3],[65,9],[108],[106],[34,6],[32,0],[34,5],[57,0,4],[32,6],[65,208,0],[58,0,12],[32,4],[33,7],[68,0,0,0,0,0,0,240,63],[33,8],[32,7],[252,3],[32,8],[252,3],[65,9],[108],[106],[34,6],[32,2],[34,5],[57,0,4],[32,6],[32,3],[58,0,12],[32,4],[65,208,0],[15]],
|
1919
1925
|
params: [124,127,124,127], typedParams: 1,
|
package/compiler/codegen.js
CHANGED
@@ -1438,11 +1438,25 @@ const getType = (scope, _name) => {
|
|
1438
1438
|
|
1439
1439
|
if (Object.hasOwn(builtinVars, name)) return number(builtinVars[name].type ?? TYPES.number, Valtype.i32);
|
1440
1440
|
|
1441
|
-
if (
|
1442
|
-
|
1441
|
+
if (Object.hasOwn(scope.locals, name)) {
|
1442
|
+
if (scope.locals[name]?.metadata?.type != null) return number(scope.locals[name].metadata.type, Valtype.i32);
|
1443
1443
|
|
1444
|
-
|
1445
|
-
|
1444
|
+
const typeLocal = scope.locals[name + '#type'];
|
1445
|
+
if (typeLocal) return [ [ Opcodes.local_get, typeLocal.idx ] ];
|
1446
|
+
|
1447
|
+
// todo: warn here?
|
1448
|
+
return number(TYPES.undefined, Valtype.i32);
|
1449
|
+
}
|
1450
|
+
|
1451
|
+
if (Object.hasOwn(globals, name)) {
|
1452
|
+
if (globals[name]?.metadata?.type != null) return number(globals[name].metadata.type, Valtype.i32);
|
1453
|
+
|
1454
|
+
const typeLocal = globals[name + '#type'];
|
1455
|
+
if (typeLocal) return [ [ Opcodes.global_get, typeLocal.idx ] ];
|
1456
|
+
|
1457
|
+
// todo: warn here?
|
1458
|
+
return number(TYPES.undefined, Valtype.i32);
|
1459
|
+
}
|
1446
1460
|
|
1447
1461
|
if (Object.hasOwn(builtinFuncs, name) || Object.hasOwn(importedFuncs, name) ||
|
1448
1462
|
Object.hasOwn(funcIndex, name) || Object.hasOwn(internalConstrs, name))
|
@@ -1458,17 +1472,31 @@ const setType = (scope, _name, type) => {
|
|
1458
1472
|
|
1459
1473
|
const out = typeof type === 'number' ? number(type, Valtype.i32) : type;
|
1460
1474
|
|
1461
|
-
if (
|
1462
|
-
|
1463
|
-
...out,
|
1464
|
-
[ Opcodes.local_set, scope.locals[name + '#type'].idx ]
|
1465
|
-
];
|
1475
|
+
if (Object.hasOwn(scope.locals, name)) {
|
1476
|
+
if (scope.locals[name]?.metadata?.type != null) return [];
|
1466
1477
|
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1478
|
+
const typeLocal = scope.locals[name + '#type'];
|
1479
|
+
if (typeLocal) return [
|
1480
|
+
...out,
|
1481
|
+
[ Opcodes.local_set, typeLocal.idx ]
|
1482
|
+
];
|
1483
|
+
|
1484
|
+
// todo: warn here?
|
1485
|
+
return [];
|
1486
|
+
}
|
1487
|
+
|
1488
|
+
if (Object.hasOwn(globals, name)) {
|
1489
|
+
if (globals[name]?.metadata?.type != null) return [];
|
1490
|
+
|
1491
|
+
const typeLocal = globals[name + '#type'];
|
1492
|
+
if (typeLocal) return [
|
1493
|
+
...out,
|
1494
|
+
[ Opcodes.global_set, typeLocal.idx ]
|
1495
|
+
];
|
1496
|
+
|
1497
|
+
// todo: warn here?
|
1498
|
+
return [];
|
1499
|
+
}
|
1472
1500
|
|
1473
1501
|
// throw new Error('could not find var');
|
1474
1502
|
return [];
|
@@ -1772,6 +1800,13 @@ const disposeLeftover = wasm => {
|
|
1772
1800
|
const generateExp = (scope, decl) => {
|
1773
1801
|
const expression = decl.expression;
|
1774
1802
|
|
1803
|
+
if (expression.type === 'Literal' && typeof expression.value === 'string') {
|
1804
|
+
if (expression.value === 'use strict') {
|
1805
|
+
scope.strict = true;
|
1806
|
+
}
|
1807
|
+
return [];
|
1808
|
+
}
|
1809
|
+
|
1775
1810
|
const out = generate(scope, expression, undefined, undefined, Prefs.optUnused);
|
1776
1811
|
disposeLeftover(out);
|
1777
1812
|
|
@@ -3096,7 +3131,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3096
3131
|
elements.push(...e.argument.elements);
|
3097
3132
|
} else {
|
3098
3133
|
decls.push(
|
3099
|
-
...generateVarDstr(scope, kind, e.argument
|
3134
|
+
...generateVarDstr(scope, kind, e.argument, {
|
3100
3135
|
type: 'CallExpression',
|
3101
3136
|
callee: {
|
3102
3137
|
type: 'Identifier',
|
@@ -3202,8 +3237,22 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3202
3237
|
}, undefined, global)
|
3203
3238
|
);
|
3204
3239
|
}
|
3205
|
-
} else { // let { ...foo } = {}
|
3206
|
-
|
3240
|
+
} else if (prop.type === 'RestElement') { // let { ...foo } = {}
|
3241
|
+
decls.push(
|
3242
|
+
...generateVarDstr(scope, kind, prop.argument, {
|
3243
|
+
type: 'CallExpression',
|
3244
|
+
callee: {
|
3245
|
+
type: 'Identifier',
|
3246
|
+
name: '__Porffor_object_spread'
|
3247
|
+
},
|
3248
|
+
arguments: [
|
3249
|
+
{ type: 'ObjectExpression', properties: [] },
|
3250
|
+
{ type: 'Identifier', name: tmpName }
|
3251
|
+
]
|
3252
|
+
}, undefined, global)
|
3253
|
+
);
|
3254
|
+
} else {
|
3255
|
+
return todo(scope, `${prop.type} is not supported in object patterns`);
|
3207
3256
|
}
|
3208
3257
|
}
|
3209
3258
|
|
@@ -3565,10 +3614,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3565
3614
|
}
|
3566
3615
|
|
3567
3616
|
if (local === undefined) {
|
3568
|
-
//
|
3569
|
-
|
3570
|
-
// only allow = for this
|
3571
|
-
if (op !== '=') return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`);
|
3617
|
+
// only allow = for this, or if in strict mode always throw
|
3618
|
+
if (op !== '=' || scope.strict) return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
3572
3619
|
|
3573
3620
|
if (type != 'Identifier') {
|
3574
3621
|
const tmpName = '#rhs' + uniqId();
|
@@ -3581,6 +3628,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3581
3628
|
}
|
3582
3629
|
|
3583
3630
|
if (Object.hasOwn(builtinVars, name)) {
|
3631
|
+
if (scope.strict) return internalThrow(scope, 'TypeError', `Cannot assign to non-writable global ${name}`, true);
|
3632
|
+
|
3584
3633
|
// just return rhs (eg `NaN = 2`)
|
3585
3634
|
return generate(scope, decl.right);
|
3586
3635
|
}
|
@@ -3707,7 +3756,6 @@ const generateUnary = (scope, decl) => {
|
|
3707
3756
|
|
3708
3757
|
// if ReferenceError (undeclared var), ignore and return true. otherwise false
|
3709
3758
|
if (!out[1]) {
|
3710
|
-
// todo: throw in strict mode
|
3711
3759
|
// exists
|
3712
3760
|
toReturn = false;
|
3713
3761
|
} else {
|
@@ -3979,10 +4027,9 @@ const generateForOf = (scope, decl) => {
|
|
3979
4027
|
|
3980
4028
|
// setup local for left
|
3981
4029
|
let setVar;
|
3982
|
-
|
3983
4030
|
if (decl.left.type === 'Identifier') {
|
3984
|
-
|
3985
|
-
setVar = generateVarDstr(scope, 'var', decl.left
|
4031
|
+
if (scope.strict) return internalThrow(scope, 'ReferenceError', `${decl.left.name} is not defined`);
|
4032
|
+
setVar = generateVarDstr(scope, 'var', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
|
3986
4033
|
} else {
|
3987
4034
|
// todo: verify this is correct
|
3988
4035
|
const global = scope.name === 'main' && decl.left.kind === 'var';
|
@@ -4347,14 +4394,13 @@ const generateForIn = (scope, decl) => {
|
|
4347
4394
|
localTmp(scope, tmpName + '#type', Valtype.i32);
|
4348
4395
|
|
4349
4396
|
let setVar;
|
4350
|
-
|
4351
4397
|
if (decl.left.type === 'Identifier') {
|
4352
|
-
|
4353
|
-
setVar = generateVarDstr(scope, 'var', decl.left
|
4398
|
+
if (scope.strict) return internalThrow(scope, 'ReferenceError', `${decl.left.name} is not defined`);
|
4399
|
+
setVar = generateVarDstr(scope, 'var', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
|
4354
4400
|
} else {
|
4355
4401
|
// todo: verify this is correct
|
4356
4402
|
const global = scope.name === 'main' && decl.left.kind === 'var';
|
4357
|
-
setVar = generateVarDstr(scope, 'var', decl.left
|
4403
|
+
setVar = generateVarDstr(scope, 'var', decl.left?.declarations?.[0]?.id ?? decl.left, { type: 'Identifier', name: tmpName }, undefined, global);
|
4358
4404
|
}
|
4359
4405
|
|
4360
4406
|
// set type for local
|
@@ -5090,12 +5136,33 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
|
|
5090
5136
|
];
|
5091
5137
|
|
5092
5138
|
if (decl.properties.length > 0) {
|
5093
|
-
const
|
5139
|
+
const tmpName = `#objectexpr${uniqId()}`;
|
5140
|
+
const tmp = localTmp(scope, tmpName, Valtype.i32);
|
5141
|
+
addVarMetadata(scope, tmpName, false, { type: TYPES.object });
|
5142
|
+
|
5094
5143
|
out.push([ Opcodes.local_tee, tmp ]);
|
5095
5144
|
|
5096
5145
|
for (const x of decl.properties) {
|
5097
5146
|
// method, shorthand are made into useful values by parser for us :)
|
5098
|
-
const { computed, kind, key, value } = x;
|
5147
|
+
const { type, argument, computed, kind, key, value } = x;
|
5148
|
+
|
5149
|
+
if (type === 'SpreadElement') {
|
5150
|
+
out.push(
|
5151
|
+
...generateCall(scope, {
|
5152
|
+
type: 'CallExpression',
|
5153
|
+
callee: {
|
5154
|
+
type: 'Identifier',
|
5155
|
+
name: '__Porffor_object_spread'
|
5156
|
+
},
|
5157
|
+
arguments: [
|
5158
|
+
{ type: 'Identifier', name: tmpName },
|
5159
|
+
argument
|
5160
|
+
]
|
5161
|
+
}),
|
5162
|
+
[ Opcodes.drop ]
|
5163
|
+
);
|
5164
|
+
continue;
|
5165
|
+
}
|
5099
5166
|
|
5100
5167
|
let k = key;
|
5101
5168
|
if (!computed && key.type !== 'Literal') k = {
|
@@ -5577,7 +5644,8 @@ const generateFunc = (scope, decl) => {
|
|
5577
5644
|
// not arrow function or main
|
5578
5645
|
(decl.type && decl.type !== 'ArrowFunctionExpression' && decl.type !== 'Program') &&
|
5579
5646
|
// not async or generator
|
5580
|
-
!decl.async && !decl.generator
|
5647
|
+
!decl.async && !decl.generator,
|
5648
|
+
strict: scope.strict
|
5581
5649
|
};
|
5582
5650
|
|
5583
5651
|
funcIndex[name] = func.index;
|
package/package.json
CHANGED
package/runner/index.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
import fs from 'node:fs';
|
3
|
-
globalThis.version = '0.30.
|
3
|
+
globalThis.version = '0.30.2+2e9f2148f';
|
4
4
|
|
5
5
|
// deno compat
|
6
6
|
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
@@ -115,7 +115,10 @@ if (process.argv.length >= 4) {
|
|
115
115
|
if (evalIndex !== -1) {
|
116
116
|
source = process.argv[evalIndex + 1];
|
117
117
|
if (source) {
|
118
|
-
|
118
|
+
// todo: this isn't entirely right, because shells should do the quoting for us but works well enough, see below as well
|
119
|
+
if ((source.startsWith('"') || source.startsWith("'")) && (source.endsWith('"') || source.endsWith("'"))) {
|
120
|
+
source = source.slice(1, -1);
|
121
|
+
}
|
119
122
|
process.argv.splice(evalIndex, 2); // remove flag and value
|
120
123
|
}
|
121
124
|
}
|
@@ -126,7 +129,9 @@ if (process.argv.length >= 4) {
|
|
126
129
|
process.argv.push('--no-opt-unused');
|
127
130
|
source = process.argv[printIndex + 1];
|
128
131
|
if (source) {
|
129
|
-
if (source.startsWith('"') || source.startsWith("'")) source
|
132
|
+
if ((source.startsWith('"') || source.startsWith("'")) && (source.endsWith('"') || source.endsWith("'"))) {
|
133
|
+
source = source.slice(1, -1);
|
134
|
+
}
|
130
135
|
process.argv.splice(printIndex, 2); // remove flag and value
|
131
136
|
}
|
132
137
|
|