porffor 0.17.0-b103c8894 → 0.17.0-b598eb7bb

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.
package/compiler/2c.js CHANGED
@@ -182,7 +182,15 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
182
182
  }, {});
183
183
  const invGlobals = inv(globals, x => x.idx);
184
184
 
185
- const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => String.fromCharCode(97 + _.charCodeAt(0) % 32));
185
+ const codeToSanitizedStr = code => {
186
+ let out = '';
187
+ while (code > 0) {
188
+ out += String.fromCharCode(97 + code % 26);
189
+ code -= 26;
190
+ }
191
+ return out;
192
+ };
193
+ const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
186
194
 
187
195
  for (const x in invGlobals) {
188
196
  invGlobals[x] = sanitize(invGlobals[x]);
@@ -273,10 +281,11 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
273
281
  }
274
282
 
275
283
  const returns = f.returns.length > 0;
284
+ const typedReturns = f.returnType == null;
276
285
 
277
286
  const shouldInline = false; // f.internal;
278
287
  if (f.name === 'main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
279
- else out += `${f.internal ? (returns ? 'f64' : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
288
+ else out += `${!typedReturns ? (returns ? CValtype[f.returns[0]] : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
280
289
 
281
290
  if (f.name === 'main') {
282
291
  out += ' ' + [...prependMain.values()].join('\n ');
@@ -418,11 +427,14 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
418
427
  continue;
419
428
 
420
429
  case Opcodes.return:
421
- // line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
422
- const b = vals.pop();
423
- const a = vals.pop();
430
+ if (!typedReturns) {
431
+ line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
432
+ break;
433
+ }
434
+
435
+ const b = returns ? vals.pop() : -1;
436
+ const a = returns ? vals.pop() : -1;
424
437
  line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(a)}, ${removeBrackets(b)} }` : ''}`);
425
- // line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(vals.pop())}, ${removeBrackets(vals.pop())} }` : ''}`);
426
438
  break;
427
439
 
428
440
  case Opcodes.if: {
@@ -549,10 +561,15 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
549
561
 
550
562
  prepend.set('__Porffor_readFile',
551
563
  `i32 __Porffor_readFile(u32 pathPtr, u32 outPtr) {
552
- char* path = _memory + pathPtr + 4;
553
- FILE* fp = fopen(path, "r");
554
- if (fp == NULL) {
555
- return -1;
564
+ FILE* fp;
565
+ if (pathPtr == 0) {
566
+ fp = stdin;
567
+ } else {
568
+ char* path = _memory + pathPtr + 4;
569
+ fp = fopen(path, "r");
570
+ if (fp == NULL) {
571
+ return -1;
572
+ }
556
573
  }
557
574
 
558
575
  u32 read = 0;
@@ -585,7 +602,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
585
602
  for (let j = 0; j < func.params.length; j++) args.unshift(removeBrackets(vals.pop()));
586
603
 
587
604
  if (func.returns.length > 0) {
588
- if (func.internal) {
605
+ if (func.returnType != null) {
589
606
  vals.push(`${sanitize(func.name)}(${args.join(', ')})`);
590
607
  } else {
591
608
  const id = retTmpId++;
@@ -253,7 +253,7 @@ export const __Array_prototype_reduceRight = (_this: any[], callbackFn: any, ini
253
253
 
254
254
  let i: i32 = len;
255
255
  while (i > 0) {
256
- acc = callbackFn(acc, _this[i], --i, _this);
256
+ acc = callbackFn(acc, _this[--i], i, _this);
257
257
  }
258
258
 
259
259
  return acc;
@@ -160,6 +160,17 @@ export const BuiltinVars = function() {
160
160
  this.__performance_timeOrigin = [
161
161
  [ Opcodes.call, importedFuncs.timeOrigin ]
162
162
  ];
163
+
164
+
165
+ this.__Uint8Array_BYTES_PER_ELEMENT = number(1);
166
+ this.__Int8Array_BYTES_PER_ELEMENT = number(1);
167
+ this.__Uint8ClampedArray_BYTES_PER_ELEMENT = number(1);
168
+ this.__Uint16Array_BYTES_PER_ELEMENT = number(2);
169
+ this.__Int16Array_BYTES_PER_ELEMENT = number(2);
170
+ this.__Uint32Array_BYTES_PER_ELEMENT = number(4);
171
+ this.__Int32Array_BYTES_PER_ELEMENT = number(4);
172
+ this.__Float32Array_BYTES_PER_ELEMENT = number(4);
173
+ this.__Float64Array_BYTES_PER_ELEMENT = number(8);
163
174
  };
164
175
 
165
176
  export const BuiltinFuncs = function() {
@@ -619,11 +619,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
619
619
  };
620
620
 
621
621
  const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
622
- // if (isIntToFloatOp(wasm[wasm.length - 1])) return [
623
- // ...wasm,
624
- // ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
625
- // ];
626
- // if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
622
+ if (isIntToFloatOp(wasm[wasm.length - 1])) return [
623
+ ...wasm,
624
+ ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
625
+ ];
626
+ if (isIntOp(wasm[wasm.length - 1])) return [
627
+ ...wasm,
628
+ ...(intOut ? [] : [ Opcodes.i32_from ]),
629
+ ];
627
630
 
628
631
  // todo/perf: use knownType and custom bytecode here instead of typeSwitch
629
632
 
@@ -1417,9 +1420,9 @@ const countLeftover = wasm => {
1417
1420
 
1418
1421
  if (depth === 0)
1419
1422
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1420
- 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] < 0x04)) {}
1423
+ 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.f32_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] < 0x04)) {}
1421
1424
  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++;
1422
- else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1425
+ else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1423
1426
  else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1424
1427
  else if (inst[0] === Opcodes.return) count = 0;
1425
1428
  else if (inst[0] === Opcodes.call) {
@@ -1587,9 +1590,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1587
1590
  if (!name && decl.callee.type === 'MemberExpression') {
1588
1591
  // megahack for /regex/.func()
1589
1592
  const funcName = decl.callee.property.name;
1590
- if (decl.callee.object.regex && Object.hasOwn(Rhemyn, funcName)) {
1593
+ if (decl.callee.object.regex && ['test'].includes(funcName)) {
1591
1594
  const regex = decl.callee.object.regex.pattern;
1592
- const rhemynName = `regex_${funcName}_${regex}`;
1595
+ const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
1593
1596
 
1594
1597
  if (!funcIndex[rhemynName]) {
1595
1598
  const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
@@ -1610,7 +1613,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1610
1613
  [ Opcodes.call, idx ],
1611
1614
  Opcodes.i32_from_u,
1612
1615
 
1613
- ...setLastType(scope, TYPES.boolean)
1616
+ ...setLastType(scope, Rhemyn.types[funcName])
1614
1617
  ];
1615
1618
  }
1616
1619
 
@@ -1619,24 +1622,44 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1619
1622
  target = decl.callee.object;
1620
1623
  }
1621
1624
 
1622
- // if (protoName && baseType === TYPES.string && Rhemyn[protoName]) {
1623
- // const func = Rhemyn[protoName](decl.arguments[0].regex.pattern, currentFuncIndex++);
1625
+ if (protoName) {
1626
+ if (['search'].includes(protoName)) {
1627
+ const regex = decl.arguments[0]?.regex?.pattern;
1628
+ if (!regex) return [
1629
+ // no/bad regex arg, return -1/0 for now
1630
+ ...generate(scope, target),
1631
+ [ Opcodes.drop ],
1624
1632
 
1625
- // funcIndex[func.name] = func.index;
1626
- // funcs.push(func);
1633
+ ...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
1634
+ ...setLastType(scope, Rhemyn.types[protoName])
1635
+ ];
1627
1636
 
1628
- // return [
1629
- // generate(scope, decl.callee.object)
1637
+ const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
1630
1638
 
1631
- // // call regex func
1632
- // [ Opcodes.call, func.index ],
1633
- // Opcodes.i32_from_u
1634
- // ];
1635
- // }
1639
+ if (!funcIndex[rhemynName]) {
1640
+ const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
1641
+ func.internal = true;
1636
1642
 
1637
- if (protoName) {
1638
- const protoBC = {};
1643
+ funcIndex[func.name] = func.index;
1644
+ funcs.push(func);
1645
+ }
1646
+
1647
+ const idx = funcIndex[rhemynName];
1648
+ return [
1649
+ // make string arg
1650
+ ...generate(scope, target),
1651
+ Opcodes.i32_to_u,
1652
+ ...getNodeType(scope, target),
1653
+
1654
+ // call regex func
1655
+ [ Opcodes.call, idx ],
1656
+ Opcodes.i32_from,
1639
1657
 
1658
+ ...setLastType(scope, Rhemyn.types[protoName])
1659
+ ];
1660
+ }
1661
+
1662
+ const protoBC = {};
1640
1663
  const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
1641
1664
 
1642
1665
  if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
@@ -2050,6 +2073,16 @@ const DEFAULT_VALUE = {
2050
2073
  name: 'undefined'
2051
2074
  };
2052
2075
 
2076
+ const codeToSanitizedStr = code => {
2077
+ let out = '';
2078
+ while (code > 0) {
2079
+ out += String.fromCharCode(97 + code % 26);
2080
+ code -= 26;
2081
+ }
2082
+ return out;
2083
+ };
2084
+ const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
2085
+
2053
2086
  const unhackName = name => {
2054
2087
  if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
2055
2088
  return name;
@@ -2953,7 +2986,9 @@ const generateForOf = (scope, decl) => {
2953
2986
  // // todo: we should only do this for strings but we don't know at compile-time :(
2954
2987
  // hack: this is naughty and will break things!
2955
2988
  let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2956
- if (pages.hasAnyString) {
2989
+
2990
+ const known = knownType(scope, getNodeType(scope, decl.right));
2991
+ if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
2957
2992
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2958
2993
  0, [ newOut, newPointer ] = makeArray(scope, {
2959
2994
  rawElements: new Array(0)
@@ -3001,6 +3036,7 @@ const generateForOf = (scope, decl) => {
3001
3036
  [ Opcodes.end ],
3002
3037
  [ Opcodes.end ]
3003
3038
  ],
3039
+
3004
3040
  [TYPES.string]: [
3005
3041
  ...setType(scope, leftName, TYPES.string),
3006
3042
 
@@ -3109,6 +3145,7 @@ const generateForOf = (scope, decl) => {
3109
3145
  [ Opcodes.end ],
3110
3146
  [ Opcodes.end ]
3111
3147
  ],
3148
+
3112
3149
  [TYPES.set]: [
3113
3150
  [ Opcodes.loop, Blocktype.void ],
3114
3151
 
@@ -3147,7 +3184,106 @@ const generateForOf = (scope, decl) => {
3147
3184
  [ Opcodes.end ],
3148
3185
  [ Opcodes.end ]
3149
3186
  ],
3150
- // todo: typed arrays
3187
+
3188
+ ...wrapBC({
3189
+ [TYPES.uint8array]: [
3190
+ [ Opcodes.i32_add ],
3191
+
3192
+ [ Opcodes.i32_load8_u, 0, 4 ],
3193
+ Opcodes.i32_from_u
3194
+ ],
3195
+ [TYPES.uint8clampedarray]: [
3196
+ [ Opcodes.i32_add ],
3197
+
3198
+ [ Opcodes.i32_load8_u, 0, 4 ],
3199
+ Opcodes.i32_from_u
3200
+ ],
3201
+ [TYPES.int8array]: [
3202
+ [ Opcodes.i32_add ],
3203
+
3204
+ [ Opcodes.i32_load8_s, 0, 4 ],
3205
+ Opcodes.i32_from
3206
+ ],
3207
+ [TYPES.uint16array]: [
3208
+ ...number(2, Valtype.i32),
3209
+ [ Opcodes.i32_mul ],
3210
+ [ Opcodes.i32_add ],
3211
+
3212
+ [ Opcodes.i32_load16_u, 0, 4 ],
3213
+ Opcodes.i32_from_u
3214
+ ],
3215
+ [TYPES.int16array]: [
3216
+ ...number(2, Valtype.i32),
3217
+ [ Opcodes.i32_mul ],
3218
+ [ Opcodes.i32_add ],
3219
+
3220
+ [ Opcodes.i32_load16_s, 0, 4 ],
3221
+ Opcodes.i32_from
3222
+ ],
3223
+ [TYPES.uint32array]: [
3224
+ ...number(4, Valtype.i32),
3225
+ [ Opcodes.i32_mul ],
3226
+ [ Opcodes.i32_add ],
3227
+
3228
+ [ Opcodes.i32_load, 0, 4 ],
3229
+ Opcodes.i32_from_u
3230
+ ],
3231
+ [TYPES.int32array]: [
3232
+ ...number(4, Valtype.i32),
3233
+ [ Opcodes.i32_mul ],
3234
+ [ Opcodes.i32_add ],
3235
+
3236
+ [ Opcodes.i32_load, 0, 4 ],
3237
+ Opcodes.i32_from
3238
+ ],
3239
+ [TYPES.float32array]: [
3240
+ ...number(4, Valtype.i32),
3241
+ [ Opcodes.i32_mul ],
3242
+ [ Opcodes.i32_add ],
3243
+
3244
+ [ Opcodes.f32_load, 0, 4 ],
3245
+ [ Opcodes.f64_promote_f32 ]
3246
+ ],
3247
+ [TYPES.float64array]: [
3248
+ ...number(8, Valtype.i32),
3249
+ [ Opcodes.i32_mul ],
3250
+ [ Opcodes.i32_add ],
3251
+
3252
+ [ Opcodes.f64_load, 0, 4 ]
3253
+ ],
3254
+ }, {
3255
+ prelude: [
3256
+ ...setType(scope, leftName, TYPES.number),
3257
+
3258
+ [ Opcodes.loop, Blocktype.void ],
3259
+
3260
+ [ Opcodes.local_get, pointer ],
3261
+ [ Opcodes.local_get, counter ]
3262
+ ],
3263
+ postlude: [
3264
+ [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
3265
+
3266
+ [ Opcodes.block, Blocktype.void ],
3267
+ [ Opcodes.block, Blocktype.void ],
3268
+ ...generate(scope, decl.body),
3269
+ [ Opcodes.end ],
3270
+
3271
+ // increment counter by 1
3272
+ [ Opcodes.local_get, counter ],
3273
+ ...number(1, Valtype.i32),
3274
+ [ Opcodes.i32_add ],
3275
+ [ Opcodes.local_tee, counter ],
3276
+
3277
+ // loop if counter != length
3278
+ [ Opcodes.local_get, length ],
3279
+ [ Opcodes.i32_ne ],
3280
+ [ Opcodes.br_if, 1 ],
3281
+
3282
+ [ Opcodes.end ],
3283
+ [ Opcodes.end ]
3284
+ ]
3285
+ }),
3286
+
3151
3287
  default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
3152
3288
  }, Blocktype.void));
3153
3289