porffor 0.2.0-69d30a8 → 0.2.0-6bc63ef

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.
Files changed (50) hide show
  1. package/CONTRIBUTING.md +256 -0
  2. package/README.md +64 -44
  3. package/asur/index.js +2 -2
  4. package/byg/index.js +3 -24
  5. package/compiler/2c.js +2 -53
  6. package/compiler/assemble.js +6 -7
  7. package/compiler/builtins/annexb_string.js +12 -12
  8. package/compiler/builtins/annexb_string.ts +5 -6
  9. package/compiler/builtins/array.ts +15 -15
  10. package/compiler/builtins/base64.ts +4 -79
  11. package/compiler/builtins/boolean.ts +18 -0
  12. package/compiler/builtins/crypto.ts +1 -1
  13. package/compiler/builtins/date.ts +2067 -0
  14. package/compiler/builtins/escape.ts +2 -2
  15. package/compiler/builtins/function.ts +5 -0
  16. package/compiler/builtins/int.ts +2 -4
  17. package/compiler/builtins/number.ts +11 -9
  18. package/compiler/builtins/object.ts +4 -0
  19. package/compiler/builtins/porffor.d.ts +28 -10
  20. package/compiler/builtins/set.ts +187 -0
  21. package/compiler/builtins/string.ts +47 -22
  22. package/compiler/builtins.js +19 -36
  23. package/compiler/codegen.js +239 -199
  24. package/compiler/decompile.js +2 -3
  25. package/compiler/embedding.js +2 -2
  26. package/compiler/encoding.js +0 -14
  27. package/compiler/expression.js +1 -1
  28. package/compiler/generated_builtins.js +1138 -208
  29. package/compiler/index.js +0 -2
  30. package/compiler/opt.js +7 -7
  31. package/compiler/parse.js +5 -5
  32. package/compiler/precompile.js +21 -24
  33. package/compiler/prefs.js +6 -5
  34. package/compiler/prototype.js +19 -19
  35. package/compiler/types.js +3 -2
  36. package/compiler/wasmSpec.js +1 -0
  37. package/compiler/wrap.js +70 -54
  38. package/package.json +1 -1
  39. package/rhemyn/compile.js +42 -25
  40. package/rhemyn/parse.js +4 -5
  41. package/runner/compare.js +0 -1
  42. package/runner/debug.js +1 -6
  43. package/runner/index.js +45 -4
  44. package/runner/profiler.js +15 -42
  45. package/runner/repl.js +3 -9
  46. package/runner/sizes.js +2 -2
  47. package/runner/version.js +3 -3
  48. package/.vscode/launch.json +0 -18
  49. package/compiler/builtins/tostring.ts +0 -45
  50. package/test262_changes_from_1afe9b87d2_to_04-09.md +0 -270
@@ -1,14 +1,14 @@
1
- import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from "./wasmSpec.js";
2
- import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from "./encoding.js";
3
- import { operatorOpcode } from "./expression.js";
4
- import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from "./builtins.js";
5
- import { PrototypeFuncs } from "./prototype.js";
6
- import { number, i32x4, enforceOneByte, enforceTwoBytes, enforceFourBytes, enforceEightBytes } from "./embedding.js";
7
- import { log } from "./log.js";
8
- import parse from "./parse.js";
9
- import * as Rhemyn from "../rhemyn/compile.js";
10
- import Prefs from './prefs.js';
1
+ import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
2
+ import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
3
+ import { operatorOpcode } from './expression.js';
4
+ import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
5
+ import { PrototypeFuncs } from './prototype.js';
6
+ import { number } from './embedding.js';
11
7
  import { TYPES, TYPE_NAMES } from './types.js';
8
+ import * as Rhemyn from '../rhemyn/compile.js';
9
+ import parse from './parse.js';
10
+ import { log } from './log.js';
11
+ import Prefs from './prefs.js';
12
12
 
13
13
  let globals = {};
14
14
  let globalInd = 0;
@@ -19,24 +19,6 @@ let funcIndex = {};
19
19
  let currentFuncIndex = importedFuncs.length;
20
20
  let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
21
21
 
