porffor 0.55.17 → 0.55.18

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.
@@ -136,7 +136,12 @@ const funcRef = func => {
136
136
  }
137
137
  }
138
138
 
139
- if (func.returns.length === 1) {
139
+ if (func.returns.length === 0) {
140
+ // add to stack if returns nothing
141
+ wasm.push(number(UNDEFINED));
142
+ }
143
+
144
+ if (func.returns.length < 2) {
140
145
  // add built-in returnType if only returns a value
141
146
  wasm.push(number(func.returnType ?? TYPES.number, Valtype.i32));
142
147
  }
@@ -353,6 +358,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
353
358
 
354
359
  return cacheAst(decl, [ number(UNDEFINED) ]);
355
360
 
361
+ case 'TSAsExpression':
362
+ return cacheAst(decl, generate(scope, decl.expression));
363
+
356
364
  default:
357
365
  // ignore typescript nodes
358
366
  if (decl.type.startsWith('TS') ||
@@ -539,12 +547,10 @@ const generateYield = (scope, decl) => {
539
547
  ...getNodeType(scope, arg),
540
548
 
541
549
  [ Opcodes.call, includeBuiltin(scope, scope.async ? '__Porffor_AsyncGenerator_yield' : '__Porffor_Generator_yield').index ],
542
- [ Opcodes.drop ],
543
- [ Opcodes.drop ],
544
550
 
545
551
  // return generator
546
552
  [ Opcodes.local_get, scope.locals['#generator_out'].idx ],
547
- number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32),
553
+ ...(scope.returnType != null ? [] : [ number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32) ]),
548
554
  [ Opcodes.return ],
549
555
 
550
556
  // use undefined as yield expression value
@@ -565,8 +571,9 @@ const generateReturn = (scope, decl) => {
565
571
  ...generate(scope, arg),
566
572
  ...getNodeType(scope, arg),
567
573
 
574
+ // return generator
568
575
  [ Opcodes.call, includeBuiltin(scope, scope.async ? '__Porffor_AsyncGenerator_return' : '__Porffor_Generator_return').index ],
569
- // returns generator
576
+ ...(scope.returnType != null ? [] : [ number(scope.async ? TYPES.__porffor_asyncgenerator : TYPES.__porffor_generator, Valtype.i32) ]),
570
577
  [ Opcodes.return ]
571
578
  ];
572
579
  }
@@ -581,16 +588,18 @@ const generateReturn = (scope, decl) => {
581
588
  number(TYPES.promise, Valtype.i32),
582
589
 
583
590
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_resolve').index ],
584
- [ Opcodes.drop ],
585
- [ Opcodes.drop ],
586
591
 
587
592
  // return promise
588
593
  [ Opcodes.local_get, scope.locals['#async_out_promise'].idx ],
589
- number(TYPES.promise, Valtype.i32),
594
+ ...(scope.returnType != null ? [] : [ number(TYPES.promise, Valtype.i32) ]),
590
595
  [ Opcodes.return ]
591
596
  ];
592
597
  }
593
598
 
599
+ if (scope.returns.length === 0) return [
600
+ [ Opcodes.return ]
601
+ ];
602
+
594
603
  if (
595
604
  scope.constr && // only do this in constructors
596
605
  !globalThis.precompile // skip in precompiled built-ins, we should not require this and handle it ourselves
@@ -650,7 +659,7 @@ const generateReturn = (scope, decl) => {
650
659
  ]),
651
660
 
652
661
  [ Opcodes.local_get, localTmp(scope, '#return') ],
653
- [ Opcodes.local_get, localTmp(scope, '#return#type', Valtype.i32) ],
662
+ ...(scope.returnType != null ? [] : [ [ Opcodes.local_get, localTmp(scope, '#return#type', Valtype.i32) ] ]),
654
663
  [ Opcodes.return ]
655
664
  ];
656
665
  }
@@ -757,8 +766,7 @@ const compareStrings = (scope, left, right, leftType, rightType, noConv = false)
757
766
  Opcodes.i32_to_u,
758
767
  ...rightType,
759
768
 
760
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_strcmp').index ],
761
- [ Opcodes.drop ]
769
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_strcmp').index ]
762
770
  ];
