porffor 0.2.0-a6c01f5 → 0.2.0-a88bbe6

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':
@@ -167,11 +171,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
167
171
  newFunc.export = true;
168
172
  }
169
173
 
170
- // if (funcsBefore === funcs.length) throw new Error('no new func added in export');
171
-
172
- // const newFunc = funcs[funcs.length - 1];
173
- // newFunc.export = true;
174
-
175
174
  return [];
176
175
 
177
176
  case 'TaggedTemplateExpression': {
@@ -201,7 +200,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
201
200
  }
202
201
 
203
202
  let inst = Opcodes[asm[0].replace('.', '_')];
204
- if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
203
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
205
204
 
206
205
  if (!Array.isArray(inst)) inst = [ inst ];
207
206
  const immediates = asm.slice(1).map(x => {
@@ -219,8 +218,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
219
218
  __Porffor_bs: str => [
220
219
  ...makeString(scope, str, global, name, true),
221
220
 
222
- ...(name ? setType(scope, name, TYPES._bytestring) : [
223
- ...number(TYPES._bytestring, Valtype.i32),
221
+ ...(name ? setType(scope, name, TYPES.bytestring) : [
222
+ ...number(TYPES.bytestring, Valtype.i32),
224
223
  ...setLastType(scope)
225
224
  ])
226
225
  ],
@@ -460,7 +459,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
460
459
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
461
460
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
462
461
 
463
- if (assign) {
462
+ if (assign && Prefs.aotPointerOpt) {
464
463
  const pointer = scope.arrays?.get(name ?? '$undeclared');
465
464
 
466
465
  return [
@@ -723,7 +722,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
723
722
 
724
723
  ...typeSwitch(scope, type, {
725
724
  // [TYPES.number]: def,
726
- [TYPES._array]: [
725
+ [TYPES.array]: [
727
726
  // arrays are always truthy
728
727
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
729
728
  ],
@@ -739,7 +738,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
739
738
  [ Opcodes.i32_eqz ], */
740
739
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
741
740
  ],
742
- [TYPES._bytestring]: [ // duplicate of string
741
+ [TYPES.bytestring]: [ // duplicate of string
743
742
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
744
743
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
745
744
 
@@ -762,7 +761,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
762
761
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
763
762
 
764
763
  ...typeSwitch(scope, type, {
765
- [TYPES._array]: [
764
+ [TYPES.array]: [
766
765
  // arrays are always truthy
767
766
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
768
767
  ],
@@ -777,7 +776,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
777
776
  [ Opcodes.i32_eqz ],
778
777
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
779
778
  ],
780
- [TYPES._bytestring]: [ // duplicate of string
779
+ [TYPES.bytestring]: [ // duplicate of string
781
780
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
782
781
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
783
782
 
@@ -922,7 +921,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
922
921
  }
923
922
  }
924
923
 
925
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) {
924
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
926
925
  if (op === '+') {
927
926
  // todo: this should be dynamic too but for now only static
928
927
  // string concat (a + b)
@@ -1041,12 +1040,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1041
1040
 
1042
1041
  // if left is bytestring
1043
1042
  ...leftType,
1044
- ...number(TYPES._bytestring, Valtype.i32),
1043
+ ...number(TYPES.bytestring, Valtype.i32),
1045
1044
  [ Opcodes.i32_eq ],
1046
1045
 
1047
1046
  // if right is bytestring
1048
1047
  ...rightType,
1049
- ...number(TYPES._bytestring, Valtype.i32),
1048
+ ...number(TYPES.bytestring, Valtype.i32),
1050
1049
  [ Opcodes.i32_eq ],
1051
1050
 
1052
1051
  // if both are true
@@ -1085,7 +1084,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1085
1084
 
1086
1085
  const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
1087
1086
  return func({ name, params, locals, returns, localInd }, {
1088
- TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
1087
+ TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1089
1088
  builtin: name => {
1090
1089
  let idx = funcIndex[name] ?? importedFuncs[name];
1091
1090
  if (idx === undefined && builtinFuncs[name]) {
@@ -1177,7 +1176,6 @@ const generateLogicExp = (scope, decl) => {
1177
1176
  // js type: 4 bits
1178
1177
  // internal type: ? bits
1179
1178
  // pointer: 32 bits
1180
-
1181
1179
  // generic
1182
1180
  // 1 23 4 5
1183
1181
  // 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
@@ -1188,7 +1186,7 @@ const generateLogicExp = (scope, decl) => {
1188
1186
  // 5: pointer
1189
1187
 
1190
1188
  const isExistingProtoFunc = name => {
1191
- if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES._array][name.slice(18)];
1189
+ if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
1192
1190
  if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
1193
1191
 
1194
1192
  return false;
@@ -1245,11 +1243,11 @@ const setLastType = scope => {
1245
1243
  };
1246
1244
 
1247
1245
  const getNodeType = (scope, node) => {
1248
- const inner = () => {
1246
+ const ret = (() => {
1249
1247
  if (node.type === 'Literal') {
1250
- if (node.regex) return TYPES._regexp;
1248
+ if (node.regex) return TYPES.regexp;
1251
1249
 
1252
- if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
1250
+ if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
1253
1251
 
1254
1252
  return TYPES[typeof node.value];
1255
1253
  }
@@ -1288,7 +1286,6 @@ const getNodeType = (scope, node) => {
1288
1286
  const func = funcs.find(x => x.name === name);
1289
1287
 
1290
1288
  if (func) {
1291
- // console.log(scope, func, func.returnType);
1292
1289
  if (func.returnType) return func.returnType;
1293
1290
  }
1294
1291
 
@@ -1303,7 +1300,7 @@ const getNodeType = (scope, node) => {
1303
1300
  const spl = name.slice(2).split('_');
1304
1301
 
1305
1302
  const func = spl[spl.length - 1];
1306
- const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES._bytestring && prototypeFuncs[x][func] != null);
1303
+ const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1307
1304
  if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
1308
1305
  }
1309
1306
 
@@ -1355,7 +1352,7 @@ const getNodeType = (scope, node) => {
1355
1352
  }
1356
1353
 
1357
1354
  if (node.type === 'ArrayExpression') {
1358
- return TYPES._array;
1355
+ return TYPES.array;
1359
1356
  }
1360
1357
 
1361
1358
  if (node.type === 'BinaryExpression') {
@@ -1367,7 +1364,7 @@ const getNodeType = (scope, node) => {
1367
1364
 
1368
1365
  // todo: this should be dynamic but for now only static
1369
1366
  if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
1370
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) return TYPES._bytestring;
1367
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
1371
1368
 
1372
1369
  return TYPES.number;
1373
1370
 
@@ -1393,19 +1390,28 @@ const getNodeType = (scope, node) => {
1393
1390
  if (node.operator === '!') return TYPES.boolean;
1394
1391
  if (node.operator === 'void') return TYPES.undefined;
1395
1392
  if (node.operator === 'delete') return TYPES.boolean;
1396
- if (node.operator === 'typeof') return Prefs.bytestring ? TYPES._bytestring : TYPES.string;
1393
+ if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
1397
1394
 
1398
1395
  return TYPES.number;
1399
1396
  }
1400
1397
 
1401
1398
  if (node.type === 'MemberExpression') {
1399
+ // hack: if something.name, string type
1400
+ if (node.property.name === 'name') {
1401
+ if (hasFuncWithName(node.object.name)) {
1402
+ return TYPES.bytestring;
1403
+ } else {
1404
+ return TYPES.undefined;
1405
+ }
1406
+ }
1407
+
1402
1408
  // hack: if something.length, number type
1403
1409
  if (node.property.name === 'length') return TYPES.number;
1404
1410
 
1405
1411
  // ts hack
1406
1412
  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;
1413
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
1414
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
1409
1415
 
1410
1416
  if (scope.locals['#last_type']) return getLastType(scope);
1411
1417
 
@@ -1423,10 +1429,8 @@ const getNodeType = (scope, node) => {
1423
1429
  // presume
1424
1430
  // todo: warn here?
1425
1431
  return TYPES.number;
1426
- };
1432
+ })();
1427
1433
 
1428
- const ret = inner();
1429
- // console.trace(node, ret);
1430
1434
  if (typeof ret === 'number') return number(ret, Valtype.i32);
1431
1435
  return ret;
1432
1436
  };
@@ -1646,18 +1650,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1646
1650
  // megahack for /regex/.func()
1647
1651
  const funcName = decl.callee.property.name;
1648
1652
  if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1649
- const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
1653
+ const regex = decl.callee.object.regex.pattern;
1654
+ const rhemynName = `regex_${funcName}_${regex}`;
1655
+
1656
+ if (!funcIndex[rhemynName]) {
1657
+ const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
1650
1658
 
1651
- funcIndex[func.name] = func.index;
1652
- funcs.push(func);
1659
+ funcIndex[func.name] = func.index;
1660
+ funcs.push(func);
1661
+ }
1653
1662
 
1663
+ const idx = funcIndex[rhemynName];
1654
1664
  return [
1655
1665
  // make string arg
1656
1666
  ...generate(scope, decl.arguments[0]),
1667
+ Opcodes.i32_to_u,
1668
+ ...getNodeType(scope, decl.arguments[0]),
1657
1669
 
1658
1670
  // call regex func
1659
- Opcodes.i32_to_u,
1660
- [ Opcodes.call, func.index ],
1671
+ [ Opcodes.call, idx ],
1661
1672
  Opcodes.i32_from_u,
1662
1673
 
1663
1674
  ...number(TYPES.boolean, Valtype.i32),
@@ -1818,22 +1829,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1818
1829
 
1819
1830
  includeBuiltin(scope, name);
1820
1831
  idx = funcIndex[name];
1821
-
1822
- // infer arguments types from builtins params
1823
- const func = funcs.find(x => x.name === name);
1824
- for (let i = 0; i < decl.arguments.length; i++) {
1825
- const arg = decl.arguments[i];
1826
- if (!arg.name) continue;
1827
-
1828
- const local = scope.locals[arg.name];
1829
- if (!local) continue;
1830
-
1831
- local.type = func.params[i];
1832
- if (local.type === Valtype.v128) {
1833
- // specify vec subtype inferred from last vec type in function name
1834
- local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1835
- }
1836
- }
1837
1832
  }
1838
1833
 
1839
1834
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1865,9 +1860,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1865
1860
 
1866
1861
  // value
1867
1862
  i32_const: { imms: 1, args: [], returns: 1 },
1868
-
1869
- // a, b
1870
- i32_or: { imms: 0, args: [ true, true ], returns: 1 },
1871
1863
  };
1872
1864
 
1873
1865
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -2088,7 +2080,7 @@ const brTable = (input, bc, returns) => {
2088
2080
  };
2089
2081
 
2090
2082
  const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2091
- if (!Prefs.bytestring) delete bc[TYPES._bytestring];
2083
+ if (!Prefs.bytestring) delete bc[TYPES.bytestring];
2092
2084
 
2093
2085
  const known = knownType(scope, type);
2094
2086
  if (known != null) {
@@ -2162,7 +2154,6 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2162
2154
  const typeAnnoToPorfType = x => {
2163
2155
  if (!x) return null;
2164
2156
  if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2165
- if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
2166
2157
 
2167
2158
  switch (x) {
2168
2159
  case 'i32':
@@ -2191,7 +2182,7 @@ const extractTypeAnnotation = decl => {
2191
2182
  const typeName = type;
2192
2183
  type = typeAnnoToPorfType(type);
2193
2184
 
2194
- if (type === TYPES._bytestring && !Prefs.bytestring) type = TYPES.string;
2185
+ if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
2195
2186
 
2196
2187
  // if (decl.name) console.log(decl.name, { type, elementType });
2197
2188
 
@@ -2203,8 +2194,8 @@ const generateVar = (scope, decl) => {
2203
2194
 
2204
2195
  const topLevel = scope.name === 'main';
2205
2196
 
2206
- // global variable if in top scope (main) and var ..., or if wanted
2207
- const global = topLevel || decl._bare; // decl.kind === 'var';
2197
+ // global variable if in top scope (main) or if internally wanted
2198
+ const global = topLevel || decl._bare;
2208
2199
 
2209
2200
  for (const x of decl.declarations) {
2210
2201
  const name = mapName(x.id.name);
@@ -2218,7 +2209,6 @@ const generateVar = (scope, decl) => {
2218
2209
  continue;
2219
2210
  }
2220
2211
 
2221
- // console.log(name);
2222
2212
  if (topLevel && builtinVars[name]) {
2223
2213
  // cannot redeclare
2224
2214
  if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
@@ -2226,6 +2216,10 @@ const generateVar = (scope, decl) => {
2226
2216
  continue; // always ignore
2227
2217
  }
2228
2218
 
2219
+ // // generate init before allocating var
2220
+ // let generated;
2221
+ // if (x.init) generated = generate(scope, x.init, global, name);
2222
+
2229
2223
  const typed = typedInput && x.id.typeAnnotation;
2230
2224
  let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
2231
2225
 
@@ -2234,9 +2228,17 @@ const generateVar = (scope, decl) => {
2234
2228
  }
2235
2229
 
2236
2230
  if (x.init) {
2237
- out = out.concat(generate(scope, x.init, global, name));
2238
-
2239
- out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2231
+ const generated = generate(scope, x.init, global, name);
2232
+ if (scope.arrays?.get(name) != null) {
2233
+ // hack to set local as pointer before
2234
+ out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2235
+ if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
2236
+ generated.pop();
2237
+ out = out.concat(generated);
2238
+ } else {
2239
+ out = out.concat(generated);
2240
+ out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2241
+ }
2240
2242
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2241
2243
  }
2242
2244
 
@@ -2263,6 +2265,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2263
2265
  return [];
2264
2266
  }
2265
2267
 
2268
+ const op = decl.operator.slice(0, -1) || '=';
2269
+
2266
2270
  // hack: .length setter
2267
2271
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2268
2272
  const name = decl.left.object.name;
@@ -2271,14 +2275,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2271
2275
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
2272
2276
 
2273
2277
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2278
+ const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2274
2279
 
2275
2280
  return [
2276
2281
  ...(aotPointer ? number(0, Valtype.i32) : [
2277
2282
  ...generate(scope, decl.left.object),
2278
2283
  Opcodes.i32_to_u
2279
2284
  ]),
2285
+ ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2280
2286
 
2281
- ...generate(scope, decl.right),
2287
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2288
+ [ Opcodes.local_get, pointerTmp ],
2289
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
2290
+ Opcodes.i32_from_u
2291
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
2282
2292
  [ Opcodes.local_tee, newValueTmp ],
2283
2293
 
2284
2294
  Opcodes.i32_to_u,
@@ -2288,8 +2298,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2288
2298
  ];
2289
2299
  }
2290
2300
 
2291
- const op = decl.operator.slice(0, -1) || '=';
2292
-
2293
2301
  // arr[i]
2294
2302
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2295
2303
  const name = decl.left.object.name;
@@ -2302,7 +2310,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2302
2310
 
2303
2311
  return [
2304
2312
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2305
- [TYPES._array]: [
2313
+ [TYPES.array]: [
2306
2314
  ...(aotPointer ? [] : [
2307
2315
  ...generate(scope, decl.left.object),
2308
2316
  Opcodes.i32_to_u
@@ -2504,7 +2512,7 @@ const generateUnary = (scope, decl) => {
2504
2512
  [TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
2505
2513
  [TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
2506
2514
 
2507
- [TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2515
+ [TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2508
2516
 
2509
2517
  // object and internal types
2510
2518
  default: makeString(scope, 'object', false, '#typeof_result'),
@@ -2740,7 +2748,7 @@ const generateForOf = (scope, decl) => {
2740
2748
  // set type for local
2741
2749
  // todo: optimize away counter and use end pointer
2742
2750
  out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
2743
- [TYPES._array]: [
2751
+ [TYPES.array]: [
2744
2752
  ...setType(scope, leftName, TYPES.number),
2745
2753
 
2746
2754
  [ Opcodes.loop, Blocktype.void ],
@@ -2823,8 +2831,8 @@ const generateForOf = (scope, decl) => {
2823
2831
  [ Opcodes.end ],
2824
2832
  [ Opcodes.end ]
2825
2833
  ],
2826
- [TYPES._bytestring]: [
2827
- ...setType(scope, leftName, TYPES._bytestring),
2834
+ [TYPES.bytestring]: [
2835
+ ...setType(scope, leftName, TYPES.bytestring),
2828
2836
 
2829
2837
  [ Opcodes.loop, Blocktype.void ],
2830
2838
 
@@ -3093,12 +3101,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3093
3101
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3094
3102
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3095
3103
 
3096
- if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${scope.name} | ${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3104
+ if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
3097
3105
  else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3098
3106
  }
3099
3107
 
3100
3108
  const pointer = scope.arrays.get(name);
3101
3109
 
3110
+ const local = global ? globals[name] : scope.locals[name];
3111
+
3102
3112
  const useRawElements = !!decl.rawElements;
3103
3113
  const elements = useRawElements ? decl.rawElements : decl.elements;
3104
3114
 
@@ -3131,11 +3141,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3131
3141
  return [ out, pointer ];
3132
3142
  }
3133
3143
 
3144
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3145
+ if (pointerTmp != null) {
3146
+ out.push(
3147
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3148
+ Opcodes.i32_to_u,
3149
+ [ Opcodes.local_set, pointerTmp ]
3150
+ );
3151
+ }
3152
+
3153
+ const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3154
+
3134
3155
  // store length as 0th array
3135
3156
  out.push(
3136
- ...number(0, Valtype.i32),
3157
+ ...pointerWasm,
3137
3158
  ...number(length, Valtype.i32),
3138
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
3159
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3139
3160
  );
3140
3161
 
3141
3162
  const storeOp = StoreOps[itemType];
@@ -3144,14 +3165,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3144
3165
  if (elements[i] == null) continue;
3145
3166
 
3146
3167
  out.push(
3147
- ...number(0, Valtype.i32),
3168
+ ...pointerWasm,
3148
3169
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3149
- [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3170
+ [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3150
3171
  );
3151
3172
  }
3152
3173
 
3153
3174
  // local value as pointer
3154
- out.push(...number(pointer));
3175
+ out.push(...pointerWasm, Opcodes.i32_from_u);
3155
3176
 
3156
3177
  return [ out, pointer ];
3157
3178
  };
@@ -3193,6 +3214,20 @@ export const generateMember = (scope, decl, _global, _name) => {
3193
3214
 
3194
3215
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
3195
3216
 
3217
+ // hack: .name
3218
+ if (decl.property.name === 'name') {
3219
+ if (hasFuncWithName(name)) {
3220
+ let nameProp = name;
3221
+
3222
+ // eg: __String_prototype_toLowerCase -> toLowerCase
3223
+ if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
3224
+
3225
+ return makeString(scope, nameProp, _global, _name, true);
3226
+ } else {
3227
+ return generate(scope, DEFAULT_VALUE);
3228
+ }
3229
+ }
3230
+
3196
3231
  // hack: .length
3197
3232
  if (decl.property.name === 'length') {
3198
3233
  const func = funcs.find(x => x.name === name);
@@ -3202,6 +3237,16 @@ export const generateMember = (scope, decl, _global, _name) => {
3202
3237
  return number(typedParams ? func.params.length / 2 : func.params.length);
3203
3238
  }
3204
3239
 
3240
+ if (builtinFuncs[name + '$constructor']) {
3241
+ const regularFunc = builtinFuncs[name];
3242
+ const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
3243
+
3244
+ const constructorFunc = builtinFuncs[name + '$constructor'];
3245
+ const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
3246
+
3247
+ return number(Math.max(regularParams, constructorParams));
3248
+ }
3249
+
3205
3250
  if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
3206
3251
  if (importedFuncs[name]) return number(importedFuncs[name].params);
3207
3252
  if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
@@ -3230,7 +3275,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3230
3275
  }
3231
3276
 
3232
3277
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3233
- [TYPES._array]: [
3278
+ [TYPES.array]: [
3234
3279
  // get index as valtype
3235
3280
  ...property,
3236
3281
 
@@ -3283,7 +3328,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3283
3328
  ...number(TYPES.string, Valtype.i32),
3284
3329
  ...setLastType(scope)
3285
3330
  ],
3286
- [TYPES._bytestring]: [
3331
+ [TYPES.bytestring]: [
3287
3332
  // setup new/out array
3288
3333
  ...newOut,
3289
3334
  [ Opcodes.drop ],
@@ -3308,7 +3353,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3308
3353
  // return new string (page)
3309
3354
  ...number(newPointer),
3310
3355
 
3311
- ...number(TYPES._bytestring, Valtype.i32),
3356
+ ...number(TYPES.bytestring, Valtype.i32),
3312
3357
  ...setLastType(scope)
3313
3358
  ],
3314
3359
 
@@ -3333,8 +3378,8 @@ const objectHack = node => {
3333
3378
 
3334
3379
  if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
3335
3380
 
3336
- // if .length, give up (hack within a hack!)
3337
- if (node.property.name === 'length') {
3381
+ // if .name or .length, give up (hack within a hack!)
3382
+ if (['name', 'length'].includes(node.property.name)) {
3338
3383
  node.object = objectHack(node.object);
3339
3384
  return;
3340
3385
  }
@@ -3383,8 +3428,11 @@ const generateFunc = (scope, decl) => {
3383
3428
  };
3384
3429
 
3385
3430
  if (typedInput && decl.returnType) {
3386
- innerScope.returnType = extractTypeAnnotation(decl.returnType).type;
3387
- innerScope.returns = [ valtypeBinary ];
3431
+ const { type } = extractTypeAnnotation(decl.returnType);
3432
+ if (type != null) {
3433
+ innerScope.returnType = type;
3434
+ innerScope.returns = [ valtypeBinary ];
3435
+ }
3388
3436
  }
3389
3437
 
3390
3438
  for (let i = 0; i < params.length; i++) {
@@ -3426,7 +3474,7 @@ const generateFunc = (scope, decl) => {
3426
3474
  if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
3427
3475
  wasm.push(
3428
3476
  ...number(0),
3429
- ...number(TYPES.undefined, Valtype.i32),
3477
+ ...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
3430
3478
  [ Opcodes.return ]
3431
3479
  );
3432
3480
  }
@@ -3477,7 +3525,7 @@ const internalConstrs = {
3477
3525
  ...number(pointer)
3478
3526
  ];
3479
3527
  },
3480
- type: TYPES._array,
3528
+ type: TYPES.array,
3481
3529
  length: 1
3482
3530
  },
3483
3531
 
@@ -3489,7 +3537,7 @@ const internalConstrs = {
3489
3537
  elements: decl.arguments
3490
3538
  }, global, name);
3491
3539
  },
3492
- type: TYPES._array,
3540
+ type: TYPES.array,
3493
3541
  notConstr: true,
3494
3542
  length: 0
3495
3543
  },
@@ -3618,23 +3666,6 @@ const internalConstrs = {
3618
3666
  }
3619
3667
  };
3620
3668
 
3621
- // const _ = Array.prototype.push;
3622
- // Array.prototype.push = function (a) {
3623
- // const check = arr => {
3624
- // for (const x of arr) {
3625
- // if (x === undefined) {
3626
- // console.trace(arr);
3627
- // process.exit();
3628
- // }
3629
- // if (Array.isArray(x)) check(x);
3630
- // }
3631
- // };
3632
- // if (Array.isArray(a) && !new Error().stack.includes('node:')) check(a);
3633
- // // if (Array.isArray(a)) check(a);
3634
-
3635
- // return _.apply(this, arguments);
3636
- // };
3637
-
3638
3669
  export default program => {
3639
3670
  globals = {};
3640
3671
  globalInd = 0;
@@ -3649,7 +3680,7 @@ export default program => {
3649
3680
 
3650
3681
  globalThis.valtype = 'f64';
3651
3682
 
3652
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
3683
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3653
3684
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3654
3685
 
3655
3686
  globalThis.valtypeBinary = Valtype[valtype];
@@ -3657,7 +3688,7 @@ export default program => {
3657
3688
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3658
3689
 
3659
3690
  globalThis.pageSize = PageSize;
3660
- const pageSizeOpt = process.argv.find(x => x.startsWith('-page-size='));
3691
+ const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3661
3692
  if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3662
3693
 
3663
3694
  // 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);