22
- const debug = str => {
23
- const code = [];
24
-
25
- const logChar = n => {
26
- code.push(...number(n));
27
-
28
- code.push([ Opcodes.call, 0 ]);
29
- };
30
-
31
- for (let i = 0; i < str.length; i++) {
32
- logChar(str.charCodeAt(i));
33
- }
34
-
35
- logChar(10); // new line
36
-
37
- return code;
38
- };
39
-
40
22
  class TodoError extends Error {
41
23
  constructor(message) {
42
24
  super(message);
@@ -59,6 +41,10 @@ const todo = (scope, msg, expectsValue = undefined) => {
59
41
  };
60
42
 
61
43
  const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
44
+ const hasFuncWithName = name => {
45
+ const func = funcs.find(x => x.name === name);
46
+ return !!(func || builtinFuncs[name] || importedFuncs[name] || internalConstrs[name]);
47
+ };
62
48
  const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
63
49
  switch (decl.type) {
64
50
  case 'BinaryExpression':
@@ -167,11 +153,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
167
153
  newFunc.export = true;
168
154
  }
169
155
 
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
156
  return [];
176
157
 
177
158
  case 'TaggedTemplateExpression': {
@@ -201,7 +182,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
201
182
  }
202
183
 
203
184
  let inst = Opcodes[asm[0].replace('.', '_')];
204
- if (!inst) throw new Error(`inline asm: inst ${asm[0]} not found`);
185
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
205
186
 
206
187
  if (!Array.isArray(inst)) inst = [ inst ];
207
188
  const immediates = asm.slice(1).map(x => {
@@ -210,7 +191,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
210
191
  return int;
211
192
  });
212
193
 
213
- out.push([ ...inst, ...immediates ]);
194
+ out.push([ ...inst, ...immediates.flatMap(x => signedLEB128(x)) ]);
214
195
  }
215
196
 
216
197
  return out;
@@ -219,8 +200,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
219
200
  __Porffor_bs: str => [
220
201
  ...makeString(scope, str, global, name, true),
221
202
 
222
- ...(name ? setType(scope, name, TYPES._bytestring) : [
223
- ...number(TYPES._bytestring, Valtype.i32),
203
+ ...(name ? setType(scope, name, TYPES.bytestring) : [
204
+ ...number(TYPES.bytestring, Valtype.i32),
224
205
  ...setLastType(scope)
225
206
  ])
226
207
  ],
@@ -460,7 +441,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
460
441
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
461
442
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
462
443
 
463
- if (assign) {
444
+ if (assign && Prefs.aotPointerOpt) {
464
445
  const pointer = scope.arrays?.get(name ?? '$undeclared');
465
446
 
466
447
  return [
@@ -723,7 +704,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
723
704
 
724
705
  ...typeSwitch(scope, type, {
725
706
  // [TYPES.number]: def,
726
- [TYPES._array]: [
707
+ [TYPES.array]: [
727
708
  // arrays are always truthy
728
709
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
729
710
  ],
@@ -739,7 +720,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
739
720
  [ Opcodes.i32_eqz ], */
740
721
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
741
722
  ],
742
- [TYPES._bytestring]: [ // duplicate of string
723
+ [TYPES.bytestring]: [ // duplicate of string
743
724
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
744
725
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
745
726
 
@@ -762,7 +743,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
762
743
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
763
744
 
764
745
  ...typeSwitch(scope, type, {
765
- [TYPES._array]: [
746
+ [TYPES.array]: [
766
747
  // arrays are always truthy
767
748
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
768
749
  ],
@@ -777,7 +758,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
777
758
  [ Opcodes.i32_eqz ],
778
759
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
779
760
  ],
780
- [TYPES._bytestring]: [ // duplicate of string
761
+ [TYPES.bytestring]: [ // duplicate of string
781
762
  ...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
782
763
  ...(intIn ? [] : [ Opcodes.i32_to_u ]),
783
764
 
@@ -854,31 +835,6 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
854
835
 
855
836
  // if strict (in)equal check types match
856
837
  if (strictOp) {
857
- // startOut.push(
858
- // ...leftType,
859
- // ...rightType,
860
- // [ Opcodes.i32_eq ]
861
- // );
862
-
863
- // endOut.push(
864
- // [ Opcodes.i32_and ]
865
- // );
866
-
867
- // startOut.push(
868
- // [ Opcodes.block, Valtype.i32 ],
869
- // ...leftType,
870
- // ...rightType,
871
- // [ Opcodes.i32_ne ],
872
- // [ Opcodes.if, Blocktype.void ],
873
- // ...number(op === '===' ? 0 : 1, Valtype.i32),
874
- // [ Opcodes.br, 1 ],
875
- // [ Opcodes.end ]
876
- // );
877
-
878
- // endOut.push(
879
- // [ Opcodes.end ]
880
- // );
881
-
882
838
  endOut.push(
883
839
  ...leftType,
884
840
  ...rightType,
@@ -922,7 +878,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
922
878
  }
923
879
  }
924
880
 
925
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) {
881
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) {
926
882
  if (op === '+') {
927
883
  // todo: this should be dynamic too but for now only static
928
884
  // string concat (a + b)
@@ -1041,12 +997,12 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1041
997
 
1042
998
  // if left is bytestring
1043
999
  ...leftType,
1044
- ...number(TYPES._bytestring, Valtype.i32),
1000
+ ...number(TYPES.bytestring, Valtype.i32),
1045
1001
  [ Opcodes.i32_eq ],
1046
1002
 
1047
1003
  // if right is bytestring
1048
1004
  ...rightType,
1049
- ...number(TYPES._bytestring, Valtype.i32),
1005
+ ...number(TYPES.bytestring, Valtype.i32),
1050
1006
  [ Opcodes.i32_eq ],
1051
1007
 
1052
1008
  // if both are true
@@ -1085,7 +1041,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1085
1041
 
1086
1042
  const asmFuncToAsm = (func, { name = '#unknown_asm_func', params = [], locals = [], returns = [], localInd = 0 }) => {
1087
1043
  return func({ name, params, locals, returns, localInd }, {
1088
- TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage,
1044
+ TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1089
1045
  builtin: name => {
1090
1046
  let idx = funcIndex[name] ?? importedFuncs[name];
1091
1047
  if (idx === undefined && builtinFuncs[name]) {
@@ -1177,7 +1133,6 @@ const generateLogicExp = (scope, decl) => {
1177
1133
  // js type: 4 bits
1178
1134
  // internal type: ? bits
1179
1135
  // pointer: 32 bits
1180
-
1181
1136
  // generic
1182
1137
  // 1 23 4 5
1183
1138
  // 0 11111111111 11TTTTIIII??????????PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
@@ -1188,7 +1143,7 @@ const generateLogicExp = (scope, decl) => {
1188
1143
  // 5: pointer
1189
1144
 
1190
1145
  const isExistingProtoFunc = name => {
1191
- if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES._array][name.slice(18)];
1146
+ if (name.startsWith('__Array_prototype')) return !!prototypeFuncs[TYPES.array][name.slice(18)];
1192
1147
  if (name.startsWith('__String_prototype_')) return !!prototypeFuncs[TYPES.string][name.slice(19)];
1193
1148
 
1194
1149
  return false;
@@ -1245,11 +1200,11 @@ const setLastType = scope => {
1245
1200
  };
1246
1201
 
1247
1202
  const getNodeType = (scope, node) => {
1248
- const inner = () => {
1203
+ const ret = (() => {
1249
1204
  if (node.type === 'Literal') {
1250
- if (node.regex) return TYPES._regexp;
1205
+ if (node.regex) return TYPES.regexp;
1251
1206
 
1252
- if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
1207
+ if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES.bytestring;
1253
1208
 
1254
1209
  return TYPES[typeof node.value];
1255
1210
  }
@@ -1273,10 +1228,21 @@ const getNodeType = (scope, node) => {
1273
1228
  return TYPES.number;
1274
1229
  }
1275
1230
 
1231
+ if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
1232
+ if (builtinFuncs[name + '$constructor'].typedReturns) {
1233
+ if (scope.locals['#last_type']) return getLastType(scope);
1234
+
1235
+ // presume
1236
+ // todo: warn here?
1237
+ return TYPES.number;
1238
+ }
1239
+
1240
+ return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
1241
+ }
1242
+
1276
1243
  const func = funcs.find(x => x.name === name);
1277
1244
 
1278
1245
  if (func) {
1279
- // console.log(scope, func, func.returnType);
1280
1246
  if (func.returnType) return func.returnType;
1281
1247
  }
1282
1248
 
@@ -1291,7 +1257,7 @@ const getNodeType = (scope, node) => {
1291
1257
  const spl = name.slice(2).split('_');
1292
1258
 
1293
1259
  const func = spl[spl.length - 1];
1294
- const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES._bytestring && prototypeFuncs[x][func] != null);
1260
+ const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1295
1261
  if (protoFuncs.length === 1) return protoFuncs[0].returnType ?? TYPES.number;
1296
1262
  }
1297
1263
 
@@ -1343,7 +1309,7 @@ const getNodeType = (scope, node) => {
1343
1309
  }
1344
1310
 
1345
1311
  if (node.type === 'ArrayExpression') {
1346
- return TYPES._array;
1312
+ return TYPES.array;
1347
1313
  }
1348
1314
 
1349
1315
  if (node.type === 'BinaryExpression') {
@@ -1355,7 +1321,7 @@ const getNodeType = (scope, node) => {
1355
1321
 
1356
1322
  // todo: this should be dynamic but for now only static
1357
1323
  if (knownLeft === TYPES.string || knownRight === TYPES.string) return TYPES.string;
1358
- if (knownLeft === TYPES._bytestring || knownRight === TYPES._bytestring) return TYPES._bytestring;
1324
+ if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
1359
1325
 
1360
1326
  return TYPES.number;
1361
1327
 
@@ -1381,19 +1347,28 @@ const getNodeType = (scope, node) => {
1381
1347
  if (node.operator === '!') return TYPES.boolean;
1382
1348
  if (node.operator === 'void') return TYPES.undefined;
1383
1349
  if (node.operator === 'delete') return TYPES.boolean;
1384
- if (node.operator === 'typeof') return Prefs.bytestring ? TYPES._bytestring : TYPES.string;
1350
+ if (node.operator === 'typeof') return Prefs.bytestring ? TYPES.bytestring : TYPES.string;
1385
1351
 
1386
1352
  return TYPES.number;
1387
1353
  }
1388
1354
 
1389
1355
  if (node.type === 'MemberExpression') {
1356
+ // hack: if something.name, string type
1357
+ if (node.property.name === 'name') {
1358
+ if (hasFuncWithName(node.object.name)) {
1359
+ return TYPES.bytestring;
1360
+ } else {
1361
+ return TYPES.undefined;
1362
+ }
1363
+ }
1364
+
1390
1365
  // hack: if something.length, number type
1391
1366
  if (node.property.name === 'length') return TYPES.number;
1392
1367
 
1393
1368
  // ts hack
1394
1369
  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;
1370
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.bytestring) return TYPES.bytestring;
1371
+ if (scope.locals[node.object.name]?.metadata?.type === TYPES.array) return TYPES.number;
1397
1372
 
1398
1373
  if (scope.locals['#last_type']) return getLastType(scope);
1399
1374
 
@@ -1411,10 +1386,8 @@ const getNodeType = (scope, node) => {
1411
1386
  // presume
1412
1387
  // todo: warn here?
1413
1388
  return TYPES.number;
1414
- };
1389
+ })();
1415
1390
 
1416
- const ret = inner();
1417
- // console.trace(node, ret);
1418
1391
  if (typeof ret === 'number') return number(ret, Valtype.i32);
1419
1392
  return ret;
1420
1393
  };
@@ -1460,16 +1433,23 @@ const countLeftover = wasm => {
1460
1433
  if (depth === 0)
1461
1434
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1462
1435
  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++;
1436
+ 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
1437
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1465
1438
  else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
1466
1439
  else if (inst[0] === Opcodes.return) count = 0;
1467
1440
  else if (inst[0] === Opcodes.call) {
1468
1441
  let func = funcs.find(x => x.index === inst[1]);
1469
- if (func) {
1470
- count -= func.params.length;
1471
- } else count--;
1472
- if (func) count += func.returns.length;
1442
+ if (inst[1] === -1) {
1443
+ // todo: count for calling self
1444
+ } else if (!func && inst[1] < importedFuncs.length) {
1445
+ count -= importedFuncs[inst[1]].params;
1446
+ count += importedFuncs[inst[1]].returns;
1447
+ } else {
1448
+ if (func) {
1449
+ count -= func.params.length;
1450
+ } else count--;
1451
+ if (func) count += func.returns.length;
1452
+ }
1473
1453
  } else count--;
1474
1454
 
1475
1455
  // console.log(count, decompile([ inst ]).slice(0, -1));
@@ -1546,15 +1526,6 @@ const RTArrayUtil = {
1546
1526
  };
1547
1527
 
1548
1528
  const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1549
- /* const callee = decl.callee;
1550
- const args = decl.arguments;
1551
-
1552
- return [
1553
- ...generate(args),
1554
- ...generate(callee),
1555
- Opcodes.call_indirect,
1556
- ]; */
1557
-
1558
1529
  let name = mapName(decl.callee.name);
1559
1530
  if (isFuncType(decl.callee.type)) { // iife
1560
1531
  const func = generateFunc(scope, decl.callee);
@@ -1627,18 +1598,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1627
1598
  // megahack for /regex/.func()
1628
1599
  const funcName = decl.callee.property.name;
1629
1600
  if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1630
- const func = Rhemyn[funcName](decl.callee.object.regex.pattern, currentFuncIndex++);
1601
+ const regex = decl.callee.object.regex.pattern;
1602
+ const rhemynName = `regex_${funcName}_${regex}`;
1603
+
1604
+ if (!funcIndex[rhemynName]) {
1605
+ const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
1631
1606
 
1632
- funcIndex[func.name] = func.index;
1633
- funcs.push(func);
1607
+ funcIndex[func.name] = func.index;
1608
+ funcs.push(func);
1609
+ }
1634
1610
 
1611
+ const idx = funcIndex[rhemynName];
1635
1612
  return [
1636
1613
  // make string arg
1637
1614
  ...generate(scope, decl.arguments[0]),
1615
+ Opcodes.i32_to_u,
1616
+ ...getNodeType(scope, decl.arguments[0]),
1638
1617
 
1639
1618
  // call regex func
1640
- Opcodes.i32_to_u,
1641
- [ Opcodes.call, func.index ],
1619
+ [ Opcodes.call, idx ],
1642
1620
  Opcodes.i32_from_u,
1643
1621
 
1644
1622
  ...number(TYPES.boolean, Valtype.i32),
@@ -1678,6 +1656,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1678
1656
 
1679
1657
  protoBC[type] = generateCall(scope, {
1680
1658
  callee: {
1659
+ type: 'Identifier',
1681
1660
  name: x
1682
1661
  },
1683
1662
  arguments: [ target, ...decl.arguments ],
@@ -1720,8 +1699,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1720
1699
  continue;
1721
1700
  }
1722
1701
 
1723
- // const protoLocal = protoFunc.local ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp`, protoFunc.local) : -1;
1724
- // const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${TYPE_NAMES[x]}_${protoName}_tmp2`, protoFunc.local2) : -1;
1725
1702
  const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
1726
1703
  const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
1727
1704
 
@@ -1798,22 +1775,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1798
1775
 
1799
1776
  includeBuiltin(scope, name);
1800
1777
  idx = funcIndex[name];
1801
-
1802
- // infer arguments types from builtins params
1803
- const func = funcs.find(x => x.name === name);
1804
- for (let i = 0; i < decl.arguments.length; i++) {
1805
- const arg = decl.arguments[i];
1806
- if (!arg.name) continue;
1807
-
1808
- const local = scope.locals[arg.name];
1809
- if (!local) continue;
1810
-
1811
- local.type = func.params[i];
1812
- if (local.type === Valtype.v128) {
1813
- // specify vec subtype inferred from last vec type in function name
1814
- local.vecType = name.split('_').reverse().find(x => x.includes('x'));
1815
- }
1816
- }
1817
1778
  }
1818
1779
 
1819
1780
  if (idx === undefined && internalConstrs[name]) return internalConstrs[name].generate(scope, decl, _global, _name);
@@ -1826,28 +1787,25 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1826
1787
  if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
1827
1788
  const wasmOps = {
1828
1789
  // pointer, align, offset
1829
- i32_load: { imms: 2, args: 1, returns: 1 },
1790
+ i32_load: { imms: 2, args: [ true ], returns: 1 },
1830
1791
  // pointer, value, align, offset
1831
- i32_store: { imms: 2, args: 2, returns: 0 },
1792
+ i32_store: { imms: 2, args: [ true, true ], returns: 0 },
1832
1793
  // pointer, align, offset
1833
- i32_load8_u: { imms: 2, args: 1, returns: 1 },
1794
+ i32_load8_u: { imms: 2, args: [ true ], returns: 1 },
1834
1795
  // pointer, value, align, offset
1835
- i32_store8: { imms: 2, args: 2, returns: 0 },
1796
+ i32_store8: { imms: 2, args: [ true, true ], returns: 0 },
1836
1797
  // pointer, align, offset
1837
- i32_load16_u: { imms: 2, args: 1, returns: 1 },
1798
+ i32_load16_u: { imms: 2, args: [ true ], returns: 1 },
1838
1799
  // pointer, value, align, offset
1839
- i32_store16: { imms: 2, args: 2, returns: 0 },
1800
+ i32_store16: { imms: 2, args: [ true, true ], returns: 0 },
1840
1801
 
1841
1802
  // pointer, align, offset
1842
- f64_load: { imms: 2, args: 1, returns: 1 },
1803
+ f64_load: { imms: 2, args: [ true ], returns: 0 }, // 0 due to not i32
1843
1804
  // pointer, value, align, offset
1844
- f64_store: { imms: 2, args: 2, returns: 0 },
1805
+ f64_store: { imms: 2, args: [ true, false ], returns: 0 },
1845
1806
 
1846
1807
  // value
1847
- i32_const: { imms: 1, args: 0, returns: 1 },
1848
-
1849
- // a, b
1850
- i32_or: { imms: 0, args: 2, returns: 1 },
1808
+ i32_const: { imms: 1, args: [], returns: 1 },
1851
1809
  };
1852
1810
 
1853
1811
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -1856,13 +1814,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1856
1814
  const op = wasmOps[opName];
1857
1815
 
1858
1816
  const argOut = [];
1859
- for (let i = 0; i < op.args; i++) argOut.push(
1817
+ for (let i = 0; i < op.args.length; i++) argOut.push(
1860
1818
  ...generate(scope, decl.arguments[i]),
1861
- Opcodes.i32_to
1819
+ ...(op.args[i] ? [ Opcodes.i32_to ] : [])
1862
1820
  );
1863
1821
 
1864
1822
  // literals only
1865
- const imms = decl.arguments.slice(op.args).map(x => x.value);
1823
+ const imms = decl.arguments.slice(op.args.length).map(x => x.value);
1866
1824
 
1867
1825
  return [
1868
1826
  ...argOut,
@@ -1937,7 +1895,20 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1937
1895
  const generateNew = (scope, decl, _global, _name) => {
1938
1896
  // hack: basically treat this as a normal call for builtins for now
1939
1897
  const name = mapName(decl.callee.name);
1898
+
1940
1899
  if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
1900
+
1901
+ if (builtinFuncs[name + '$constructor']) {
1902
+ // custom ...$constructor override builtin func
1903
+ return generateCall(scope, {
1904
+ ...decl,
1905
+ callee: {
1906
+ type: 'Identifier',
1907
+ name: name + '$constructor'
1908
+ }
1909
+ }, _global, _name);
1910
+ }
1911
+
1941
1912
  if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
1942
1913
 
1943
1914
  return generateCall(scope, decl, _global, _name);
@@ -2055,7 +2026,7 @@ const brTable = (input, bc, returns) => {
2055
2026
  };
2056
2027
 
2057
2028
  const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2058
- if (!Prefs.bytestring) delete bc[TYPES._bytestring];
2029
+ if (!Prefs.bytestring) delete bc[TYPES.bytestring];
2059
2030
 
2060
2031
  const known = knownType(scope, type);
2061
2032
  if (known != null) {
@@ -2128,8 +2099,7 @@ const addVarMetadata = (scope, name, global = false, metadata = {}) => {
2128
2099
 
2129
2100
  const typeAnnoToPorfType = x => {
2130
2101
  if (!x) return null;
2131
- if (TYPES[x] != null) return TYPES[x];
2132
- if (TYPES['_' + x] != null) return TYPES['_' + x];
2102
+ if (TYPES[x.toLowerCase()] != null) return TYPES[x.toLowerCase()];
2133
2103
 
2134
2104
  switch (x) {
2135
2105
  case 'i32':
@@ -2158,7 +2128,7 @@ const extractTypeAnnotation = decl => {
2158
2128
  const typeName = type;
2159
2129
  type = typeAnnoToPorfType(type);
2160
2130
 
2161
- if (type === TYPES._bytestring && !Prefs.bytestring) type = TYPES.string;
2131
+ if (type === TYPES.bytestring && !Prefs.bytestring) type = TYPES.string;
2162
2132
 
2163
2133
  // if (decl.name) console.log(decl.name, { type, elementType });
2164
2134
 
@@ -2170,8 +2140,8 @@ const generateVar = (scope, decl) => {
2170
2140
 
2171
2141
  const topLevel = scope.name === 'main';
2172
2142
 
2173
- // global variable if in top scope (main) and var ..., or if wanted
2174
- const global = topLevel || decl._bare; // decl.kind === 'var';
2143
+ // global variable if in top scope (main) or if internally wanted
2144
+ const global = topLevel || decl._bare;
2175
2145
 
2176
2146
  for (const x of decl.declarations) {
2177
2147
  const name = mapName(x.id.name);
@@ -2185,7 +2155,6 @@ const generateVar = (scope, decl) => {
2185
2155
  continue;
2186
2156
  }
2187
2157
 
2188
- // console.log(name);
2189
2158
  if (topLevel && builtinVars[name]) {
2190
2159
  // cannot redeclare
2191
2160
  if (decl.kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
@@ -2193,17 +2162,29 @@ const generateVar = (scope, decl) => {
2193
2162
  continue; // always ignore
2194
2163
  }
2195
2164
 
2165
+ // // generate init before allocating var
2166
+ // let generated;
2167
+ // if (x.init) generated = generate(scope, x.init, global, name);
2168
+
2196
2169
  const typed = typedInput && x.id.typeAnnotation;
2197
- let idx = allocVar(scope, name, global, !typed);
2170
+ let idx = allocVar(scope, name, global, !(typed && extractTypeAnnotation(x.id).type != null));
2198
2171
 
2199
2172
  if (typed) {
2200
2173
  addVarMetadata(scope, name, global, extractTypeAnnotation(x.id));
2201
2174
  }
2202
2175
 
2203
2176
  if (x.init) {
2204
- out = out.concat(generate(scope, x.init, global, name));
2205
-
2206
- out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2177
+ const generated = generate(scope, x.init, global, name);
2178
+ if (scope.arrays?.get(name) != null) {
2179
+ // hack to set local as pointer before
2180
+ out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2181
+ if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
2182
+ generated.pop();
2183
+ out = out.concat(generated);
2184
+ } else {
2185
+ out = out.concat(generated);
2186
+ out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2187
+ }
2207
2188
  out.push(...setType(scope, name, getNodeType(scope, x.init)));
2208
2189
  }
2209
2190
 
@@ -2230,6 +2211,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2230
2211
  return [];
2231
2212
  }
2232
2213
 
2214
+ const op = decl.operator.slice(0, -1) || '=';
2215
+
2233
2216
  // hack: .length setter
2234
2217
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2235
2218
  const name = decl.left.object.name;
@@ -2238,14 +2221,20 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2238
2221
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
2239
2222
 
2240
2223
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2224
+ const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2241
2225
 
2242
2226
  return [
2243
2227
  ...(aotPointer ? number(0, Valtype.i32) : [
2244
2228
  ...generate(scope, decl.left.object),
2245
2229
  Opcodes.i32_to_u
2246
2230
  ]),
2231
+ ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2247
2232
 
2248
- ...generate(scope, decl.right),
2233
+ ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2234
+ [ Opcodes.local_get, pointerTmp ],
2235
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
2236
+ Opcodes.i32_from_u
2237
+ ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
2249
2238
  [ Opcodes.local_tee, newValueTmp ],
2250
2239
 
2251
2240
  Opcodes.i32_to_u,
@@ -2255,8 +2244,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2255
2244
  ];
2256
2245
  }
2257
2246
 
2258
- const op = decl.operator.slice(0, -1) || '=';
2259
-
2260
2247
  // arr[i]
2261
2248
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2262
2249
  const name = decl.left.object.name;
@@ -2269,7 +2256,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2269
2256
 
2270
2257
  return [
2271
2258
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2272
- [TYPES._array]: [
2259
+ [TYPES.array]: [
2273
2260
  ...(aotPointer ? [] : [
2274
2261
  ...generate(scope, decl.left.object),
2275
2262
  Opcodes.i32_to_u
@@ -2471,7 +2458,7 @@ const generateUnary = (scope, decl) => {
2471
2458
  [TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
2472
2459
  [TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
2473
2460
 
2474
- [TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2461
+ [TYPES.bytestring]: makeString(scope, 'string', false, '#typeof_result'),
2475
2462
 
2476
2463
  // object and internal types
2477
2464
  default: makeString(scope, 'object', false, '#typeof_result'),
@@ -2707,7 +2694,7 @@ const generateForOf = (scope, decl) => {
2707
2694
  // set type for local
2708
2695
  // todo: optimize away counter and use end pointer
2709
2696
  out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
2710
- [TYPES._array]: [
2697
+ [TYPES.array]: [
2711
2698
  ...setType(scope, leftName, TYPES.number),
2712
2699
 
2713
2700
  [ Opcodes.loop, Blocktype.void ],
@@ -2790,8 +2777,8 @@ const generateForOf = (scope, decl) => {
2790
2777
  [ Opcodes.end ],
2791
2778
  [ Opcodes.end ]
2792
2779
  ],
2793
- [TYPES._bytestring]: [
2794
- ...setType(scope, leftName, TYPES._bytestring),
2780
+ [TYPES.bytestring]: [
2781
+ ...setType(scope, leftName, TYPES.bytestring),
2795
2782
 
2796
2783
  [ Opcodes.loop, Blocktype.void ],
2797
2784
 
@@ -2968,13 +2955,6 @@ const generateEmpty = (scope, decl) => {
2968
2955
  return [];
2969
2956
  };
2970
2957
 
2971
- const generateAssignPat = (scope, decl) => {
2972
- // TODO
2973
- // if identifier declared, use that
2974
- // else, use default (right)
2975
- return todo(scope, 'assignment pattern (optional arg)');
2976
- };
2977
-
2978
2958
  let pages = new Map();
2979
2959
  const allocPage = (scope, reason, type) => {
2980
2960
  if (pages.has(reason)) return pages.get(reason).ind;
@@ -3060,12 +3040,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3060
3040
  // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3061
3041
  const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3062
3042
 
3063
- if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${scope.name} | ${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3043
+ if (Prefs.scopedPageNames) scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType) * pageSize);
3064
3044
  else scope.arrays.set(name, allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType) * pageSize);
3065
3045
  }
3066
3046
 
3067
3047
  const pointer = scope.arrays.get(name);
3068
3048
 
3049
+ const local = global ? globals[name] : scope.locals[name];
3050
+
3069
3051
  const useRawElements = !!decl.rawElements;
3070
3052
  const elements = useRawElements ? decl.rawElements : decl.elements;
3071
3053
 
@@ -3098,11 +3080,22 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3098
3080
  return [ out, pointer ];
3099
3081
  }
3100
3082
 
3083
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3084
+ if (pointerTmp != null) {
3085
+ out.push(
3086
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3087
+ Opcodes.i32_to_u,
3088
+ [ Opcodes.local_set, pointerTmp ]
3089
+ );
3090
+ }
3091
+
3092
+ const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3093
+
3101
3094
  // store length as 0th array
3102
3095
  out.push(
3103
- ...number(0, Valtype.i32),
3096
+ ...pointerWasm,
3104
3097
  ...number(length, Valtype.i32),
3105
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
3098
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3106
3099
  );
3107
3100
 
3108
3101
  const storeOp = StoreOps[itemType];
@@ -3111,14 +3104,14 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3111
3104
  if (elements[i] == null) continue;
3112
3105
 
3113
3106
  out.push(
3114
- ...number(0, Valtype.i32),
3107
+ ...pointerWasm,
3115
3108
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3116
- [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3109
+ [ storeOp, (Math.log2(ValtypeSize[itemType]) || 1) - 1, ...unsignedLEB128(ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
3117
3110
  );
3118
3111
  }
3119
3112
 
3120
3113
  // local value as pointer
3121
- out.push(...number(pointer));
3114
+ out.push(...pointerWasm, Opcodes.i32_from_u);
3122
3115
 
3123
3116
  return [ out, pointer ];
3124
3117
  };
@@ -3160,6 +3153,20 @@ export const generateMember = (scope, decl, _global, _name) => {
3160
3153
 
3161
3154
  const aotPointer = Prefs.aotPointerOpt && pointer != null;
3162
3155
 
3156
+ // hack: .name
3157
+ if (decl.property.name === 'name') {
3158
+ if (hasFuncWithName(name)) {
3159
+ let nameProp = name;
3160
+
3161
+ // eg: __String_prototype_toLowerCase -> toLowerCase
3162
+ if (nameProp.startsWith('__')) nameProp = nameProp.split('_').pop();
3163
+
3164
+ return makeString(scope, nameProp, _global, _name, true);
3165
+ } else {
3166
+ return generate(scope, DEFAULT_VALUE);
3167
+ }
3168
+ }
3169
+
3163
3170
  // hack: .length
3164
3171
  if (decl.property.name === 'length') {
3165
3172
  const func = funcs.find(x => x.name === name);
@@ -3169,6 +3176,16 @@ export const generateMember = (scope, decl, _global, _name) => {
3169
3176
  return number(typedParams ? func.params.length / 2 : func.params.length);
3170
3177
  }
3171
3178
 
3179
+ if (builtinFuncs[name + '$constructor']) {
3180
+ const regularFunc = builtinFuncs[name];
3181
+ const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
3182
+
3183
+ const constructorFunc = builtinFuncs[name + '$constructor'];
3184
+ const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
3185
+
3186
+ return number(Math.max(regularParams, constructorParams));
3187
+ }
3188
+
3172
3189
  if (builtinFuncs[name]) return number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length);
3173
3190
  if (importedFuncs[name]) return number(importedFuncs[name].params);
3174
3191
  if (internalConstrs[name]) return number(internalConstrs[name].length ?? 0);
@@ -3197,7 +3214,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3197
3214
  }
3198
3215
 
3199
3216
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3200
- [TYPES._array]: [
3217
+ [TYPES.array]: [
3201
3218
  // get index as valtype
3202
3219
  ...property,
3203
3220
 
@@ -3250,7 +3267,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3250
3267
  ...number(TYPES.string, Valtype.i32),
3251
3268
  ...setLastType(scope)
3252
3269
  ],
3253
- [TYPES._bytestring]: [
3270
+ [TYPES.bytestring]: [
3254
3271
  // setup new/out array
3255
3272
  ...newOut,
3256
3273
  [ Opcodes.drop ],
@@ -3275,7 +3292,7 @@ export const generateMember = (scope, decl, _global, _name) => {
3275
3292
  // return new string (page)
3276
3293
  ...number(newPointer),
3277
3294
 
3278
- ...number(TYPES._bytestring, Valtype.i32),
3295
+ ...number(TYPES.bytestring, Valtype.i32),
3279
3296
  ...setLastType(scope)
3280
3297
  ],
3281
3298
 
@@ -3300,8 +3317,8 @@ const objectHack = node => {
3300
3317
 
3301
3318
  if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
3302
3319
 
3303
- // if .length, give up (hack within a hack!)
3304
- if (node.property.name === 'length') {
3320
+ // if .name or .length, give up (hack within a hack!)
3321
+ if (['name', 'length'].includes(node.property.name)) {
3305
3322
  node.object = objectHack(node.object);
3306
3323
  return;
3307
3324
  }
@@ -3350,8 +3367,11 @@ const generateFunc = (scope, decl) => {
3350
3367
  };
3351
3368
 
3352
3369
  if (typedInput && decl.returnType) {
3353
- innerScope.returnType = extractTypeAnnotation(decl.returnType).type;
3354
- innerScope.returns = [ valtypeBinary ];
3370
+ const { type } = extractTypeAnnotation(decl.returnType);
3371
+ if (type != null) {
3372
+ innerScope.returnType = type;
3373
+ innerScope.returns = [ valtypeBinary ];
3374
+ }
3355
3375
  }
3356
3376
 
3357
3377
  for (let i = 0; i < params.length; i++) {
@@ -3393,7 +3413,7 @@ const generateFunc = (scope, decl) => {
3393
3413
  if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
3394
3414
  wasm.push(
3395
3415
  ...number(0),
3396
- ...number(TYPES.undefined, Valtype.i32),
3416
+ ...(innerScope.returnType != null ? [] : number(TYPES.undefined, Valtype.i32)),
3397
3417
  [ Opcodes.return ]
3398
3418
  );
3399
3419
  }
@@ -3444,7 +3464,7 @@ const internalConstrs = {
3444
3464
  ...number(pointer)
3445
3465
  ];
3446
3466
  },
3447
- type: TYPES._array,
3467
+ type: TYPES.array,
3448
3468
  length: 1
3449
3469
  },
3450
3470
 
@@ -3456,7 +3476,7 @@ const internalConstrs = {
3456
3476
  elements: decl.arguments
3457
3477
  }, global, name);
3458
3478
  },
3459
- type: TYPES._array,
3479
+ type: TYPES.array,
3460
3480
  notConstr: true,
3461
3481
  length: 0
3462
3482
  },
@@ -3473,6 +3493,8 @@ const internalConstrs = {
3473
3493
  );
3474
3494
  }
3475
3495
 
3496
+ out.push(Opcodes.i32_from_u);
3497
+
3476
3498
  return out;
3477
3499
  },
3478
3500
  type: TYPES.boolean,
@@ -3491,6 +3513,8 @@ const internalConstrs = {
3491
3513
  );
3492
3514
  }
3493
3515
 
3516
+ out.push(Opcodes.i32_from_u);
3517
+
3494
3518
  return out;
3495
3519
  },
3496
3520
  type: TYPES.boolean,
@@ -3545,25 +3569,41 @@ const internalConstrs = {
3545
3569
  type: TYPES.number,
3546
3570
  notConstr: true,
3547
3571
  length: 2
3548
- }
3549
- };
3572
+ },
3573
+
3574
+ __console_log: {
3575
+ generate: (scope, decl) => {
3576
+ const out = [];
3550
3577
 
3551
- // const _ = Array.prototype.push;
3552
- // Array.prototype.push = function (a) {
3553
- // const check = arr => {
3554
- // for (const x of arr) {
3555
- // if (x === undefined) {
3556
- // console.trace(arr);
3557
- // process.exit();
3558
- // }
3559
- // if (Array.isArray(x)) check(x);
3560
- // }
3561
- // };
3562
- // if (Array.isArray(a) && !new Error().stack.includes('node:')) check(a);
3563
- // // if (Array.isArray(a)) check(a);
3578
+ for (let i = 0; i < decl.arguments.length; i++) {
3579
+ out.push(
3580
+ ...generateCall(scope, {
3581
+ callee: {
3582
+ type: 'Identifier',
3583
+ name: '__Porffor_print'
3584
+ },
3585
+ arguments: [ decl.arguments[i] ]
3586
+ }),
3587
+
3588
+ // print space
3589
+ ...number(32),
3590
+ [ Opcodes.call, importedFuncs.printChar ]
3591
+ );
3592
+ }
3593
+
3594
+ // print newline
3595
+ out.push(
3596
+ ...number(10),
3597
+ [ Opcodes.call, importedFuncs.printChar ]
3598
+ );
3564
3599
 
3565
- // return _.apply(this, arguments);
3566
- // };
3600
+ return out;
3601
+ },
3602
+ type: TYPES.undefined,
3603
+ notConstr: true,
3604
+ length: 0
3605
+ }
3606
+ };
3567
3607
 
3568
3608
  export default program => {
3569
3609
  globals = {};
@@ -3579,7 +3619,7 @@ export default program => {
3579
3619
 
3580
3620
  globalThis.valtype = 'f64';
3581
3621
 
3582
- const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
3622
+ const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3583
3623
  if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3584
3624
 
3585
3625
  globalThis.valtypeBinary = Valtype[valtype];
@@ -3587,7 +3627,7 @@ export default program => {
3587
3627
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3588
3628
 
3589
3629
  globalThis.pageSize = PageSize;
3590
- const pageSizeOpt = process.argv.find(x => x.startsWith('-page-size='));
3630
+ const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3591
3631
  if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3592
3632
 
3593
3633
  // set generic opcodes for current valtype