porffor 0.36.6 → 0.37.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.
@@ -104,6 +104,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
104
104
  case 'ThisExpression':
105
105
  return cacheAst(decl, generateThis(scope, decl));
106
106
 
107
+ case 'Super':
108
+ return cacheAst(decl, generateSuper(scope, decl));
109
+
107
110
  case 'Literal':
108
111
  return cacheAst(decl, generateLiteral(scope, decl, global, name));
109
112
 
@@ -245,7 +248,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
245
248
 
246
249
  const encodeFunc = ({
247
250
  [Opcodes.f64_const]: x => x,
248
- [Opcodes.if]: unsignedLEB128
251
+ [Opcodes.if]: unsignedLEB128,
252
+ [Opcodes.loop]: unsignedLEB128
249
253
  })[inst[0]] ?? signedLEB128;
250
254
  out.push([ ...inst, ...immediates.flatMap(x => encodeFunc(x)) ]);
251
255
  }
@@ -311,7 +315,8 @@ const lookupName = (scope, _name) => {
311
315
  };
312
316
 
313
317
  const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysValueInternalThrows) => [
314
- ...generateThrow(scope, {
318
+ ...generate(scope, {
319
+ type: 'ThrowStatement',
315
320
  argument: {
316
321
  type: 'NewExpression',
317
322
  callee: {
@@ -1601,8 +1606,8 @@ const RTArrayUtil = {
1601
1606
  ]
1602
1607
  };
1603
1608
 
1604
- const createNewTarget = (scope, decl, idx = 0) => {
1605
- if (decl._new) {
1609
+ const createNewTarget = (scope, decl, idx = 0, force = false) => {
1610
+ if (decl._new || force) {
1606
1611
  return [
1607
1612
  ...(typeof idx === 'number' ? number(idx) : idx),
1608
1613
  ...number(TYPES.function, Valtype.i32)
@@ -1632,7 +1637,7 @@ const makeObject = (scope, obj) => {
1632
1637
  });
1633
1638
  }
1634
1639
 
1635
- return generateObject(scope, {
1640
+ return generate(scope, {
1636
1641
  type: 'ObjectExpression',
1637
1642
  properties
1638
1643
  });
@@ -1692,13 +1697,48 @@ const createThisArg = (scope, decl, knownThis = undefined) => {
1692
1697
  return knownThis;
1693
1698
  }
1694
1699
 
1700
+ const name = mapName(decl.callee?.name);
1695
1701
  if (decl._new) {
1702
+ // if precompiling or builtin func, just make empty object
1703
+ if (globalThis.precompile || Object.hasOwn(builtinFuncs, name)) return [
1704
+ ...makeObject(scope, {}),
1705
+ ...number(TYPES.object, Valtype.i32)
1706
+ ];
1707
+
1708
+ // create new object with __proto__ set to callee prototype
1709
+ const tmp = localTmp(scope, '#this_create_tmp');
1710
+ const proto = getObjProp(decl.callee, 'prototype');
1711
+ localTmp(scope, '#member_prop_assign');
1712
+
1696
1713
  return [
1697
1714
  ...makeObject(scope, {}),
1715
+ [ Opcodes.local_tee, tmp ],
1716
+ Opcodes.i32_to_u,
1717
+
1718
+ ...number(TYPES.object, Valtype.i32),
1719
+
1720
+ ...generate(scope, {
1721
+ type: 'Literal',
1722
+ value: '__proto__'
1723
+ }, false, '#member_prop_assign'),
1724
+ Opcodes.i32_to_u,
1725
+ ...number(TYPES.bytestring, Valtype.i32),
1726
+
1727
+ ...generate(scope, proto),
1728
+ ...getNodeType(scope, proto),
1729
+
1730
+ // flags: writable
1731
+ ...number(0b1000, Valtype.i32),
1732
+ ...number(TYPES.number, Valtype.i32),
1733
+
1734
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_object_expr_initWithFlags').index ],
1735
+ [ Opcodes.drop ],
1736
+ [ Opcodes.drop ],
1737
+
1738
+ [ Opcodes.local_get, tmp ],
1698
1739
  ...number(TYPES.object, Valtype.i32)
1699
1740
  ];
1700
1741
  } else {
1701
- const name = mapName(decl.callee?.name);
1702
1742
  if (name && name.startsWith('__') && name.includes('_prototype_')) {
1703
1743
  // todo: this should just be same as decl._new
1704
1744
  // but we do not support prototype, constructor, etc yet
@@ -1714,7 +1754,7 @@ const createThisArg = (scope, decl, knownThis = undefined) => {
1714
1754
  };
1715
1755
 
1716
1756
  return [
1717
- ...generateCall(scope, node),
1757
+ ...generate(scope, node),
1718
1758
  ...getNodeType(scope, node)
1719
1759
  ];
1720
1760
  }
@@ -1733,7 +1773,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1733
1773
 
1734
1774
  // opt: virtualize iifes
1735
1775
  if (isFuncType(decl.callee.type)) {
1736
- const [ func ] = generateFunc(scope, decl.callee, true);
1776
+ const [ func ] = generateFunc(scope, decl.callee);
1737
1777
  name = func.name;
1738
1778
  }
1739
1779
 
@@ -1836,7 +1876,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1836
1876
  const valTmp = localTmp(scope, '#call_val');
1837
1877
  const typeTmp = localTmp(scope, '#call_type', Valtype.i32);
1838
1878
 
1839
- return generateCall(scope, {
1879
+ return generate(scope, {
1840
1880
  type: 'CallExpression',
1841
1881
  callee: target,
1842
1882
  arguments: decl.arguments.slice(1),
@@ -1939,7 +1979,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1939
1979
  const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
1940
1980
  if (type == null) continue;
1941
1981
 
1942
- protoBC[type] = generateCall(scope, {
1982
+ protoBC[type] = generate(scope, {
1983
+ type: 'CallExpression',
1943
1984
  callee: {
1944
1985
  type: 'Identifier',
1945
1986
  name: x
@@ -2233,11 +2274,22 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2233
2274
  ];
2234
2275
  }
2235
2276
 
2277
+ let callee = decl.callee, callAsNew = decl._new, overrideThisWasm = decl._thisWasm;
2278
+ if (callee.type === 'Super') {
2279
+ // call super constructor with direct super() call
2280
+ callee = getObjProp(callee, 'constructor');
2281
+ callAsNew = true;
2282
+ overrideThisWasm = [
2283
+ ...generate(scope, { type: 'ThisExpression' }),
2284
+ ...getNodeType(scope, { type: 'ThisExpression' })
2285
+ ];
2286
+ }
2287
+
2236
2288
  const newTargetWasm = decl._newTargetWasm ?? createNewTarget(scope, decl, [
2237
2289
  [ Opcodes.local_get, funcLocal ],
2238
2290
  Opcodes.i32_from_u
2239
- ]);
2240
- const thisWasm = decl._thisWasm ?? createThisArg(scope, decl, knownThis);
2291
+ ], callAsNew);
2292
+ const thisWasm = overrideThisWasm ?? createThisArg(scope, decl, knownThis);
2241
2293
 
2242
2294
  const gen = argc => {
2243
2295
  const argsOut = [];
@@ -2305,11 +2357,11 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2305
2357
  return [
2306
2358
  ...(getCalleeObj ? [
2307
2359
  ...initCalleeObj,
2308
- ...generateMember(scope, decl.callee, false, undefined, getCalleeObj)
2309
- ]: generate(scope, decl.callee)),
2360
+ ...generate(scope, callee, false, undefined, getCalleeObj)
2361
+ ]: generate(scope, callee)),
2310
2362
  [ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
2311
2363
 
2312
- ...typeSwitch(scope, getNodeType(scope, decl.callee), {
2364
+ ...typeSwitch(scope, getNodeType(scope, callee), {
2313
2365
  [TYPES.function]: [
2314
2366
  ...out,
2315
2367
 
@@ -2327,7 +2379,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2327
2379
  [ Opcodes.local_set, flags ],
2328
2380
 
2329
2381
  // check if non-constructor was called with new, if so throw
2330
- ...(decl._new ? [
2382
+ ...(callAsNew ? [
2331
2383
  [ Opcodes.local_get, flags ],
2332
2384
  ...number(0b10, Valtype.i32),
2333
2385
  [ Opcodes.i32_and ],
@@ -2535,6 +2587,9 @@ const generateThis = (scope, decl) => {
2535
2587
  ];
2536
2588
  };
2537
2589
 
2590
+ const generateSuper = (scope, decl) => generate(scope,
2591
+ getObjProp(getObjProp({ type: 'ThisExpression', _noGlobalThis: true }, '__proto__'), '__proto__'));
2592
+
2538
2593
  // bad hack for undefined and null working without additional logic
2539
2594
  const DEFAULT_VALUE = () => ({
2540
2595
  type: 'Identifier',
@@ -2892,7 +2947,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
2892
2947
  // hack for let a = function () { ... }
2893
2948
  if (!init.id) {
2894
2949
  init.id = { name };
2895
- generateFunc(scope, init, true);
2950
+ generateFunc(scope, init);
2896
2951
  return out;
2897
2952
  }
2898
2953
  }
@@ -3543,7 +3598,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3543
3598
 
3544
3599
  const ifIdentifierErrors = (scope, decl) => {
3545
3600
  if (decl.type === 'Identifier') {
3546
- const out = generateIdent(scope, decl);
3601
+ const out = generate(scope, decl);
3547
3602
  if (out[1]) return true;
3548
3603
  }
3549
3604
 
@@ -3620,7 +3675,7 @@ const generateUnary = (scope, decl) => {
3620
3675
  let toReturn = true, toGenerate = true;
3621
3676
 
3622
3677
  if (decl.argument.type === 'Identifier') {
3623
- const out = generateIdent(scope, decl.argument);
3678
+ const out = generate(scope, decl.argument);
3624
3679
 
3625
3680
  // if ReferenceError (undeclared var), ignore and return true. otherwise false
3626
3681
  if (!out[1]) {
@@ -4397,7 +4452,7 @@ const generateSwitch = (scope, decl) => {
4397
4452
  const ret = typeSwitch(scope, getNodeType(scope, decl.discriminant.arguments[0]), () => {
4398
4453
  const ret = [];
4399
4454
  for (const [type, consequent] of cases) {
4400
- const o = generateCode(scope, { body: consequent });
4455
+ const o = generate(scope, { type: 'BlockStatement', body: consequent });
4401
4456
  ret.push([type, o]);
4402
4457
  }
4403
4458
  return ret;
@@ -4440,7 +4495,7 @@ const generateSwitch = (scope, decl) => {
4440
4495
  depth.pop();
4441
4496
  out.push(
4442
4497
  [ Opcodes.end ],
4443
- ...generateCode(scope, { body: cases[i].consequent })
4498
+ ...generate(scope, { type: 'BlockStatement', body: cases[i].consequent })
4444
4499
  );
4445
4500
  }
4446
4501
 
@@ -5042,7 +5097,7 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
5042
5097
 
5043
5098
  if (type === 'SpreadElement') {
5044
5099
  out.push(
5045
- ...generateCall(scope, {
5100
+ ...generate(scope, {
5046
5101
  type: 'CallExpression',
5047
5102
  callee: {
5048
5103
  type: 'Identifier',
@@ -5237,7 +5292,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5237
5292
  const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
5238
5293
  if (type == null) continue;
5239
5294
 
5240
- if (type === known) return generateCall(scope, {
5295
+ if (type === known) return generate(scope, {
5296
+ type: 'CallExpression',
5241
5297
  callee: {
5242
5298
  type: 'Identifier',
5243
5299
  name: x
@@ -5246,7 +5302,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5246
5302
  _protoInternalCall: true
5247
5303
  });
5248
5304
 
5249
- bc[type] = generateCall(scope, {
5305
+ bc[type] = generate(scope, {
5306
+ type: 'CallExpression',
5250
5307
  callee: {
5251
5308
  type: 'Identifier',
5252
5309
  name: x
@@ -5281,7 +5338,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5281
5338
  };
5282
5339
 
5283
5340
  bc[type] = [
5284
- ...generateIdent(scope, ident),
5341
+ ...generate(scope, ident),
5285
5342
  ...setLastType(scope, getNodeType(scope, ident))
5286
5343
  ];
5287
5344
  if (type === known) return bc[type];
@@ -5512,7 +5569,7 @@ const generateAwait = (scope, decl) => {
5512
5569
 
5513
5570
  // todo: warn here if -d?
5514
5571
 
5515
- return generateCall(scope, {
5572
+ return generate(scope, {
5516
5573
  type: 'CallExpression',
5517
5574
  callee: {
5518
5575
  type: 'Identifier',
@@ -5585,7 +5642,7 @@ const generateClass = (scope, decl) => {
5585
5642
 
5586
5643
  const k = getProperty(x, true);
5587
5644
 
5588
- let initKind = 'init';
5645
+ let initKind = type === 'MethodDefinition' ? 'method' : 'value';
5589
5646
  if (kind === 'get' || kind === 'set') initKind = kind;
5590
5647
 
5591
5648
  // default value to undefined
@@ -5628,10 +5685,10 @@ const generateClass = (scope, decl) => {
5628
5685
  ...toPropertyKey(outScope, generate(outScope, k), getNodeType(outScope, k), computed, true),
5629
5686
 
5630
5687
  ...generate(outScope, value),
5631
- ...(initKind !== 'init' ? [ Opcodes.i32_to_u ] : []),
5688
+ ...(initKind !== 'value' && initKind !== 'method' ? [ Opcodes.i32_to_u ] : []),
5632
5689
  ...getNodeType(outScope, value),
5633
5690
 
5634
- [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_expr_${initKind}`).index ],
5691
+ [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_class_${initKind}`).index ],
5635
5692
 
5636
5693
  [ Opcodes.drop ],
5637
5694
  [ Opcodes.drop ]
@@ -5748,7 +5805,7 @@ const funcByIndex = idx => {
5748
5805
  };
5749
5806
  const funcByName = name => funcByIndex(funcIndex[name]);
5750
5807
 
5751
- const generateFunc = (scope, decl, outUnused = false) => {
5808
+ const generateFunc = (scope, decl) => {
5752
5809
  const name = decl.id ? decl.id.name : `#anonymous${uniqId()}`;
5753
5810
  if (decl.type.startsWith('Class')) {
5754
5811
  const out = generateClass(scope, {
@@ -5757,6 +5814,7 @@ const generateFunc = (scope, decl, outUnused = false) => {
5757
5814
  });
5758
5815
 
5759
5816
  const func = funcByName(name);
5817
+ astCache.set(decl, out);
5760
5818
  return [ func, out ];
5761
5819
  }
5762
5820
 
@@ -5834,21 +5892,6 @@ const generateFunc = (scope, decl, outUnused = false) => {
5834
5892
  // todo: wrap in try and reject thrown value once supported
5835
5893
  }
5836
5894
 
5837
- if (!globalThis.precompile && func.constr && !func._onlyThisMethod) {
5838
- wasm.unshift(
5839
- // opt: do not check for pure constructors
5840
- ...(func._onlyConstr ? [] : [
5841
- // if being constructed
5842
- [ Opcodes.local_get, func.locals['#newtarget'].idx ],
5843
- Opcodes.i32_to_u,
5844
- [ Opcodes.if, Blocktype.void ],
5845
- ]),
5846
- // set prototype of this ;)
5847
- ...generate(func, setObjProp({ type: 'ThisExpression', _noGlobalThis: true }, '__proto__', getObjProp(func.name, 'prototype'))),
5848
- ...(func._onlyConstr ? [] : [ [ Opcodes.end ] ])
5849
- );
5850
- }
5851
-
5852
5895
  if (name === 'main') {
5853
5896
  func.gotLastType = true;
5854
5897
  func.export = true;
@@ -6004,7 +6047,8 @@ const generateFunc = (scope, decl, outUnused = false) => {
6004
6047
  // force generate all for precompile
6005
6048
  if (globalThis.precompile) func.generate();
6006
6049
 
6007
- const out = decl.type.endsWith('Expression') && !outUnused ? funcRef(func) : [];
6050
+ const out = decl.type.endsWith('Expression') ? funcRef(func) : [];
6051
+ astCache.set(decl, out);
6008
6052
  return [ func, out ];
6009
6053
  };
6010
6054
 
@@ -62,6 +62,8 @@ const compile = async (file, _funcs) => {
62
62
  __Porffor_object_setStrict: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
63
63
  __Porffor_object_expr_init: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
64
64
  __Porffor_object_expr_initWithFlags: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
65
+ __Porffor_object_class_value: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
66
+ __Porffor_object_class_method: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
65
67
  __Porffor_object_define: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32, Valtype.i32, Valtype.i32 ],
66
68
  };
67
69
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.36.6+732d836d7",
4
+ "version": "0.37.0+44ce75202",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
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.36.6+732d836d7';
3
+ globalThis.version = '0.37.0+44ce75202';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {