porffor 0.2.0-c87ffeb → 0.2.0-c908b46

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.
@@ -201,7 +201,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
201
201
  }
202
202
 
203
203
  let inst = Opcodes[asm[0].replace('.', '_')];
204
- if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
204
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
205
205
 
206
206
  if (!Array.isArray(inst)) inst = [ inst ];
207
207
  const immediates = asm.slice(1).map(x => {
@@ -210,7 +210,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
210
210
  return int;
211
211
  });
212
212
 
213
- out.push([ ...inst, ...immediates ]);
213
+ out.push([ ...inst, ...immediates.flatMap(x => signedLEB128(x)) ]);
214
214
  }
215
215
 
216
216
  return out;
@@ -219,8 +219,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
219
219
  __Porffor_bs: str => [
220
220
  ...makeString(scope, str, global, name, true),
221
221
 
222
- ...(name ? setType(scope, name, TYPES._bytestring) : [
223
- ...number(TYPES._bytestring, Valtype.i32),
222
+ ...(name ? setType(scope, name, TYPES.bytestring) : [
223
+ ...number(TYPES.bytestring, Valtype.i32),
224
224
  ...setLastType(scope)
225
225
  ])
226
226
  ],
@@ -460,7 +460,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
460
460
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
461
461
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
462
462
 
463
- if (assign) {
463
+ if (assign && Prefs.aotPointerOpt) {
464
464
  const pointer = scope.arrays?.get(name ?? '$undeclared');
465
465
 
466
466
  return [
@@ -723,7 +723,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
723
723
 
724
724
  ...typeSwitch(scope, type, {
725
725
  // [TYPES.number]: def,
726
- [TYPES._array]: [
726
+ [TYPES.array]: [
727
727
  // arrays are always truthy
728
728
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
729
729
  ],
@@ -739,7 +739,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
739
739
  [ Opcodes.i32_eqz ], */
740
740
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
741
741
  ],
742
- [TYPES._bytestring]: [ // duplicate of string
742
+ [TYPES.bytestring]: [ // duplicate of string
743
743
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
744
744
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
745
745
 
@@ -762,7 +762,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
762
762
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
763
763
 
764
764
  ...typeSwitch(scope, type, {
765
- [TYPES._array]: [
765
+ [TYPES.array]: [
766
766
  // arrays are always truthy
767
767
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
768
768
  ],
@@ -777,7 +777,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
777
777
  [ Opcodes.i32_eqz ],
778
778
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
779
779
  ],
780
- [TYPES._bytestring]: [ // duplicate of string
780
+ [TYPES.bytestring]: [ // duplicate of string
781
781
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
782
782
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
783
783
 
@@ -922,7 +922,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
922
922
  }
923
923
  }
924
924
 
925
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) {
925
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
926
926
  if (op === '+') {
927
927
  // todo: this should be dynamic too but for now only static
928
928
  // string concat (a + b)
@@ -1041,12 +1041,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1041
1041
 
1042
1042
  // if left is bytestring
1043
1043
  ...leftType,
1044
- ...number(TYPES._bytestring, Valtype.i32),
1044
+ ...number(TYPES.bytestring, Valtype.i32),
1045
1045
  [ Opcodes.i32_eq ],
1046
1046
 
1047
1047
  // if right is bytestring
1048
1048
  ...rightType,
1049
- ...number(TYPES._bytestring, Valtype.i32),
1049
+ ...number(TYPES.bytestring, Valtype.i32),
1050
1050
  [ Opcodes.i32_eq ],
1051
1051
 
1052
1052
  // if both are true
@@ -1177,7 +1177,6 @@ const generateLogicExp = (scope, decl) => {
1177
1177
  // js type: 4 bits
1178
1178
  // internal type: ? bits
1179
1179
  // pointer: 32 bits
1180
-
1181
1180
  // generic
1182
1181
  // 1 23 4 5
1183
1182
  // 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
@@ -1188,7 +1187,7 @@ const generateLogicExp = (scope, decl) => {
1188
1187
  // 5: pointer
1189
1188
 
1190
1189
  const isExistingProtoFunc = name => {
1191
- if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES._array][name.slice(18)];
1190
+ if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
1192
1191
  if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
1193
1192
 
1194
1193
  return false;
@@ -1247,9 +1246,9 @@ const setLastType = scope => {
1247
1246
  const getNodeType = (scope, node) => {
1248
1247
  const inner = () => {
1249
1248
  if (node.type === 'Literal') {
1250
- if (node.regex) return TYPES._regexp;
1249
+ if (node.regex) return TYPES.regexp;
1251
1250
 
1252
- if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
1251
+ if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
1253
1252
 
1254
1253
  return TYPES[typeof node.value];
1255
1254
  }
@@ -1273,6 +1272,18 @@ const getNodeType = (scope, node) => {
1273
1272
  return TYPES.number;
1274
1273
  }
1275
1274
 
1275
+ if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
1276
+ if (builtinFuncs[name + '$constructor'].typedReturns) {
1277
+ if (scope.locals['#last_type']) return getLastType(scope);
1278
+
1279
+ // presume
1280
+ // todo: warn here?
1281
+ return TYPES.number;
1282
+ }
1283
+
1284
+ return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
1285
+ }
1286
+
1276
1287
  const func = funcs.find(x => x.name === name);
1277
1288
 
1278
1289
  if (func) {
@@ -1291,7 +1302,7 @@ const getNodeType = (scope, node) => {
1291
1302
  const spl = name.slice(2).split('_');
1292
1303
 
1293
1304
  const func = spl[spl.length - 1];
1294
- const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES._bytestring && prototypeFuncs[x][func] != null);
1305
+ const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1295
1306
  if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
1296
1307
  }
1297
1308
 
@@ -1343,7 +1354,7 @@ const getNodeType = (scope, node) => {
1343
1354
  }
1344
1355
 
1345
1356
  if (node.type === 'ArrayExpression') {
1346
- return TYPES._array;
1357
+ return TYPES.array;
1347
1358
  }
1348
1359
 
1349
1360
  if (node.type === 'BinaryExpression') {
@@ -1355,7 +1366,7 @@ const getNodeType = (scope, node) => {
1355
1366
 
1356
1367
  // todo: this should be dynamic but for now only static
1357
1368
  if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
1358
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) return TYPES._bytestring;
1369
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
1359
1370
 
1360
1371
  return TYPES.number;
1361
1372
 
@@ -1381,7 +1392,7 @@ const getNodeType = (scope, node) => {
1381
1392
  if (node.operator === '!') return TYPES.boolean;
1382
1393
  if (node.operator === 'void') return TYPES.undefined;
1383
1394
  if (node.operator === 'delete') return TYPES.boolean;
1384
- if (node.operator === 'typeof') return Prefs.bytestring ? TYPES._bytestring : TYPES.string;
1395
+ if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
1385
1396
 
1386
1397
  return TYPES.number;
1387
1398
  }
@@ -1392,8 +1403,8 @@ const getNodeType = (scope, node) => {
1392
1403
 
1393
1404
  // ts hack
1394
1405
  if (scope.locals[node.object.name]?.metadata?.type === TYPES.string) return TYPES.string;
1395
- if (scope.locals[node.object.name]?.metadata?.type === TYPES._bytestring) return TYPES._bytestring;
1396
- if (scope.locals[node.object.name]?.metadata?.type === TYPES._array) return TYPES.number;
1406
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
1407
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
1397
1408
 
1398
1409
  if (scope.locals['#last_type']) return getLastType(scope);
1399
1410
 
@@ -1460,7 +1471,7 @@ const countLeftover = wasm => {
1460
1471
  if (depth === 0)
1461
1472
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1462
1473
  else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
1463
- else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const].includes(inst[0])) count++;
1474
+ else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
1464
1475
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1465
1476
  else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
1466
1477
  else if (inst[0] === Opcodes.return) count = 0;
@@ -1634,18 +1645,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1634
1645
  // megahack for /regex/.func()
1635
1646
  const funcName = decl.callee.property.name;
1636
1647
  if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1637
- const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
1648
+ const regex = decl.callee.object.regex.pattern;
1649
+ const rhemynName = `regex_${funcName}_${regex}`;
1638
1650
 
1639
- funcIndex[func.name] = func.index;
1640
- funcs.push(func);
1651
+ if (!funcIndex[rhemynName]) {
1652
+ const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
1653
+
1654
+ funcIndex[func.name] = func.index;
1655
+ funcs.push(func);
1656
+ }
1641
1657
 
1658
+ const idx = funcIndex[rhemynName];
1642
1659
  return [
1643
1660
  // make string arg
1644
1661
  ...generate(scope, decl.arguments[0]),
1662
+ Opcodes.i32_to_u,
1663
+ ...getNodeType(scope, decl.arguments[0]),
1645
1664
 
1646
1665
  // call regex func
1647
- Opcodes.i32_to_u,
1648
- [ Opcodes.call, func.index ],
1666
+ [ Opcodes.call, idx ],
1649
1667
  Opcodes.i32_from_u,
1650
1668
 
1651
1669
  ...number(TYPES.boolean, Valtype.i32),
@@ -1685,6 +1703,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1685
1703
 
1686
1704
  protoBC[type] = generateCall(scope, {
1687
1705
  callee: {
1706
+ type: 'Identifier',
1688
1707
  name: x
1689
1708
  },
1690
1709
  arguments: [ target, ...decl.arguments ],
@@ -1807,20 +1826,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1807
1826
  idx = funcIndex[name];
1808
1827
 
1809
1828
  // infer arguments types from builtins params
1810
- const func = funcs.find(x => x.name === name);
1811
- for (let i = 0; i < decl.arguments.length; i++) {
1812
- const arg = decl.arguments[i];
1813
- if (!arg.name) continue;
1814
-
1815
- const local = scope.locals[arg.name];
1816
- if (!local) continue;
1817
-
1818
- local.type = func.params[i];
1819
- if (local.type === Valtype.v128) {
1820
- // specify vec subtype inferred from last vec type in function name
1821
- local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1822
- }
1823
- }
1829
+ // const func = funcs.find(x => x.name === name);
1830
+ // for (let i = 0; i < decl.arguments.length; i++) {
1831
+ // const arg = decl.arguments[i];
1832
+ // if (!arg.name) continue;
1833
+
1834
+ // const local = scope.locals[arg.name];
1835
+ // if (!local) continue;
1836
+
1837
+ // local.type = func.params[i];
1838
+ // if (local.type === Valtype.v128) {
1839
+ // // specify vec subtype inferred from last vec type in function name
1840
+ // local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1841
+ // }
1842
+ // }
1824
1843
  }
1825
1844
 
1826
1845
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1833,28 +1852,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1833
1852
  if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
1834
1853
  const wasmOps = {
1835
1854
  // pointer, align, offset
1836
- i32_load: { imms: 2, args: 1, returns: 1 },
1855
+ i32_load: { imms: 2, args: [ true ], returns: 1 },
1837
1856
  // pointer, value, align, offset
1838
- i32_store: { imms: 2, args: 2, returns: 0 },
1857
+ i32_store: { imms: 2, args: [ true, true ], returns: 0 },
1839
1858
  // pointer, align, offset
1840
- i32_load8_u: { imms: 2, args: 1, returns: 1 },
1859
+ i32_load8_u: { imms: 2, args: [ true ], returns: 1 },
1841
1860
  // pointer, value, align, offset
1842
- i32_store8: { imms: 2, args: 2, returns: 0 },
1861
+ i32_store8: { imms: 2, args: [ true, true ], returns: 0 },
1843
1862
  // pointer, align, offset
1844
- i32_load16_u: { imms: 2, args: 1, returns: 1 },
1863
+ i32_load16_u: { imms: 2, args: [ true ], returns: 1 },
1845
1864
  // pointer, value, align, offset
1846
- i32_store16: { imms: 2, args: 2, returns: 0 },
1865
+ i32_store16: { imms: 2, args: [ true, true ], returns: 0 },
1847
1866
 
1848
1867
  // pointer, align, offset
1849
- f64_load: { imms: 2, args: 1, returns: 1 },
1868
+ f64_load: { imms: 2, args: [ true ], returns: 0 }, // 0 due to not i32
1850
1869
  // pointer, value, align, offset
1851
- f64_store: { imms: 2, args: 2, returns: 0 },
1870
+ f64_store: { imms: 2, args: [ true, false ], returns: 0 },
1852
1871
 
1853
1872
  // value
1854
- i32_const: { imms: 1, args: 0, returns: 1 },
1855
-
1856
- // a, b
1857
- i32_or: { imms: 0, args: 2, returns: 1 },
1873
+ i32_const: { imms: 1, args: [], returns: 1 },
1858
1874
  };
1859
1875
 
1860
1876
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -1863,13 +1879,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1863
1879
  const op = wasmOps[opName];
1864
1880
 
1865
1881
  const argOut = [];
1866
- for (let i = 0; i < op.args; i++) argOut.push(
1882
+ for (let i = 0; i < op.args.length; i++) argOut.push(
1867
1883
  ...generate(scope, decl.arguments[i]),
1868
- Opcodes.i32_to
1884
+ ...(op.args[i] ? [ Opcodes.i32_to ] : [])
1869
1885
  );
1870
1886
 
1871
1887
  // literals only
1872
- const imms = decl.arguments.slice(op.args).map(x => x.value);
1888
+ const imms = decl.arguments.slice(op.args.length).map(x => x.value);
1873
1889
 
1874
1890
  return [
1875
1891
  ...argOut,
@@ -2075,7 +2091,7 @@ const brTable = (input, bc, returns) => {
2075
2091
  };
2076
2092
 
2077
2093
  const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2078
- if (!Prefs.bytestring) delete bc[TYPES._bytestring];
2094
+ if (!Prefs.bytestring) delete bc[TYPES.bytestring];
2079
2095
 
2080
2096
  const known = knownType(scope, type);
2081
2097
  if (known != null) {
@@ -2148,8 +2164,8 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2148
2164
 
2149
2165
  const typeAnnoToPorfType = x => {
2150
2166
  if (!x) return null;
2151
- if (TYPES[x] != null) return TYPES[x];
2152
- if (TYPES['_' + x] != null) return TYPES['_' + x];
2167
+ if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2168
+ if (TYPES['_' + x.toLowerCase()] != null) return TYPES['_' + x.toLowerCase()];
2153
2169
 
2154
2170
  switch (x) {
2155
2171
  case 'i32':
@@ -2178,7 +2194,7 @@ const extractTypeAnnotation = decl => {
2178
2194
  const typeName = type;
2179
2195
  type = typeAnnoToPorfType(type);
2180
2196
 
2181
- if (type === TYPES._bytestring && !Prefs.bytestring) type = TYPES.string;
2197
+ if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
2182
2198
 
2183
2199
  // if (decl.name) console.log(decl.name, { type, elementType });
2184
2200
 
@@ -2192,6 +2208,7 @@ const generateVar = (scope, decl) => {
2192
2208
 
2193
2209
  // global variable if in top scope (main) and var ..., or if wanted
2194
2210
  const global = topLevel || decl._bare; // decl.kind === 'var';
2211
+ const target = global ? globals : scope.locals;
2195
2212
 
2196
2213
  for (const x of decl.declarations) {
2197
2214
  const name = mapName(x.id.name);
@@ -2213,17 +2230,29 @@ const generateVar = (scope, decl) => {
2213
2230
  continue; // always ignore
2214
2231
  }
2215
2232
 
2233
+ // // generate init before allocating var
2234
+ // let generated;
2235
+ // if (x.init) generated = generate(scope, x.init, global, name);
2236
+
2216
2237
  const typed = typedInput && x.id.typeAnnotation;
2217
- let idx = allocVar(scope, name, global, !typed);
2238
+ let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
2218
2239
 
2219
2240
  if (typed) {
2220
2241
  addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
2221
2242
  }
2222
2243
 
2223
2244
  if (x.init) {
2224
- out = out.concat(generate(scope, x.init, global, name));
2225
-
2226
- out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2245
+ const generated = generate(scope, x.init, global, name);
2246
+ if (scope.arrays?.get(name) != null) {
2247
+ // hack to set local as pointer before
2248
+ out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2249
+ if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
2250
+ generated.pop();
2251
+ out = out.concat(generated);
2252
+ } else {
2253
+ out = out.concat(generated);
2254
+ out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2255
+ }
2227
2256
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2228
2257
  }
2229
2258
 
@@ -2250,6 +2279,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2250
2279
  return [];
2251
2280
  }
2252
2281
 
2282
+ const op = decl.operator.slice(0, -1) || '=';
2283
+
2253
2284
  // hack: .length setter
2254
2285
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2255
2286
  const name = decl.left.object.name;
@@ -2258,14 +2289,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2258
2289
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
2259
2290
 
2260
2291
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2292
+ const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2261
2293
 
2262
2294
  return [
2263
2295
  ...(aotPointer ? number(0, Valtype.i32) : [
2264
2296
  ...generate(scope, decl.left.object),
2265
2297
  Opcodes.i32_to_u
2266
2298
  ]),
2299
+ ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2267
2300
 
2268
- ...generate(scope, decl.right),
2301
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2302
+ [ Opcodes.local_get, pointerTmp ],
2303
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
2304
+ Opcodes.i32_from_u
2305
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
2269
2306
  [ Opcodes.local_tee, newValueTmp ],
2270
2307
 
2271
2308
  Opcodes.i32_to_u,
@@ -2275,8 +2312,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2275
2312
  ];
2276
2313
  }
2277
2314
 
2278
- const op = decl.operator.slice(0, -1) || '=';
2279
-
2280
2315
  // arr[i]
2281
2316
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2282
2317
  const name = decl.left.object.name;
@@ -2289,7 +2324,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2289
2324
 
2290
2325
  return [
2291
2326
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2292
- [TYPES._array]: [
2327
+ [TYPES.array]: [
2293
2328
  ...(aotPointer ? [] : [
2294
2329
  ...generate(scope, decl.left.object),
2295
2330
  Opcodes.i32_to_u
@@ -2491,7 +2526,7 @@ const generateUnary = (scope, decl) => {
2491
2526
  [TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
2492
2527
  [TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
2493
2528
 
2494
- [TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2529
+ [TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2495
2530
 
2496
2531
  // object and internal types
2497
2532
  default: makeString(scope, 'object', false, '#typeof_result'),
@@ -2727,7 +2762,7 @@ const generateForOf = (scope, decl) => {
2727
2762
  // set type for local
2728
2763
  // todo: optimize away counter and use end pointer
2729
2764
  out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
2730
- [TYPES._array]: [
2765
+ [TYPES.array]: [
2731
2766
  ...setType(scope, leftName, TYPES.number),
2732
2767
 
2733
2768
  [ Opcodes.loop, Blocktype.void ],
@@ -2810,8 +2845,8 @@ const generateForOf = (scope, decl) => {
2810
2845
  [ Opcodes.end ],
2811
2846
  [ Opcodes.end ]
2812
2847
  ],
2813
- [TYPES._bytestring]: [
2814
- ...setType(scope, leftName, TYPES._bytestring),
2848
+ [TYPES.bytestring]: [
2849
+ ...setType(scope, leftName, TYPES.bytestring),
2815
2850
 
2816
2851
  [ Opcodes.loop, Blocktype.void ],
2817
2852
 
@@ -3080,12 +3115,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3080
3115
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3081
3116
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3082
3117
 
3083
- if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${scope.name} | ${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3118
+ if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
3084
3119
  else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3085
3120
  }
3086
3121
 
3087
3122
  const pointer = scope.arrays.get(name);
3088
3123
 
3124
+ const local = global ? globals[name] : scope.locals[name];
3125
+
3089
3126
  const useRawElements = !!decl.rawElements;
3090
3127
  const elements = useRawElements ? decl.rawElements : decl.elements;
3091
3128
 
@@ -3118,11 +3155,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3118
3155
  return [ out, pointer ];
3119
3156
  }
3120
3157
 
3158
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3159
+ if (pointerTmp != null) {
3160
+ out.push(
3161
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3162
+ Opcodes.i32_to_u,
3163
+ [ Opcodes.local_set, pointerTmp ]
3164
+ );
3165
+ }
3166
+
3167
+ const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3168
+
3121
3169
  // store length as 0th array
3122
3170
  out.push(
3123
- ...number(0, Valtype.i32),
3171
+ ...pointerWasm,
3124
3172
  ...number(length, Valtype.i32),
3125
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
3173
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3126
3174
  );
3127
3175
 
3128
3176
  const storeOp = StoreOps[itemType];
@@ -3131,14 +3179,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3131
3179
  if (elements[i] == null) continue;
3132
3180
 
3133
3181
  out.push(
3134
- ...number(0, Valtype.i32),
3182
+ ...pointerWasm,
3135
3183
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3136
- [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3184
+ [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3137
3185
  );
3138
3186
  }
3139
3187
 
3140
3188
  // local value as pointer
3141
- out.push(...number(pointer));
3189
+ out.push(...pointerWasm, Opcodes.i32_from_u);
3142
3190
 
3143
3191
  return [ out, pointer ];
3144
3192
  };
@@ -3189,6 +3237,16 @@ export const generateMember = (scope, decl, _global, _name) => {
3189
3237
  return number(typedParams ? func.params.length / 2 : func.params.length);
3190
3238
  }
3191
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
+
3192
3250
  if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
3193
3251
  if (importedFuncs[name]) return number(importedFuncs[name].params);
3194
3252
  if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
@@ -3217,7 +3275,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3217
3275
  }
3218
3276
 
3219
3277
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3220
- [TYPES._array]: [
3278
+ [TYPES.array]: [
3221
3279
  // get index as valtype
3222
3280
  ...property,
3223
3281
 
@@ -3270,7 +3328,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3270
3328
  ...number(TYPES.string, Valtype.i32),
3271
3329
  ...setLastType(scope)
3272
3330
  ],
3273
- [TYPES._bytestring]: [
3331
+ [TYPES.bytestring]: [
3274
3332
  // setup new/out array
3275
3333
  ...newOut,
3276
3334
  [ Opcodes.drop ],
@@ -3295,7 +3353,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3295
3353
  // return new string (page)
3296
3354
  ...number(newPointer),
3297
3355
 
3298
- ...number(TYPES._bytestring, Valtype.i32),
3356
+ ...number(TYPES.bytestring, Valtype.i32),
3299
3357
  ...setLastType(scope)
3300
3358
  ],
3301
3359
 
@@ -3464,7 +3522,7 @@ const internalConstrs = {
3464
3522
  ...number(pointer)
3465
3523
  ];
3466
3524
  },
3467
- type: TYPES._array,
3525
+ type: TYPES.array,
3468
3526
  length: 1
3469
3527
  },
3470
3528
 
@@ -3476,7 +3534,7 @@ const internalConstrs = {
3476
3534
  elements: decl.arguments
3477
3535
  }, global, name);
3478
3536
  },
3479
- type: TYPES._array,
3537
+ type: TYPES.array,
3480
3538
  notConstr: true,
3481
3539
  length: 0
3482
3540
  },
@@ -3493,6 +3551,8 @@ const internalConstrs = {
3493
3551
  );
3494
3552
  }
3495
3553
 
3554
+ out.push(Opcodes.i32_from_u);
3555
+
3496
3556
  return out;
3497
3557
  },
3498
3558
  type: TYPES.boolean,
@@ -3511,6 +3571,8 @@ const internalConstrs = {
3511
3571
  );
3512
3572
  }
3513
3573
 
3574
+ out.push(Opcodes.i32_from_u);
3575
+
3514
3576
  return out;
3515
3577
  },
3516
3578
  type: TYPES.boolean,
@@ -3565,25 +3627,41 @@ const internalConstrs = {
3565
3627
  type: TYPES.number,
3566
3628
  notConstr: true,
3567
3629
  length: 2
3568
- }
3569
- };
3630
+ },
3631
+
3632
+ __console_log: {
3633
+ generate: (scope, decl) => {
3634
+ const out = [];
3570
3635
 
3571
- // const _ = Array.prototype.push;
3572
- // Array.prototype.push = function (a) {
3573
- // const check = arr => {
3574
- // for (const x of arr) {
3575
- // if (x === undefined) {
3576
- // console.trace(arr);
3577
- // process.exit();
3578
- // }
3579
- // if (Array.isArray(x)) check(x);
3580
- // }
3581
- // };
3582
- // if (Array.isArray(a) && !new Error().stack.includes('node:')) check(a);
3583
- // // if (Array.isArray(a)) check(a);
3636
+ for (let i = 0; i < decl.arguments.length; i++) {
3637
+ out.push(
3638
+ ...generateCall(scope, {
3639
+ callee: {
3640
+ type: 'Identifier',
3641
+ name: '__Porffor_print'
3642
+ },
3643
+ arguments: [ decl.arguments[i] ]
3644
+ }),
3645
+
3646
+ // print space
3647
+ ...number(32),
3648
+ [ Opcodes.call, importedFuncs.printChar ]
3649
+ );
3650
+ }
3584
3651
 
3585
- // return _.apply(this, arguments);
3586
- // };
3652
+ // print newline
3653
+ out.push(
3654
+ ...number(10),
3655
+ [ Opcodes.call, importedFuncs.printChar ]
3656
+ );
3657
+
3658
+ return out;
3659
+ },
3660
+ type: TYPES.undefined,
3661
+ notConstr: true,
3662
+ length: 0
3663
+ }
3664
+ };
3587
3665
 
3588
3666
  export default program => {
3589
3667
  globals = {};
@@ -3599,7 +3677,7 @@ export default program => {
3599
3677
 
3600
3678
  globalThis.valtype = 'f64';
3601
3679
 
3602
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
3680
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3603
3681
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3604
3682
 
3605
3683
  globalThis.valtypeBinary = Valtype[valtype];
@@ -3607,7 +3685,7 @@ export default program => {
3607
3685
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3608
3686
 
3609
3687
  globalThis.pageSize = PageSize;
3610
- const pageSizeOpt = process.argv.find(x => x.startsWith('-page-size='));
3688
+ const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3611
3689
  if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3612
3690
 
3613
3691
  // set generic opcodes for current valtype