763
771
 
764
772
  return [
@@ -771,7 +779,6 @@ const compareStrings = (scope, left, right, leftType, rightType, noConv = false)
771
779
  ...rightType,
772
780
 
773
781
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_compareStrings').index ],
774
- [ Opcodes.drop ],
775
782
 
776
783
  // convert valtype result to i32 as i32 output expected
777
784
  Opcodes.i32_trunc_sat_f64_u
@@ -1527,6 +1534,11 @@ const getNodeType = (scope, node) => {
1527
1534
  let guess = null;
1528
1535
  const ret = (() => {
1529
1536
  if (node._type) return node._type;
1537
+
1538
+ if (node.type === 'TSAsExpression') {
1539
+ return extractTypeAnnotation(node).type;
1540
+ }
1541
+
1530
1542
  if (node.type === 'Literal') {
1531
1543
  if (node.regex) return TYPES.regexp;
1532
1544
 
@@ -1549,7 +1561,7 @@ const getNodeType = (scope, node) => {
1549
1561
  }
1550
1562
 
1551
1563
  if (node.type === 'CallExpression' || node.type === 'NewExpression') {
1552
- const name = node.callee.name;
1564
+ let name = node.callee.name;
1553
1565
 
1554
1566
  // hack: special primitive object types
1555
1567
  if (node.type === 'NewExpression') {
@@ -1558,8 +1570,13 @@ const getNodeType = (scope, node) => {
1558
1570
  if (name === 'String') return TYPES.stringobject;
1559
1571
  }
1560
1572
 
1573
+ // hack: try reading from member if call
1574
+ if (name == null && node.callee.type === 'MemberExpression' && node.callee.property.name === 'call') {
1575
+ name = node.callee.object.name;
1576
+ }
1577
+
1561
1578
  if (name == null) {
1562
- // iife
1579
+ // unknown name
1563
1580
  return getLastType(scope);
1564
1581
  }
1565
1582
 
@@ -1568,7 +1585,7 @@ const getNodeType = (scope, node) => {
1568
1585
  if (func.returnType != null) return func.returnType;
1569
1586
  }
1570
1587
 
1571
- if (Object.hasOwn(builtinFuncs, name) && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
1588
+ if (Object.hasOwn(builtinFuncs, name) && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
1572
1589
  if (Object.hasOwn(internalConstrs, name) && internalConstrs[name].type != null) return internalConstrs[name].type;
1573
1590
 
1574
1591
  // check if this is a prototype function
@@ -1971,8 +1988,6 @@ const createThisArg = (scope, decl) => {
1971
1988
  number(TYPES.number, Valtype.i32),
1972
1989
 
1973
1990
  [ Opcodes.call, includeBuiltin(scope, '__Porffor_object_expr_initWithFlags').index ],
1974
- [ Opcodes.drop ],
1975
- [ Opcodes.drop ],
1976
1991
 
1977
1992
  [ Opcodes.local_get, tmp ],
1978
1993
  number(TYPES.object, Valtype.i32)
@@ -2083,14 +2098,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2083
2098
  }
2084
2099
 
2085
2100
  if (name === 'Function') {
2086
- const known = knownValue(scope, decl.arguments[0]);
2087
- if (known !== unknownValue) {
2088
- // new Function('with known/literal string')
2089
- const code = String(known);
2101
+ const knowns = decl.arguments.map(x => knownValue(scope, x));
2102
+ if (knowns.every(x => x !== unknownValue)) {
2103
+ // new Function('with known/literal strings')
2104
+ const code = String(knowns[knowns.length - 1]);
2105
+ const args = knowns.slice(0, -1).map(x => String(x));
2090
2106
 
2091
2107
  let parsed;
2092
2108
  try {
2093
- parsed = objectHack(parse(`(function(){${code}})`));
2109
+ parsed = objectHack(parse(`(function(${args.join(',')}){${code}})`));
2094
2110
  } catch (e) {
2095
2111
  if (e.name === 'SyntaxError') {
2096
2112
  // throw syntax errors of evals at runtime instead
@@ -2609,7 +2625,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2609
2625
 
2610
2626
  const userFunc = func && !func.internal;
2611
2627
  const typedParams = userFunc || func?.typedParams;
2612
- const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
2628
+ const typedReturns = func && func.returnType == null;
2613
2629
  let paramCount = countParams(func, name);
2614
2630
 
2615
2631
  let paramOffset = 0;
@@ -2709,17 +2725,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2709
2725
  // );
2710
2726
  } else out.push(...setLastType(scope));
2711
2727
 
2712
- if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
2713
- out.push(Opcodes.i32_from);
2728
+ if (
2729
+ func?.returns?.length === 0 ||
2730
+ (idx === importedFuncs[name] && importedFuncs[importedFuncs[name]]?.returns === 0)
2731
+ ) {
2732
+ out.push(number(UNDEFINED));
2714
2733
  }
2715
2734
 
2716
- if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32 && !globalThis.noi32F64CallConv) {
2717
- out.push(Opcodes.i32_trunc_sat_f64_s);
2735
+ if (func?.returns?.[0] === Valtype.i32 && valtypeBinary !== Valtype.i32) {
2736
+ out.push(Opcodes.i32_from);
2718
2737
  }
2719
2738
 
2720
- if ((builtinFuncs[name] && builtinFuncs[name].returns?.length === 0) ||
2721
- (idx === importedFuncs[name] && importedFuncs[importedFuncs[name]]?.returns === 0)) {
2722
- out.push(number(UNDEFINED));
2739
+ if (func?.returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32 && !globalThis.noi32F64CallConv) {
2740
+ out.push(Opcodes.i32_trunc_sat_f64_s);
2723
2741
  }
2724
2742
 
2725
2743
  return out;
@@ -3143,6 +3161,7 @@ const extractTypeAnnotation = decl => {
3143
3161
  type = a.typeName.name;
3144
3162
  } else if (a.type.endsWith('Keyword')) {
3145
3163
  type = a.type.slice(2, -7).toLowerCase();
3164
+ if (type === 'void') type = 'undefined';
3146
3165
  } else if (a.type === 'TSArrayType') {
3147
3166
  type = 'array';
3148
3167
  elementType = extractTypeAnnotation(a.elementType).type;
@@ -4155,7 +4174,6 @@ const generateUnary = (scope, decl) => {
4155
4174
  ...toPropertyKey(scope, generate(scope, property), getNodeType(scope, property), decl.argument.computed, true),
4156
4175
 
4157
4176
  [ Opcodes.call, includeBuiltin(scope, scope.strict ? '__Porffor_object_deleteStrict' : '__Porffor_object_delete').index ],
4158
- [ Opcodes.drop ],
4159
4177
  Opcodes.i32_from_u
4160
4178
  ];
4161
4179
 
@@ -5616,10 +5634,7 @@ const generateObject = (scope, decl, global = false, name = '$undeclared') => {
5616
5634
  ...(kind !== 'init' ? [ Opcodes.i32_to_u ] : []),
5617
5635
  ...getNodeType(scope, value),
5618
5636
 
5619
- [ Opcodes.call, includeBuiltin(scope, `__Porffor_object_expr_${kind}`).index ],
5620
-
5621
- [ Opcodes.drop ],
5622
- [ Opcodes.drop ]
5637
+ [ Opcodes.call, includeBuiltin(scope, `__Porffor_object_expr_${kind}`).index ]
5623
5638
  );
5624
5639
  }
5625
5640
  }
@@ -6264,10 +6279,7 @@ const generateClass = (scope, decl) => {
6264
6279
  ...(initKind !== 'value' && initKind !== 'method' ? [ Opcodes.i32_to_u ] : []),
6265
6280
  ...getNodeType(outScope, value),
6266
6281
 
6267
- [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_class_${initKind}`).index ],
6268
-
6269
- [ Opcodes.drop ],
6270
- [ Opcodes.drop ]
6282
+ [ Opcodes.call, includeBuiltin(outScope, `__Porffor_object_class_${initKind}`).index ]
6271
6283
  );
6272
6284
  }
6273
6285
 
@@ -6575,9 +6587,10 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6575
6587
  number(0),
6576
6588
  number(TYPES.undefined, Valtype.i32),
6577
6589
  [ Opcodes.call, includeBuiltin(scope, '__Array_from').index ],
6590
+ [ Opcodes.local_set, func.locals[name].idx ],
6578
6591
 
6592
+ number(TYPES.array, Valtype.i32),
6579
6593
  [ Opcodes.local_set, func.locals[name].idx + 1 ],
6580
- [ Opcodes.local_set, func.locals[name].idx ],
6581
6594
  [ Opcodes.end ]
6582
6595
  );
6583
6596
  }
@@ -6664,9 +6677,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6664
6677
  // inject promise job runner func at the end of main if promises are made
6665
6678
  if (Object.hasOwn(funcIndex, 'Promise') || Object.hasOwn(funcIndex, '__Promise_resolve') || Object.hasOwn(funcIndex, '__Promise_reject')) {
6666
6679
  wasm.push(
6667
- [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ],
6668
- [ Opcodes.drop ],
6669
- [ Opcodes.drop ]
6680
+ [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ]
6670
6681
  );
6671
6682
  }
6672
6683
  } else {
@@ -6687,14 +6698,12 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6687
6698
  number(TYPES.array, Valtype.i32),
6688
6699
 
6689
6700
  [ Opcodes.call, includeBuiltin(func, func.async ? '__Porffor_AsyncGenerator' : '__Porffor_Generator').index ],
6690
- [ Opcodes.drop ],
6691
6701
  [ Opcodes.local_set, func.locals['#generator_out'].idx ]
6692
6702
  );
6693
6703
  } else if (func.async) {
6694
6704
  // make promise at the start
6695
6705
  wasm.unshift(
6696
6706
  [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
6697
- [ Opcodes.drop ],
6698
6707
  [ Opcodes.local_set, func.locals['#async_out_promise'].idx ],
6699
6708
 
6700
6709
  // wrap in try for later catch
@@ -6704,18 +6713,15 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6704
6713
  // reject with thrown value if caught error
6705
6714
  wasm.push(
6706
6715
  [ Opcodes.catch, 0 ],
6716
+ [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6717
+ number(TYPES.promise, Valtype.i32),
6707
6718
 
6708
- [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6709
- number(TYPES.promise, Valtype.i32),
6710
-
6711
- [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_reject').index ],
6712
- [ Opcodes.drop ],
6713
- [ Opcodes.drop ],
6719
+ [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_reject').index ],
6714
6720
  [ Opcodes.end ],
6715
6721
 
6716
6722
  // return promise at the end of func
6717
6723
  [ Opcodes.local_get, func.locals['#async_out_promise'].idx ],
6718
- number(TYPES.promise, Valtype.i32),
6724
+ ...(scope.returnType != null ? [] : [ number(TYPES.promise, Valtype.i32) ]),
6719
6725
  [ Opcodes.return ]
6720
6726
  );
6721
6727
 
@@ -6732,10 +6738,9 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6732
6738
 
6733
6739
  if (typedInput && decl.returnType) {
6734
6740
  const { type } = extractTypeAnnotation(decl.returnType);
6735
- if (type != null && !Prefs.indirectCalls) {
6736
- // if (type != null) {
6741
+ if (type != null) {
6737
6742
  func.returnType = type;
6738
- func.returns = [ valtypeBinary ];
6743
+ func.returns = func.returnType === TYPES.undefined && !func.async && !func.generator ? [] : [ valtypeBinary ];
6739
6744
  }
6740
6745
  }
6741
6746
 
@@ -17,11 +17,10 @@ globalThis.precompile = true;
17
17
  globalThis.valtypeOverrides = {
18
18
  returns: {
19
19
  __Porffor_object_get: [ Valtype.f64, Valtype.i32 ],
20
- __Porffor_object_getExplicit: [ Valtype.f64, Valtype.i32 ],
21
20
  __Porffor_object_readValue: [ Valtype.f64, Valtype.i32 ],
22
21
  __Porffor_object_set: [ Valtype.f64, Valtype.i32 ],
23
22
  __Porffor_object_setStrict: [ Valtype.f64, Valtype.i32 ],
24
- __Porffor_object_packAccessor: [ Valtype.f64, Valtype.i32 ]
23
+ __Porffor_object_packAccessor: [ Valtype.f64 ]
25
24
  },
26
25
  params: {
27
26
  __Porffor_object_set: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.f64, Valtype.i32 ],
@@ -209,7 +208,7 @@ const precompile = async () => {
209
208
  }
210
209
 
211
210
  const total = performance.now() - t;
212
- console.log(`\r${' '.repeat(80)}\r\u001b[2m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${fileCount} files/${funcs.length} funcs\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
211
+ console.log(`\r${' '.repeat(80)}\r\u001b[2m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${funcs.length} funcs from ${fileCount} files\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
213
212
 
214
213
  const comptimeFlagChecks = {
215
214
  hasFunc: x => `hasFunc('${x}')`
@@ -258,7 +257,7 @@ ${funcs.map(x => {
258
257
 
259
258
  return `this${name} = {
260
259
  wasm:${rewriteWasm(x.wasm)},
261
- params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)}` : 'typedReturns:1'},
260
+ params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)},` : ''}
262
261
  locals:${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))},localNames:${JSON.stringify(locals.map(x => x[0]))},
263
262
  ${usedTypes.length > 0 ? `usedTypes:${JSON.stringify(usedTypes)},` : ''}
264
263
  ${x.globalInits ? `globalInits:{${Object.keys(x.globalInits).map(y => `${y}:${rewriteWasm(x.globalInits[y])}`).join(',')}},` : ''}${x.data && Object.keys(x.data).length > 0 ? `data:${JSON.stringify(x.data)},` : ''}
package/compiler/wrap.js CHANGED
@@ -335,20 +335,6 @@ ${flags & 0b0001 ? ` get func idx: ${get}
335
335
  return out;
336
336
  }
337
337
 
338
- case TYPES.bigint: {
339
- const negative = read(Uint8Array, memory, value, 1)[0] !== 0;
340
- const len = read(Uint16Array, memory, value + 2, 1)[0];
341
- const digits = read(Uint32Array, memory, value + 4, len);
342
-
343
- console.log(digits);
344
-
345
- let result = 0n;
346
- for (let i = 0; i < digits.length; i++) {
347
- result = result * 0x100000000n + BigInt(digits[i]);
348
- }
349
- return negative ? -result : result;
350
- }
351
-
352
338
  default: return value;
353
339
  }
354
340
  };
@@ -382,8 +368,8 @@ export default (source, module = undefined, customImports = {}, print = str => p
382
368
 
383
369
  const noAnsi = s => s && s.replace(/\u001b\[[0-9]+m/g, '');
384
370
  let longest = 0;
385
- for (let j = 0; j < disassemble.length; j++) {
386
- longest = Math.max(longest, noAnsi(disassemble[j])?.length ?? 0);
371
+ for (let j = 0; j < disasm.length; j++) {
372
+ longest = Math.max(longest, noAnsi(disasm[j])?.length ?? 0);
387
373
  }
388
374
 
389
375
  if (middleIndex != -1) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.55.17",
4
+ "version": "0.55.18",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/r.cjs CHANGED
@@ -1,3 +1,5 @@
1
+ Array.from.call(null, 0);
2
+
1
3
  // let o = { set foo(x) { console.log('set foo', x); }, __proto__: { set bar(x) { console.log('set bar', x); } } };
2
4
 
3
5
  // o.foo = 1;
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.55.17';
3
+ globalThis.version = '0.55.18';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -1,233 +0,0 @@
1
- import type {} from './porffor.d.ts';
2
-
3
- // digits is an array of u32s as digits in base 2^32
4
- export const __Porffor_bigint_fromDigits = (negative: boolean, digits: i32[]): bigint => {
5
- const len: i32 = digits.length;
6
- if (len > 16383) throw new RangeError('Maximum BigInt size exceeded'); // (65536 - 4) / 4
7
-
8
- // const ptr: i32 = Porffor.allocate();
9
- const ptr: i32 = Porffor.wasm`local.get ${digits}`;
10
-
11
- Porffor.wasm.i32.store8(ptr, negative ? 1 : 0, 0, 0);
12
- Porffor.wasm.i32.store16(ptr, len, 0, 2);
13
-
14
- for (let i: i32 = 0; i < len; i++) {
15
- Porffor.wasm.i32.store(ptr + i * 4, digits[i], 0, 4);
16
- }
17
-
18
- const out: bigint = ptr;
19
- return out;
20
- };
21
-
22
- export const __Porffor_bigint_fromNumber = (n: number): bigint => {
23
- if (!Number.isInteger(n) || !Number.isFinite(n)) throw new RangeError('Cannot convert non-integer to BigInt');
24
-
25
- const negative: boolean = n < 0;
26
- n = Math.abs(n);
27
-
28
- const digits: i32[] = Porffor.allocate();
29
- while (n > 0) {
30
- digits.unshift(n % 0x100000000);
31
- n = Math.trunc(n / 0x100000000);
32
- }
33
-
34
- return __Porffor_bigint_fromDigits(negative, digits);
35
- };
36
-
37
- export const __Porffor_bigint_toNumber = (ptr: i32): number => {
38
- const negative: boolean = Porffor.wasm.i32.load8_u(ptr, 0, 0) != 0;
39
- const len: i32 = Porffor.wasm.i32.load16_u(ptr, 0, 2);
40
-
41
- let out: number = 0;
42
- for (let i: i32 = 0; i < len; i++) {
43
- const d: i32 = Porffor.wasm.i32.load(ptr + i * 4, 0, 4);
44
- out = out * 0x100000000 + d;
45
- }
46
-
47
- if (negative) out = -out;
48
- return out;
49
- };
50
-
51
- export const __Porffor_bigint_fromString = (n: string|bytestring): bigint => {
52
- const len: i32 = n.length;
53
-
54
- let negative: boolean = false;
55
- let end: i32 = 0;
56
- if (n[0] === '-') {
57
- negative = true;
58
- end = 1;
59
- } else if (n[0] === '+') {
60
- end = 1;
61
- }
62
-
63
- // n -> digits (base 2^32) (most to least significant)
64
- // 4294967294 -> [ 4294967294 ]
65
- // 4294967295 -> [ 4294967295 ]
66
- // 4294967296 -> [ 1, 0 ]
67
- // 4294967297 -> [ 1, 1 ]
68
- // 4294967298 -> [ 1, 2 ]
69
- // 9007199254740992 -> [ 2097152 ]
70
- // 9007199254740993 -> [ 2097152, 1 ]
71
- // 9007199254740994 -> [ 2097152, 2 ]
72
- // 9007199254740995 -> [ 2097152, 3 ]
73
-
74
- const digits: i32[] = Porffor.allocate();
75
-
76
- const base = 0x100000000; // 2^32
77
-
78
- for (let i: i32 = end; i < len; i++) {
79
- const char: i32 = n.charCodeAt(i);
80
- const digit: i32 = char - 48;
81
- if (digit < 0 || digit > 9) throw new SyntaxError('Invalid characters in BigInt string');
82
-
83
- // Multiply current digits by 10 and add the new digit
84
- let carry: i32 = digit;
85
- for (let j: i32 = 0; j < digits.length; j++) {
86
- const value: i32 = digits[j] * 10 + carry;
87
- digits[j] = value % base;
88
- carry = Math.trunc(value / base);
89
- }
90
-
91
- // If there's a carry left, push it as a new digit
92
- if (carry > 0) {
93
- digits.push(carry);
94
- }
95
- }
96
-
97
- return __Porffor_bigint_fromDigits(negative, digits);
98
- };
99
-
100
- export const __Porffor_bigint_toString = (ptr: i32, radix: number): string => {
101
- // todo
102
- // return '';
103
- };
104
-
105
- export const __Porffor_bigint_add = (a: i32, b: i32, sub: boolean): bigint => {
106
- const aNegative: boolean = Porffor.wasm.i32.load8_u(a, 0, 0) != 0;
107
- const aLen: i32 = Porffor.wasm.i32.load16_u(a, 0, 2);
108
-
109
- let bNegative: boolean = Porffor.wasm.i32.load8_u(b, 0, 0) != 0;
110
- if (sub) bNegative = !bNegative;
111
- const bLen: i32 = Porffor.wasm.i32.load16_u(b, 0, 2);
112
-
113
- const maxLen: i32 = Math.max(aLen, bLen);
114
- const digits: i32[] = Porffor.allocate();
115
-
116
- // fast path: same sign
117
- let negative: boolean = false;
118
- let carry: i32 = 0;
119
- if (aNegative == bNegative) {
120
- negative = aNegative;
121
-
122
- for (let i: i32 = 0; i < maxLen; i++) {
123
- let aDigit: i32 = 0;
124
- const aOffset: i32 = aLen - i;
125
- if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
126
-
127
- let bDigit: i32 = 0;
128
- const bOffset: i32 = bLen - i;
129
- if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
130
-
131
- let sum: i32 = aDigit + bDigit + carry;
132
- if (sum >= 0x100000000) {
133
- sum -= 0x100000000;
134
- carry = 1;
135
- } else if (sum < 0) {
136
- sum += 0x100000000;
137
- carry = 1;
138
- } else {
139
- carry = 0;
140
- }
141
-
142
- digits.unshift(sum);
143
- }
144
- } else {
145
- let aLarger: i32 = 0;
146
- for (let i: i32 = 0; i < maxLen; i++) {
147
- let aDigit: i32 = 0;
148
- const aOffset: i32 = aLen - i;
149
- if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
150
-
151
- let bDigit: i32 = 0;
152
- const bOffset: i32 = bLen - i;
153
- if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
154
-
155
- let sum: i32 = carry;
156
- if (aNegative) sum -= aDigit;
157
- else sum += aDigit;
158
- if (bNegative) sum -= bDigit;
159
- else sum += bDigit;
160
-
161
- if (aDigit != bDigit) aLarger = aDigit > bDigit ? 1 : -1;
162
-
163
- if (sum >= 0x100000000) {
164
- sum -= 0x100000000;
165
- carry = 1;
166
- } else if (sum < 0) {
167
- sum += 0x100000000;
168
- carry = -1;
169
- } else {
170
- carry = 0;
171
- }
172
-
173
- digits.unshift(sum);
174
- }
175
-
176
- if (aLarger == 1) negative = aNegative;
177
- else if (aLarger == -1) negative = bNegative;
178
- }
179
-
180
- if (carry != 0) {
181
- digits.unshift(Math.abs(carry));
182
- if (carry < 0) negative = !negative;
183
- }
184
-
185
- return __Porffor_bigint_fromDigits(negative, digits);
186
- };
187
-
188
- export const __Porffor_bigint_sub = (a: i32, b: i32): bigint => {
189
- return __Porffor_bigint_add(a, b, true);
190
- };
191
-
192
- export const __Porffor_bigint_mul = (a: i32, b: i32): bigint => {
193
- // todo
194
- // return 0n;
195
- };
196
-
197
- export const __Porffor_bigint_div = (a: i32, b: i32): bigint => {
198
- // todo
199
- // return 0n;
200
- };
201
-
202
- export const __Porffor_bigint_rem = (a: i32, b: i32): bigint => {
203
- // todo
204
- // return 0n;
205
- };
206
-
207
- export const __Porffor_bigint_eq = (a: i32, b: i32): boolean => {
208
- // todo
209
- // return false;
210
- };
211
-
212
- export const __Porffor_bigint_ne = (a: i32, b: i32): boolean => {
213
- return !__Porffor_bigint_eq(a, b);
214
- };
215
-
216
- export const __Porffor_bigint_gt = (a: i32, b: i32): boolean => {
217
- // todo
218
- // return false;
219
- };
220
-
221
- export const __Porffor_bigint_ge = (a: i32, b: i32): boolean => {
222
- // todo
223
- // return false;
224
- };
225
-
226
- export const __Porffor_bigint_lt = (a: i32, b: i32): boolean => {
227
- return !__Porffor_bigint_ge(a, b);
228
- };
229
-
230
- export const __Porffor_bigint_le = (a: i32, b: i32): boolean => {
231
- return !__Porffor_bigint_gt(a, b);
232
- };
233
-