porffor 0.60.27 → 0.60.28

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.
@@ -1411,6 +1411,165 @@ export const BuiltinFuncs = () => {
1411
1411
  ]
1412
1412
  };
1413
1413
 
1414
+ // allow non-comptime redefinition later in precompiled
1415
+ const comptime = (name, returnType, comptime) => {
1416
+ let v = {
1417
+ returnType,
1418
+ comptime,
1419
+ params: [],
1420
+ locals: [],
1421
+ returns: []
1422
+ };
1423
+
1424
+ Object.defineProperty(_, name, {
1425
+ get() {
1426
+ return v;
1427
+ },
1428
+ set(x) {
1429
+ // v = { ...x, comptime, returnType };
1430
+ x.comptime = comptime;
1431
+ x.returnType = returnType;
1432
+ v = x;
1433
+ }
1434
+ });
1435
+ };
1436
+
1437
+ comptime('__Array_of', TYPES.array, (scope, decl, { generate }) => generate(scope, {
1438
+ type: 'ArrayExpression',
1439
+ elements: decl.arguments
1440
+ }));
1441
+
1442
+ comptime('__Porffor_fastOr', TYPES.boolean, (scope, decl, { generate }) => {
1443
+ const out = [];
1444
+
1445
+ for (let i = 0; i < decl.arguments.length; i++) {
1446
+ out.push(
1447
+ ...generate(scope, decl.arguments[i]),
1448
+ Opcodes.i32_to_u,
1449
+ ...(i > 0 ? [ [ Opcodes.i32_or ] ] : [])
1450
+ );
1451
+ }
1452
+
1453
+ out.push(Opcodes.i32_from_u);
1454
+ return out;
1455
+ });
1456
+
1457
+ comptime('__Porffor_fastAnd', TYPES.boolean, (scope, decl, { generate }) => {
1458
+ const out = [];
1459
+
1460
+ for (let i = 0; i < decl.arguments.length; i++) {
1461
+ out.push(
1462
+ ...generate(scope, decl.arguments[i]),
1463
+ Opcodes.i32_to_u,
1464
+ ...(i > 0 ? [ [ Opcodes.i32_and ] ] : [])
1465
+ );
1466
+ }
1467
+
1468
+ out.push(Opcodes.i32_from_u);
1469
+ return out;
1470
+ });
1471
+
1472
+ comptime('__Math_max', TYPES.number, (scope, decl, { generate }) => {
1473
+ const out = [
1474
+ number(-Infinity)
1475
+ ];
1476
+
1477
+ for (let i = 0; i < decl.arguments.length; i++) {
1478
+ out.push(
1479
+ ...generate(scope, decl.arguments[i]),
1480
+ [ Opcodes.f64_max ]
1481
+ );
1482
+ }
1483
+
1484
+ return out;
1485
+ });
1486
+
1487
+ comptime('__Math_min', TYPES.number, (scope, decl, { generate }) => {
1488
+ const out = [
1489
+ number(Infinity)
1490
+ ];
1491
+
1492
+ for (let i = 0; i < decl.arguments.length; i++) {
1493
+ out.push(
1494
+ ...generate(scope, decl.arguments[i]),
1495
+ [ Opcodes.f64_min ]
1496
+ );
1497
+ }
1498
+
1499
+ return out;
1500
+ });
1501
+
1502
+ comptime('__Porffor_printStatic', TYPES.undefined, (scope, decl, { printStaticStr }) => {
1503
+ const str = decl.arguments[0].value;
1504
+ const out = printStaticStr(scope, str);
1505
+ out.push(number(UNDEFINED));
1506
+ return out;
1507
+ });
1508
+
1509
+ comptime('__Porffor_type', TYPES.number, (scope, decl, { getNodeType }) => [
1510
+ ...getNodeType(scope, decl.arguments[0]),
1511
+ Opcodes.i32_from_u
1512
+ ]);
1513
+
1514
+ comptime('__Porffor_compileType', TYPES.bytestring, (scope, decl, { makeString, knownType }) =>
1515
+ makeString(scope, TYPE_NAMES[knownType(scope, getNodeType(scope, decl.arguments[0]))] ?? 'unknown')
1516
+ );
1517
+
1518
+ // Porffor.call(func, argArray, this, newTarget)
1519
+ comptime('__Porffor_call', TYPES.number, (scope, decl, { generate, getNodeType }) => generate(scope, {
1520
+ type: 'CallExpression',
1521
+ callee: decl.arguments[0],
1522
+ arguments: [ {
1523
+ type: 'SpreadElement',
1524
+ argument: decl.arguments[1],
1525
+ } ],
1526
+ _thisWasm: decl.arguments[2].value === null ? null : [
1527
+ ...generate(scope, decl.arguments[2]),
1528
+ ...getNodeType(scope, decl.arguments[2])
1529
+ ],
1530
+ _newTargetWasm: decl.arguments[3].value === null ? null : [
1531
+ ...generate(scope, decl.arguments[3]),
1532
+ ...getNodeType(scope, decl.arguments[3])
1533
+ ],
1534
+ _new: decl.arguments[3].value !== null,
1535
+ _forceCreateThis: true
1536
+ }));
1537
+
1538
+ // compile-time aware console.log to optimize fast paths
1539
+ // todo: this breaks console.group, etc - disable this if those are used but edge case for now
1540
+ comptime('__console_log', TYPES.undefined, (scope, decl, { generate, getNodeType, knownTypeWithGuess, printStaticStr }) => {
1541
+ const slow = () => {
1542
+ decl._noInternalConstr = true;
1543
+ return generate(scope, decl);
1544
+ };
1545
+ const fast = name => {
1546
+ return [
1547
+ ...generate(scope, {
1548
+ ...decl,
1549
+ callee: {
1550
+ type: 'Identifier',
1551
+ name
1552
+ }
1553
+ }),
1554
+ ...printStaticStr(scope, '\n')
1555
+ ];
1556
+ };
1557
+ if (decl.arguments.length !== 1) return slow();
1558
+
1559
+ generate(scope, decl.arguments[0]); // generate first to get accurate type
1560
+ const type = knownTypeWithGuess(scope, getNodeType(scope, decl.arguments[0]));
1561
+
1562
+ // if we know the type skip the entire print logic, use type's func directly
1563
+ if (type === TYPES.string || type === TYPES.bytestring) {
1564
+ return fast('__Porffor_printString');
1565
+ } else if (type === TYPES.number) {
1566
+ return fast('print');
1567
+ }
1568
+
1569
+ // one arg, skip most of console to avoid rest arg etc
1570
+ return fast('__Porffor_consolePrint');
1571
+ });
1572
+
1414
1573
  PrecompiledBuiltins.BuiltinFuncs(_);
