porffor 0.2.0-9928127 → 0.2.0-9f58210

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.
@@ -59,6 +59,10 @@ const todo = (scope, msg, expectsValue = undefined) => {
59
59
  };
60
60
 
61
61
  const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
62
+ const hasFuncWithName = name => {
63
+ const func = funcs.find(x => x.name === name);
64
+ return !!(func || builtinFuncs[name] || importedFuncs[name] || internalConstrs[name]);
65
+ };
62
66
  const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
63
67
  switch (decl.type) {
64
68
  case 'BinaryExpression':
@@ -201,7 +205,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
201
205
  }
202
206
 
203
207
  let inst = Opcodes[asm[0].replace('.', '_')];
204
- if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
208
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
205
209
 
206
210
  if (!Array.isArray(inst)) inst = [ inst ];
207
211
  const immediates = asm.slice(1).map(x => {
@@ -219,8 +223,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
219
223
  __Porffor_bs: str => [
220
224
  ...makeString(scope, str, global, name, true),
221
225
 
222
- ...(name ? setType(scope, name, TYPES._bytestring) : [
223
- ...number(TYPES._bytestring, Valtype.i32),
226
+ ...(name ? setType(scope, name, TYPES.bytestring) : [
227
+ ...number(TYPES.bytestring, Valtype.i32),
224
228
  ...setLastType(scope)
225
229
  ])
226
230
  ],
@@ -460,7 +464,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
460
464
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
461
465
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
462
466
 
463
- if (assign) {
467
+ if (assign && Prefs.aotPointerOpt) {
464
468
  const pointer = scope.arrays?.get(name ?? '$undeclared');
465
469
 
466
470
  return [
@@ -723,7 +727,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
723
727
 
724
728
  ...typeSwitch(scope, type, {
725
729
  // [TYPES.number]: def,
726
- [TYPES._array]: [
730
+ [TYPES.array]: [
727
731
  // arrays are always truthy
728
732
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
729
733
  ],
@@ -739,7 +743,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
739
743
  [ Opcodes.i32_eqz ], */
740
744
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
741
745
  ],
742
- [TYPES._bytestring]: [ // duplicate of string
746
+ [TYPES.bytestring]: [ // duplicate of string
743
747
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
744
748
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
745
749
 
@@ -762,7 +766,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
762
766
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
763
767
 
764
768
  ...typeSwitch(scope, type, {
765
- [TYPES._array]: [
769
+ [TYPES.array]: [
766
770
  // arrays are always truthy
767
771
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
768
772
  ],
@@ -777,7 +781,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
777
781
  [ Opcodes.i32_eqz ],
778
782
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
779
783
  ],
780
- [TYPES._bytestring]: [ // duplicate of string
784
+ [TYPES.bytestring]: [ // duplicate of string
781
785
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
782
786
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
783
787
 
@@ -922,7 +926,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
922
926
  }
923
927
  }
924
928
 
925
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) {
929
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
926
930
  if (op === '+') {
927
931
  // todo: this should be dynamic too but for now only static
928
932
  // string concat (a + b)
@@ -1041,12 +1045,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1041
1045
 
1042
1046
  // if left is bytestring
1043
1047
  ...leftType,
1044
- ...number(TYPES._bytestring, Valtype.i32),
1048
+ ...number(TYPES.bytestring, Valtype.i32),
1045
1049
  [ Opcodes.i32_eq ],
1046
1050
 
1047
1051
  // if right is bytestring
1048
1052
  ...rightType,
1049
- ...number(TYPES._bytestring, Valtype.i32),
1053
+ ...number(TYPES.bytestring, Valtype.i32),
1050
1054
  [ Opcodes.i32_eq ],
1051
1055
 
1052
1056
  // if both are true
@@ -1177,7 +1181,6 @@ const generateLogicExp = (scope, decl) => {
1177
1181
  // js type: 4 bits
1178
1182
  // internal type: ? bits
1179
1183
  // pointer: 32 bits
1180
-
1181
1184
  // generic
1182
1185
  // 1 23 4 5
1183
1186
  // 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
@@ -1188,7 +1191,7 @@ const generateLogicExp = (scope, decl) => {
1188
1191
  // 5: pointer
1189
1192
 
1190
1193
  const isExistingProtoFunc = name => {
1191
- if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES._array][name.slice(18)];
1194
+ if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
1192
1195
  if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
1193
1196
 
1194
1197
  return false;
@@ -1247,9 +1250,9 @@ const setLastType = scope => {
1247
1250
  const getNodeType = (scope, node) => {
1248
1251
  const inner = () => {
1249
1252
  if (node.type === 'Literal') {
1250
- if (node.regex) return TYPES._regexp;
1253
+ if (node.regex) return TYPES.regexp;
1251
1254
 
1252
- if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
1255
+ if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
1253
1256
 
1254
1257
  return TYPES[typeof node.value];
1255
1258
  }
@@ -1303,7 +1306,7 @@ const getNodeType = (scope, node) => {
1303
1306
  const spl = name.slice(2).split('_');
1304
1307
 
1305
1308
  const func = spl[spl.length - 1];
1306
- const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES._bytestring && prototypeFuncs[x][func] != null);
1309
+ const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1307
1310
  if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
1308
1311
  }
1309
1312
 
@@ -1355,7 +1358,7 @@ const getNodeType = (scope, node) => {
1355
1358
  }
1356
1359
 
1357
1360
  if (node.type === 'ArrayExpression') {
1358
- return TYPES._array;
1361
+ return TYPES.array;
1359
1362
  }
1360
1363
 
1361
1364
  if (node.type === 'BinaryExpression') {
@@ -1367,7 +1370,7 @@ const getNodeType = (scope, node) => {
1367
1370
 
1368
1371
  // todo: this should be dynamic but for now only static
1369
1372
  if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
1370
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) return TYPES._bytestring;
1373
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
1371
1374
 
1372
1375
  return TYPES.number;
1373
1376
 
@@ -1393,19 +1396,28 @@ const getNodeType = (scope, node) => {
1393
1396
  if (node.operator === '!') return TYPES.boolean;
1394
1397
  if (node.operator === 'void') return TYPES.undefined;
1395
1398
  if (node.operator === 'delete') return TYPES.boolean;
1396
- if (node.operator === 'typeof') return Prefs.bytestring ? TYPES._bytestring : TYPES.string;
1399
+ if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
1397
1400
 
1398
1401
  return TYPES.number;
1399
1402
  }
1400
1403
 
1401
1404
  if (node.type === 'MemberExpression') {
1405
+ // hack: if something.name, string type
1406
+ if (node.property.name === 'name') {
1407
+ if (hasFuncWithName(node.object.name)) {
1408
+ return TYPES.bytestring;
1409
+ } else {
1410
+ return TYPES.undefined;
1411
+ }
1412
+ }
1413
+
1402
1414
  // hack: if something.length, number type
1403
1415
  if (node.property.name === 'length') return TYPES.number;
1404
1416
 
1405
1417
  // ts hack
1406
1418
  if (scope.locals[node.object.name]?.metadata?.type === TYPES.string) return TYPES.string;
1407
- if (scope.locals[node.object.name]?.metadata?.type === TYPES._bytestring) return TYPES._bytestring;
1408
- if (scope.locals[node.object.name]?.metadata?.type === TYPES._array) return TYPES.number;
1419
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
1420
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
1409
1421
 
1410
1422
  if (scope.locals['#last_type']) return getLastType(scope);
1411
1423
 
@@ -1646,18 +1658,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1646
1658
  // megahack for /regex/.func()
1647
1659
  const funcName = decl.callee.property.name;
1648
1660
  if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1649
- const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
1661
+ const regex = decl.callee.object.regex.pattern;
1662
+ const rhemynName = `regex_${funcName}_${regex}`;
1663
+
1664
+ if (!funcIndex[rhemynName]) {
1665
+ const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
1650
1666
 
1651
- funcIndex[func.name] = func.index;
1652
- funcs.push(func);
1667
+ funcIndex[func.name] = func.index;
1668
+ funcs.push(func);
1669
+ }
1653
1670
 
1671
+ const idx = funcIndex[rhemynName];
1654
1672
  return [
1655
1673
  // make string arg
1656
1674
  ...generate(scope, decl.arguments[0]),
1675
+ Opcodes.i32_to_u,
1676
+ ...getNodeType(scope, decl.arguments[0]),
1657
1677
 
1658
1678
  // call regex func
1659
- Opcodes.i32_to_u,
1660
- [ Opcodes.call, func.index ],
1679
+ [ Opcodes.call, idx ],
1661
1680
  Opcodes.i32_from_u,
1662
1681
 
1663
1682
  ...number(TYPES.boolean, Valtype.i32),
@@ -1697,6 +1716,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1697
1716
 
1698
1717
  protoBC[type] = generateCall(scope, {
1699
1718
  callee: {
1719
+ type: 'Identifier',
1700
1720
  name: x
1701
1721
  },
1702
1722
  arguments: [ target, ...decl.arguments ],
@@ -1819,20 +1839,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1819
1839
  idx = funcIndex[name];
1820
1840
 
1821
1841
  // infer arguments types from builtins params
1822
- const func = funcs.find(x => x.name === name);
1823
- for (let i = 0; i < decl.arguments.length; i++) {
1824
- const arg = decl.arguments[i];
1825
- if (!arg.name) continue;
1826
-
1827
- const local = scope.locals[arg.name];
1828
- if (!local) continue;
1829
-
1830
- local.type = func.params[i];
1831
- if (local.type === Valtype.v128) {
1832
- // specify vec subtype inferred from last vec type in function name
1833
- local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1834
- }
1835
- }
1842
+ // const func = funcs.find(x => x.name === name);
1843
+ // for (let i = 0; i < decl.arguments.length; i++) {
1844
+ // const arg = decl.arguments[i];
1845
+ // if (!arg.name) continue;
1846
+
1847
+ // const local = scope.locals[arg.name];
1848
+ // if (!local) continue;
1849
+
1850
+ // local.type = func.params[i];
1851
+ // if (local.type === Valtype.v128) {
1852
+ // // specify vec subtype inferred from last vec type in function name
1853
+ // local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1854
+ // }
1855
+ // }
1836
1856
  }
1837
1857
 
1838
1858
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1864,9 +1884,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1864
1884
 
1865
1885
  // value
1866
1886
  i32_const: { imms: 1, args: [], returns: 1 },
1867
-
1868
- // a, b
1869
- i32_or: { imms: 0, args: [ true, true ], returns: 1 },
1870
1887
  };
1871
1888
 
1872
1889
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -2087,7 +2104,7 @@ const brTable = (input, bc, returns) => {
2087
2104
  };
2088
2105
 
2089
2106
  const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2090
- if (!Prefs.bytestring) delete bc[TYPES._bytestring];
2107
+ if (!Prefs.bytestring) delete bc[TYPES.bytestring];
2091
2108
 
2092
2109
  const known = knownType(scope, type);
2093
2110
  if (known != null) {
@@ -2190,7 +2207,7 @@ const extractTypeAnnotation = decl => {
2190
2207
  const typeName = type;
2191
2208
  type = typeAnnoToPorfType(type);
2192
2209
 
2193
- if (type === TYPES._bytestring && !Prefs.bytestring) type = TYPES.string;
2210
+ if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
2194
2211
 
2195
2212
  // if (decl.name) console.log(decl.name, { type, elementType });
2196
2213
 
@@ -2204,6 +2221,7 @@ const generateVar = (scope, decl) => {
2204
2221
 
2205
2222
  // global variable if in top scope (main) and var ..., or if wanted
2206
2223
  const global = topLevel || decl._bare; // decl.kind === 'var';
2224
+ const target = global ? globals : scope.locals;
2207
2225
 
2208
2226
  for (const x of decl.declarations) {
2209
2227
  const name = mapName(x.id.name);
@@ -2225,6 +2243,10 @@ const generateVar = (scope, decl) => {
2225
2243
  continue; // always ignore
2226
2244
  }
2227
2245
 
2246
+ // // generate init before allocating var
2247
+ // let generated;
2248
+ // if (x.init) generated = generate(scope, x.init, global, name);
2249
+
2228
2250
  const typed = typedInput && x.id.typeAnnotation;
2229
2251
  let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
2230
2252
 
@@ -2233,9 +2255,17 @@ const generateVar = (scope, decl) => {
2233
2255
  }
2234
2256
 
2235
2257
  if (x.init) {
2236
- out = out.concat(generate(scope, x.init, global, name));
2237
-
2238
- out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2258
+ const generated = generate(scope, x.init, global, name);
2259
+ if (scope.arrays?.get(name) != null) {
2260
+ // hack to set local as pointer before
2261
+ out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2262
+ if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
2263
+ generated.pop();
2264
+ out = out.concat(generated);
2265
+ } else {
2266
+ out = out.concat(generated);
2267
+ out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2268
+ }
2239
2269
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2240
2270
  }
2241
2271
 
@@ -2262,6 +2292,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2262
2292
  return [];
2263
2293
  }
2264
2294
 
2295
+ const op = decl.operator.slice(0, -1) || '=';
2296
+
2265
2297
  // hack: .length setter
2266
2298
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2267
2299
  const name = decl.left.object.name;
@@ -2270,14 +2302,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2270
2302
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
2271
2303
 
2272
2304
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2305
+ const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2273
2306
 
2274
2307
  return [
2275
2308
  ...(aotPointer ? number(0, Valtype.i32) : [
2276
2309
  ...generate(scope, decl.left.object),
2277
2310
  Opcodes.i32_to_u
2278
2311
  ]),
2312
+ ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2279
2313
 
2280
- ...generate(scope, decl.right),
2314
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2315
+ [ Opcodes.local_get, pointerTmp ],
2316
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
2317
+ Opcodes.i32_from_u
2318
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
2281
2319
  [ Opcodes.local_tee, newValueTmp ],
2282
2320
 
2283
2321
  Opcodes.i32_to_u,
@@ -2287,8 +2325,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2287
2325
  ];
2288
2326
  }
2289
2327
 
2290
- const op = decl.operator.slice(0, -1) || '=';
2291
-
2292
2328
  // arr[i]
2293
2329
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2294
2330
  const name = decl.left.object.name;
@@ -2301,7 +2337,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2301
2337
 
2302
2338
  return [
2303
2339
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2304
- [TYPES._array]: [
2340
+ [TYPES.array]: [
2305
2341
  ...(aotPointer ? [] : [
2306
2342
  ...generate(scope, decl.left.object),
2307
2343
  Opcodes.i32_to_u
@@ -2503,7 +2539,7 @@ const generateUnary = (scope, decl) => {
2503
2539
  [TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
2504
2540
  [TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
2505
2541
 
2506
- [TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2542
+ [TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2507
2543
 
2508
2544
  // object and internal types
2509
2545
  default: makeString(scope, 'object', false, '#typeof_result'),
@@ -2739,7 +2775,7 @@ const generateForOf = (scope, decl) => {
2739
2775
  // set type for local
2740
2776
  // todo: optimize away counter and use end pointer
2741
2777
  out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
2742
- [TYPES._array]: [
2778
+ [TYPES.array]: [
2743
2779
  ...setType(scope, leftName, TYPES.number),
2744
2780
 
2745
2781
  [ Opcodes.loop, Blocktype.void ],
@@ -2822,8 +2858,8 @@ const generateForOf = (scope, decl) => {
2822
2858
  [ Opcodes.end ],
2823
2859
  [ Opcodes.end ]
2824
2860
  ],
2825
- [TYPES._bytestring]: [
2826
- ...setType(scope, leftName, TYPES._bytestring),
2861
+ [TYPES.bytestring]: [
2862
+ ...setType(scope, leftName, TYPES.bytestring),
2827
2863
 
2828
2864
  [ Opcodes.loop, Blocktype.void ],
2829
2865
 
@@ -3092,12 +3128,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3092
3128
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3093
3129
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3094
3130
 
3095
- if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${scope.name} | ${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3131
+ if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
3096
3132
  else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3097
3133
  }
3098
3134
 
3099
3135
  const pointer = scope.arrays.get(name);
3100
3136
 
3137
+ const local = global ? globals[name] : scope.locals[name];
3138
+
3101
3139
  const useRawElements = !!decl.rawElements;
3102
3140
  const elements = useRawElements ? decl.rawElements : decl.elements;
3103
3141
 
@@ -3130,11 +3168,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3130
3168
  return [ out, pointer ];
3131
3169
  }
3132
3170
 
3171
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3172
+ if (pointerTmp != null) {
3173
+ out.push(
3174
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3175
+ Opcodes.i32_to_u,
3176
+ [ Opcodes.local_set, pointerTmp ]
3177
+ );
3178
+ }
3179
+
3180
+ const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3181
+
3133
3182
  // store length as 0th array
3134
3183
  out.push(
3135
- ...number(0, Valtype.i32),
3184
+ ...pointerWasm,
3136
3185
  ...number(length, Valtype.i32),
3137
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
3186
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3138
3187
  );
3139
3188
 
3140
3189
  const storeOp = StoreOps[itemType];
@@ -3143,14 +3192,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3143
3192
  if (elements[i] == null) continue;
3144
3193
 
3145
3194
  out.push(
3146
- ...number(0, Valtype.i32),
3195
+ ...pointerWasm,
3147
3196
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3148
- [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3197
+ [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3149
3198
  );
3150
3199
  }
3151
3200
 
3152
3201
  // local value as pointer
3153
- out.push(...number(pointer));
3202
+ out.push(...pointerWasm, Opcodes.i32_from_u);
3154
3203
 
3155
3204
  return [ out, pointer ];
3156
3205
  };
@@ -3192,6 +3241,20 @@ export const generateMember = (scope, decl, _global, _name) => {
3192
3241
 
3193
3242
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
3194
3243
 
3244
+ // hack: .name
3245
+ if (decl.property.name === 'name') {
3246
+ if (hasFuncWithName(name)) {
3247
+ let nameProp = name;
3248
+
3249
+ // eg: __String_prototype_toLowerCase -> toLowerCase
3250
+ if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
3251
+
3252
+ return makeString(scope, nameProp, _global, _name, true);
3253
+ } else {
3254
+ return generate(scope, DEFAULT_VALUE);
3255
+ }
3256
+ }
3257
+
3195
3258
  // hack: .length
3196
3259
  if (decl.property.name === 'length') {
3197
3260
  const func = funcs.find(x => x.name === name);
@@ -3201,6 +3264,16 @@ export const generateMember = (scope, decl, _global, _name) => {
3201
3264
  return number(typedParams ? func.params.length / 2 : func.params.length);
3202
3265
  }
3203
3266
 
3267
+ if (builtinFuncs[name + '$constructor']) {
3268
+ const regularFunc = builtinFuncs[name];
3269
+ const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
3270
+
3271
+ const constructorFunc = builtinFuncs[name + '$constructor'];
3272
+ const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
3273
+
3274
+ return number(Math.max(regularParams, constructorParams));
3275
+ }
3276
+
3204
3277
  if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
3205
3278
  if (importedFuncs[name]) return number(importedFuncs[name].params);
3206
3279
  if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
@@ -3229,7 +3302,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3229
3302
  }
3230
3303
 
3231
3304
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3232
- [TYPES._array]: [
3305
+ [TYPES.array]: [
3233
3306
  // get index as valtype
3234
3307
  ...property,
3235
3308
 
@@ -3282,7 +3355,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3282
3355
  ...number(TYPES.string, Valtype.i32),
3283
3356
  ...setLastType(scope)
3284
3357
  ],
3285
- [TYPES._bytestring]: [
3358
+ [TYPES.bytestring]: [
3286
3359
  // setup new/out array
3287
3360
  ...newOut,
3288
3361
  [ Opcodes.drop ],
@@ -3307,7 +3380,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3307
3380
  // return new string (page)
3308
3381
  ...number(newPointer),
3309
3382
 
3310
- ...number(TYPES._bytestring, Valtype.i32),
3383
+ ...number(TYPES.bytestring, Valtype.i32),
3311
3384
  ...setLastType(scope)
3312
3385
  ],
3313
3386
 
@@ -3332,8 +3405,8 @@ const objectHack = node => {
3332
3405
 
3333
3406
  if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
3334
3407
 
3335
- // if .length, give up (hack within a hack!)
3336
- if (node.property.name === 'length') {
3408
+ // if .name or .length, give up (hack within a hack!)
3409
+ if (['name', 'length'].includes(node.property.name)) {
3337
3410
  node.object = objectHack(node.object);
3338
3411
  return;
3339
3412
  }
@@ -3476,7 +3549,7 @@ const internalConstrs = {
3476
3549
  ...number(pointer)
3477
3550
  ];
3478
3551
  },
3479
- type: TYPES._array,
3552
+ type: TYPES.array,
3480
3553
  length: 1
3481
3554
  },
3482
3555
 
@@ -3488,7 +3561,7 @@ const internalConstrs = {
3488
3561
  elements: decl.arguments
3489
3562
  }, global, name);
3490
3563
  },
3491
- type: TYPES._array,
3564
+ type: TYPES.array,
3492
3565
  notConstr: true,
3493
3566
  length: 0
3494
3567
  },
@@ -3581,25 +3654,41 @@ const internalConstrs = {
3581
3654
  type: TYPES.number,
3582
3655
  notConstr: true,
3583
3656
  length: 2
3584
- }
3585
- };
3657
+ },
3586
3658
 
3587
- // const _ = Array.prototype.push;
3588
- // Array.prototype.push = function (a) {
3589
- // const check = arr => {
3590
- // for (const x of arr) {
3591
- // if (x === undefined) {
3592
- // console.trace(arr);
3593
- // process.exit();
3594
- // }
3595
- // if (Array.isArray(x)) check(x);
3596
- // }
3597
- // };
3598
- // if (Array.isArray(a) && !new Error().stack.includes('node:')) check(a);
3599
- // // if (Array.isArray(a)) check(a);
3659
+ __console_log: {
3660
+ generate: (scope, decl) => {
3661
+ const out = [];
3662
+
3663
+ for (let i = 0; i < decl.arguments.length; i++) {
3664
+ out.push(
3665
+ ...generateCall(scope, {
3666
+ callee: {
3667
+ type: 'Identifier',
3668
+ name: '__Porffor_print'
3669
+ },
3670
+ arguments: [ decl.arguments[i] ]
3671
+ }),
3672
+
3673
+ // print space
3674
+ ...number(32),
3675
+ [ Opcodes.call, importedFuncs.printChar ]
3676
+ );
3677
+ }
3678
+
3679
+ // print newline
3680
+ out.push(
3681
+ ...number(10),
3682
+ [ Opcodes.call, importedFuncs.printChar ]
3683
+ );
3600
3684
 
3601
- // return _.apply(this, arguments);
3602
- // };
3685
+ return out;
3686
+ },
3687
+ type: TYPES.undefined,
3688
+ notConstr: true,
3689
+ length: 0
3690
+ }
3691
+ };
3603
3692
 
3604
3693
  export default program => {
3605
3694
  globals = {};
@@ -3615,7 +3704,7 @@ export default program => {
3615
3704
 
3616
3705
  globalThis.valtype = 'f64';
3617
3706
 
3618
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
3707
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3619
3708
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3620
3709
 
3621
3710
  globalThis.valtypeBinary = Valtype[valtype];
@@ -3623,7 +3712,7 @@ export default program => {
3623
3712
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3624
3713
 
3625
3714
  globalThis.pageSize = PageSize;
3626
- const pageSizeOpt = process.argv.find(x => x.startsWith('-page-size='));
3715
+ const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3627
3716
  if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3628
3717
 
3629
3718
  // set generic opcodes for current valtype
@@ -110,7 +110,6 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
110
110
 
111
111
  out += '\n';
112
112
  lastInst = inst;
113
- i++;
114
113
  }
115
114
 
116
115
  return highlightAsm(out);