porffor 0.59.8 → 0.60.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/compiler/2c.js +7 -5
- package/compiler/builtins/console.ts +0 -56
- package/compiler/builtins/json.ts +206 -14
- package/compiler/builtins_precompiled.js +497 -493
- package/compiler/codegen.js +79 -22
- package/package.json +1 -1
- package/runtime/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -553,9 +553,7 @@ const lookup = (scope, name, failEarly = false) => {
|
|
553
553
|
|
554
554
|
if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
555
555
|
includeBuiltin(scope, name);
|
556
|
-
}
|
557
|
-
|
558
|
-
if (Object.hasOwn(internalConstrs, name)) {
|
556
|
+
} else if (Object.hasOwn(internalConstrs, name)) {
|
559
557
|
// todo: return an actual something
|
560
558
|
return [ number(1) ];
|
561
559
|
}
|
@@ -892,7 +890,21 @@ const performLogicOp = (scope, op, left, right, leftType, rightType) => {
|
|
892
890
|
];
|
893
891
|
};
|
894
892
|
|
895
|
-
const concatStrings = (scope, left, right, leftType, rightType) => [
|
893
|
+
const concatStrings = (scope, left, right, leftType, rightType) => ((knownType(scope, leftType) | TYPE_FLAGS.parity) === TYPES.bytestring && (knownType(scope, rightType) | TYPE_FLAGS.parity) === TYPES.bytestring) ? [
|
894
|
+
// known types, use strcat direct
|
895
|
+
...left,
|
896
|
+
Opcodes.i32_to_u,
|
897
|
+
...leftType,
|
898
|
+
|
899
|
+
...right,
|
900
|
+
Opcodes.i32_to_u,
|
901
|
+
...rightType,
|
902
|
+
|
903
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_strcat').index ],
|
904
|
+
...setLastType(scope),
|
905
|
+
Opcodes.i32_from_u
|
906
|
+
] : [
|
907
|
+
// unknown types, check if need to coerce
|
896
908
|
...left,
|
897
909
|
...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
|
898
910
|
...leftType,
|
@@ -1528,8 +1540,9 @@ const generateLogicExp = (scope, decl) =>
|
|
1528
1540
|
performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
|
1529
1541
|
|
1530
1542
|
const getInferred = (scope, name, global = false) => {
|
1543
|
+
const isConst = getVarMetadata(scope, name, global)?.kind === 'const';
|
1531
1544
|
if (global) {
|
1532
|
-
if (globalInfer.has(name) && inferLoopPrev.length === 0) return globalInfer.get(name);
|
1545
|
+
if (globalInfer.has(name) && (isConst || inferLoopPrev.length === 0)) return globalInfer.get(name);
|
1533
1546
|
} else if (scope.inferTree) {
|
1534
1547
|
for (let i = scope.inferTree.length - 1; i >= 0; i--) {
|
1535
1548
|
const x = scope.inferTree[i];
|
@@ -1541,11 +1554,12 @@ const getInferred = (scope, name, global = false) => {
|
|
1541
1554
|
};
|
1542
1555
|
|
1543
1556
|
const setInferred = (scope, name, type, global = false) => {
|
1557
|
+
const isConst = getVarMetadata(scope, name, global)?.kind === 'const';
|
1544
1558
|
scope.inferTree ??= [];
|
1545
1559
|
|
1546
1560
|
if (global) {
|
1547
1561
|
// set inferred type in global if not already and not in a loop, else make it null
|
1548
|
-
globalInfer.set(name, globalInfer.has(name) || inferLoopPrev.length > 0 ? null : type);
|
1562
|
+
globalInfer.set(name, globalInfer.has(name) || (!isConst && inferLoopPrev.length > 0) ? null : type);
|
1549
1563
|
} else {
|
1550
1564
|
// set inferred type in top
|
1551
1565
|
const top = scope.inferTree.at(-1);
|
@@ -1771,6 +1785,8 @@ const getNodeType = (scope, node) => {
|
|
1771
1785
|
(knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)
|
1772
1786
|
) return TYPES.string;
|
1773
1787
|
|
1788
|
+
if (knownLeft === TYPES.bytestring && knownRight === TYPES.bytestring) return TYPES.bytestring;
|
1789
|
+
|
1774
1790
|
// guess bytestring, could really be bytestring or string
|
1775
1791
|
if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
|
1776
1792
|
guess = TYPES.bytestring;
|
@@ -2397,6 +2413,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2397
2413
|
let idx;
|
2398
2414
|
if (decl._funcIdx) {
|
2399
2415
|
idx = decl._funcIdx;
|
2416
|
+
} else if (Object.hasOwn(internalConstrs, name) && !decl._noInternalConstr) {
|
2417
|
+
if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2418
|
+
return internalConstrs[name].generate(scope, decl, _global, _name);
|
2400
2419
|
} else if (Object.hasOwn(funcIndex, name)) {
|
2401
2420
|
idx = funcIndex[name];
|
2402
2421
|
} else if (scope.name === name) {
|
@@ -2410,9 +2429,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2410
2429
|
|
2411
2430
|
includeBuiltin(scope, name);
|
2412
2431
|
idx = funcIndex[name];
|
2413
|
-
} else if (Object.hasOwn(internalConstrs, name)) {
|
2414
|
-
if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2415
|
-
return internalConstrs[name].generate(scope, decl, _global, _name);
|
2416
2432
|
} else if (!decl._new && name && name.startsWith('__Porffor_wasm_')) {
|
2417
2433
|
const wasmOps = {
|
2418
2434
|
// pointer, align, offset
|
@@ -2559,7 +2575,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2559
2575
|
...setLastType(scope)
|
2560
2576
|
],
|
2561
2577
|
|
2562
|
-
default: decl.optional ? withType(scope, [ number(UNDEFINED, Valtype.f64) ], TYPES.undefined)
|
2578
|
+
default: () => decl.optional ? withType(scope, [ number(UNDEFINED, Valtype.f64) ], TYPES.undefined)
|
2563
2579
|
: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, Valtype.f64)
|
2564
2580
|
}, Valtype.f64)
|
2565
2581
|
];
|
@@ -3075,6 +3091,11 @@ const allocVar = (scope, name, global = false, type = true, redecl = false, i32
|
|
3075
3091
|
return idx;
|
3076
3092
|
};
|
3077
3093
|
|
3094
|
+
const getVarMetadata = (scope, name, global = false) => {
|
3095
|
+
const target = global ? globals : scope.locals;
|
3096
|
+
return target[name]?.metadata;
|
3097
|
+
};
|
3098
|
+
|
3078
3099
|
const setVarMetadata = (scope, name, global = false, metadata = {}) => {
|
3079
3100
|
const target = global ? globals : scope.locals;
|
3080
3101
|
target[name].metadata = metadata;
|
@@ -4041,9 +4062,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
4041
4062
|
}),
|
4042
4063
|
} : {}),
|
4043
4064
|
|
4044
|
-
[TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined', !valueUnused),
|
4065
|
+
[TYPES.undefined]: () => internalThrow(scope, 'TypeError', 'Cannot set property of undefined', !valueUnused),
|
4045
4066
|
|
4046
|
-
// default: internalThrow(scope, 'TypeError', `Cannot assign member with this type`)
|
4047
4067
|
default: () => [
|
4048
4068
|
objectGet,
|
4049
4069
|
Opcodes.i32_to,
|
@@ -4948,7 +4968,7 @@ const generateForOf = (scope, decl) => {
|
|
4948
4968
|
setVar = generateVarDstr(scope, 'var', decl.left, { type: 'Wasm', wasm: nextWasm }, undefined, true);
|
4949
4969
|
} else {
|
4950
4970
|
// todo: verify this is correct
|
4951
|
-
const global = scope.name === '#main'
|
4971
|
+
const global = scope.name === '#main';
|
4952
4972
|
setVar = generateVarDstr(scope, decl.left.kind, decl.left?.declarations?.[0]?.id ?? decl.left, { type: 'Wasm', wasm: nextWasm }, undefined, global);
|
4953
4973
|
}
|
4954
4974
|
|
@@ -5015,7 +5035,7 @@ const generateForIn = (scope, decl) => {
|
|
5015
5035
|
setVar = generateVarDstr(scope, 'var', decl.left, { type: 'Identifier', name: tmpName }, undefined, true);
|
5016
5036
|
} else {
|
5017
5037
|
// todo: verify this is correct
|
5018
|
-
const global = scope.name === '#main'
|
5038
|
+
const global = scope.name === '#main';
|
5019
5039
|
setVar = generateVarDstr(scope, decl.left.kind, decl.left?.declarations?.[0]?.id ?? decl.left, { type: 'Identifier', name: tmpName }, undefined, global);
|
5020
5040
|
}
|
5021
5041
|
|
@@ -5512,14 +5532,13 @@ const makeData = (scope, elements, page = null, itemType = 'i8') => {
|
|
5512
5532
|
return { idx, size: bytes.length };
|
5513
5533
|
};
|
5514
5534
|
|
5515
|
-
const printStaticStr = str => {
|
5535
|
+
const printStaticStr = (scope, str) => {
|
5536
|
+
scope.usesImports = true;
|
5516
5537
|
const out = [];
|
5517
5538
|
|
5518
5539
|
for (let i = 0; i < str.length; i++) {
|
5519
5540
|
out.push(
|
5520
|
-
|
5521
|
-
number(str.charCodeAt(i), Valtype.i32),
|
5522
|
-
[ Opcodes.f64_convert_i32_u ],
|
5541
|
+
number(str.charCodeAt(i)),
|
5523
5542
|
[ Opcodes.call, importedFuncs.printChar ]
|
5524
5543
|
);
|
5525
5544
|
}
|
@@ -6103,7 +6122,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
6103
6122
|
})
|
6104
6123
|
} : {}),
|
6105
6124
|
|
6106
|
-
[TYPES.undefined]: internalThrow(scope, 'TypeError', `Cannot read property of undefined`, true),
|
6125
|
+
[TYPES.undefined]: () => internalThrow(scope, 'TypeError', `Cannot read property of undefined`, true),
|
6107
6126
|
|
6108
6127
|
default: () => [
|
6109
6128
|
...(coctc > 0 && known === TYPES.object ? [
|
@@ -7197,10 +7216,8 @@ const internalConstrs = {
|
|
7197
7216
|
|
7198
7217
|
__Porffor_printStatic: {
|
7199
7218
|
generate: (scope, decl) => {
|
7200
|
-
scope.usesImports = true;
|
7201
|
-
|
7202
7219
|
const str = decl.arguments[0].value;
|
7203
|
-
const out = printStaticStr(str);
|
7220
|
+
const out = printStaticStr(scope, str);
|
7204
7221
|
out.push(number(UNDEFINED));
|
7205
7222
|
return out;
|
7206
7223
|
},
|
@@ -7248,6 +7265,46 @@ const internalConstrs = {
|
|
7248
7265
|
}),
|
7249
7266
|
notConstr: true,
|
7250
7267
|
length: 1
|
7268
|
+
},
|
7269
|
+
|
7270
|
+
__console_log: {
|
7271
|
+
// compile-time aware console.log to optimize fast paths
|
7272
|
+
// todo: this breaks console.group, etc - disable this if those are used but edge case for now
|
7273
|
+
generate: (scope, decl) => {
|
7274
|
+
const slow = () => {
|
7275
|
+
decl._noInternalConstr = true;
|
7276
|
+
return generate(scope, decl);
|
7277
|
+
};
|
7278
|
+
const fast = name => {
|
7279
|
+
return [
|
7280
|
+
...generate(scope, {
|
7281
|
+
...decl,
|
7282
|
+
callee: {
|
7283
|
+
type: 'Identifier',
|
7284
|
+
name
|
7285
|
+
}
|
7286
|
+
}),
|
7287
|
+
...printStaticStr(scope, '\n')
|
7288
|
+
];
|
7289
|
+
};
|
7290
|
+
if (decl.arguments.length !== 1) return slow();
|
7291
|
+
|
7292
|
+
generate(scope, decl.arguments[0]); // generate first to get accurate type
|
7293
|
+
const type = knownTypeWithGuess(scope, getNodeType(scope, decl.arguments[0]));
|
7294
|
+
|
7295
|
+
// if we know the type skip the entire print logic, use type's func directly
|
7296
|
+
if (type === TYPES.string || type === TYPES.bytestring) {
|
7297
|
+
return fast('__Porffor_printString');
|
7298
|
+
} else if (type === TYPES.number) {
|
7299
|
+
return fast('print');
|
7300
|
+
}
|
7301
|
+
|
7302
|
+
// one arg, skip most of console to avoid rest arg etc
|
7303
|
+
return fast('__Porffor_consolePrint');
|
7304
|
+
},
|
7305
|
+
type: TYPES.undefined,
|
7306
|
+
notConstr: true,
|
7307
|
+
length: 0
|
7251
7308
|
}
|
7252
7309
|
};
|
7253
7310
|
|
package/package.json
CHANGED