1415
1574
  return _;
1416
1575
  };
@@ -79,7 +79,7 @@ const isFuncType = type =>
79
79
  type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression' ||
80
80
  type === 'ClassDeclaration' || type === 'ClassExpression';
81
81
  const hasFuncWithName = name =>
82
- name in funcIndex || name in builtinFuncs || name in importedFuncs || name in internalConstrs;
82
+ name in funcIndex || name in builtinFuncs || name in importedFuncs;
83
83
 
84
84
  const astCache = new WeakMap();
85
85
  const cacheAst = (decl, wasm) => {
@@ -614,9 +614,6 @@ const lookup = (scope, name, failEarly = false) => {
614
614
 
615
615
  if (name in builtinFuncs) {
616
616
  if (!(name in funcIndex)) includeBuiltin(scope, name);
617
- } else if (name in internalConstrs) {
618
- // todo: return an actual something
619
- return [ number(1) ];
620
617
  }
621
618
 
622
619
  if (local?.idx === undefined) {
@@ -1528,8 +1525,8 @@ const asmFunc = (name, func) => {
1528
1525
  func = { ...func };
1529
1526
  let { wasm, params = [], locals: localTypes = [], localNames = [], table, usesTag, returnTypes, returnType } = func;
1530
1527
  if (wasm == null) { // called with no built-in
1531
- log.warning('codegen', `${name} has no built-in!`);
1532
- wasm = [];
1528
+ if (!func.comptime) log.warning('codegen', `${name} has no built-in!`);
1529
+ wasm = () => [];
1533
1530
  }
1534
1531
 
1535
1532
  const existing = builtinFuncByName(name);
@@ -1782,7 +1779,6 @@ const getNodeType = (scope, node) => {
1782
1779
  }
1783
1780
 
1784
1781
  if (name in builtinFuncs && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1785
- if (name in internalConstrs && internalConstrs[name].type != null) return internalConstrs[name].type;
1786
1782
 
1787
1783
  if (name.startsWith('__Porffor_wasm_')) {
1788
1784
  // todo: return undefined for non-returning ops
@@ -2449,9 +2445,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2449
2445
  let idx;
2450
2446
  if (decl._funcIdx) {
2451
2447
  idx = decl._funcIdx;
2452
- } else if (name in internalConstrs && !decl._noInternalConstr) {
2453
- if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2454
- return internalConstrs[name].generate(scope, decl, _global, _name);
2455
2448
  } else if (name in funcIndex) {
2456
2449
  idx = funcIndex[name];
2457
2450
  } else if (scope.name === name) {
@@ -2462,6 +2455,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2462
2455
  scope.usesImports = true;
2463
2456
  } else if (name in builtinFuncs) {
2464
2457
  if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
2458
+ if (builtinFuncs[name].comptime && !decl._noComptime) return builtinFuncs[name].comptime(scope, decl, { generate, getNodeType, knownTypeWithGuess, makeString, printStaticStr });
2465
2459
 
2466
2460
  includeBuiltin(scope, name);
2467
2461
  idx = funcIndex[name];
@@ -7166,187 +7160,6 @@ const generateBlock = (scope, decl) => {
7166
7160
  return out;
7167
7161
  };
7168
7162
 
7169
- const internalConstrs = {
7170
- __proto__: null,
7171
- __Array_of: {
7172
- // this is not a constructor but best fits internal structure here
7173
- generate: (scope, decl, global, name) => {
7174
- // Array.of(i0, i1, ...)
7175
- return generateArray(scope, {
7176
- elements: decl.arguments
7177
- }, global, name);
7178
- },
7179
- type: TYPES.array,
7180
- notConstr: true
7181
- },
7182
-
7183
- __Porffor_fastOr: {
7184
- generate: (scope, decl) => {
7185
- const out = [];
7186
-
7187
- for (let i = 0; i < decl.arguments.length; i++) {
7188
- out.push(
7189
- ...generate(scope, decl.arguments[i]),
7190
- Opcodes.i32_to_u,
7191
- ...(i > 0 ? [ [ Opcodes.i32_or ] ] : [])
7192
- );
7193
- }
7194
-
7195
- out.push(Opcodes.i32_from_u);
7196
-
7197
- return out;
7198
- },
7199
- type: TYPES.boolean,
7200
- notConstr: true
7201
- },
7202
-
7203
- __Porffor_fastAnd: {
7204
- generate: (scope, decl) => {
7205
- const out = [];
7206
-
7207
- for (let i = 0; i < decl.arguments.length; i++) {
7208
- out.push(
7209
- ...generate(scope, decl.arguments[i]),
7210
- Opcodes.i32_to_u,
7211
- ...(i > 0 ? [ [ Opcodes.i32_and ] ] : [])
7212
- );
7213
- }
7214
-
7215
- out.push(Opcodes.i32_from_u);
7216
-
7217
- return out;
7218
- },
7219
- type: TYPES.boolean,
7220
- notConstr: true
7221
- },
7222
-
7223
- __Math_max: {
7224
- generate: (scope, decl) => {
7225
- const out = [
7226
- number(-Infinity)
7227
- ];
7228
-
7229
- for (let i = 0; i < decl.arguments.length; i++) {
7230
- out.push(
7231
- ...generate(scope, decl.arguments[i]),
7232
- [ Opcodes.f64_max ]
7233
- );
7234
- }
7235
-
7236
- return out;
7237
- },
7238
- type: TYPES.number,
7239
- notConstr: true
7240
- },
7241
-
7242
- __Math_min: {
7243
- generate: (scope, decl) => {
7244
- const out = [
7245
- number(Infinity)
7246
- ];
7247
-
7248
- for (let i = 0; i < decl.arguments.length; i++) {
7249
- out.push(
7250
- ...generate(scope, decl.arguments[i]),
7251
- [ Opcodes.f64_min ]
7252
- );
7253
- }
7254
-
7255
- return out;
7256
- },
7257
- type: TYPES.number,
7258
- notConstr: true
7259
- },
7260
-
7261
- __Porffor_printStatic: {
7262
- generate: (scope, decl) => {
7263
- const str = decl.arguments[0].value;
7264
- const out = printStaticStr(scope, str);
7265
- out.push(number(UNDEFINED));
7266
- return out;
7267
- },
7268
- type: TYPES.undefined,
7269
- notConstr: true
7270
- },
7271
-
7272
- __Porffor_type: {
7273
- generate: (scope, decl) => [
7274
- ...getNodeType(scope, decl.arguments[0]),
7275
- Opcodes.i32_from_u
7276
- ],
7277
- type: TYPES.number,
7278
- notConstr: true
7279
- },
7280
-
7281
- __Porffor_compileType: {
7282
- generate: (scope, decl) => makeString(scope, TYPE_NAMES[knownType(scope, getNodeType(scope, decl.arguments[0]))] ?? 'unknown'),
7283
- type: TYPES.bytestring,
7284
- notConstr: true
7285
- },
7286
-
7287
- __Porffor_call: {
7288
- // Porffor.call(func, argArray, this, newTarget)
7289
- generate: (scope, decl) => generate(scope, {
7290
- type: 'CallExpression',
7291
- callee: decl.arguments[0],
7292
- arguments: [ {
7293
- type: 'SpreadElement',
7294
- argument: decl.arguments[1],
7295
- } ],
7296
- _thisWasm: decl.arguments[2].value === null ? null : [
7297
- ...generate(scope, decl.arguments[2]),
7298
- ...getNodeType(scope, decl.arguments[2])
7299
- ],
7300
- _newTargetWasm: decl.arguments[3].value === null ? null : [
7301
- ...generate(scope, decl.arguments[3]),
7302
- ...getNodeType(scope, decl.arguments[3])
7303
- ],
7304
- _new: decl.arguments[3].value !== null,
7305
- _forceCreateThis: true
7306
- }),
7307
- notConstr: true
7308
- },
7309
-
7310
- __console_log: {
7311
- // compile-time aware console.log to optimize fast paths
7312
- // todo: this breaks console.group, etc - disable this if those are used but edge case for now
7313
- generate: (scope, decl) => {
7314
- const slow = () => {
7315
- decl._noInternalConstr = true;
7316
- return generate(scope, decl);
7317
- };
7318
- const fast = name => {
7319
- return [
7320
- ...generate(scope, {
7321
- ...decl,
7322
- callee: {
7323
- type: 'Identifier',
7324
- name
7325
- }
7326
- }),
7327
- ...printStaticStr(scope, '\n')
7328
- ];
7329
- };
7330
- if (decl.arguments.length !== 1) return slow();
7331
-
7332
- generate(scope, decl.arguments[0]); // generate first to get accurate type
7333
- const type = knownTypeWithGuess(scope, getNodeType(scope, decl.arguments[0]));
7334
-
7335
- // if we know the type skip the entire print logic, use type's func directly
7336
- if (type === TYPES.string || type === TYPES.bytestring) {
7337
- return fast('__Porffor_printString');
7338
- } else if (type === TYPES.number) {
7339
- return fast('print');
7340
- }
7341
-
7342
- // one arg, skip most of console to avoid rest arg etc
7343
- return fast('__Porffor_consolePrint');
7344
- },
7345
- type: TYPES.undefined,
7346
- notConstr: true
7347
- }
7348
- };
7349
-
7350
7163
  let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
7351
7164
  export default program => {
7352
7165
  globals = Object.create(null);
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@honk/porffor",
3
- "version": "0.60.27",
3
+ "version": "0.60.28",
4
4
  "exports": "./compiler/wrap.js",
5
5
  "publish": {
6
6
  "exclude": [
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.60.27",
4
+ "version": "0.60.28",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.60.27';
3
+ globalThis.version = '0.60.28';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {