porffor 0.41.2 → 0.41.4

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.
@@ -96,10 +96,8 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
96
96
  return cacheAst(decl, generateChain(scope, decl));
97
97
 
98
98
  case 'CallExpression':
99
- return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused));
100
-
101
99
  case 'NewExpression':
102
- return cacheAst(decl, generateNew(scope, decl, global, name));
100
+ return cacheAst(decl, generateCall(scope, decl, global, name, valueUnused));
103
101
 
104
102
  case 'ThisExpression':
105
103
  return cacheAst(decl, generateThis(scope, decl));
@@ -189,6 +187,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
189
187
  case 'TemplateLiteral':
190
188
  return cacheAst(decl, generateTemplate(scope, decl));
191
189
 
190
+ case 'TaggedTemplateExpression':
191
+ return cacheAst(decl, generateTaggedTemplate(scope, decl, global, name));
192
+
192
193
  case 'ExportNamedDeclaration':
193
194
  if (!decl.declaration) return todo(scope, 'unsupported export declaration');
194
195
 
@@ -209,79 +210,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
209
210
 
210
211
  return cacheAst(decl, []);
211
212
 
212
- case 'TaggedTemplateExpression': {
213
- const funcs = {
214
- __Porffor_wasm: str => {
215
- let out = [];
216
-
217
- for (const line of str.split('\n')) {
218
- const asm = line.trim().split(';;')[0].split(' ').filter(x => x);
219
- if (!asm[0]) continue; // blank
220
-
221
- if (asm[0] === 'local') {
222
- const [ name, type ] = asm.slice(1);
223
- scope.locals[name] = { idx: scope.localInd++, type: Valtype[type] };
224
- continue;
225
- }
226
-
227
- if (asm[0] === 'returns') {
228
- scope.returns = asm.slice(1).map(x => Valtype[x]);
229
- continue;
230
- }
231
-
232
- let inst = Opcodes[asm[0].replace('.', '_')];
233
- if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
234
- if (!Array.isArray(inst)) inst = [ inst ];
235
-
236
- const immediates = asm.slice(1).map(x => {
237
- const int = parseInt(x);
238
- if (Number.isNaN(int)) {
239
- if (builtinFuncs[x]) {
240
- if (funcIndex[x] == null) includeBuiltin(scope, x);
241
- return funcIndex[x];
242
- }
243
-
244
- return scope.locals[x]?.idx ?? globals[x].idx;
245
- }
246
- return int;
247
- });
248
-
249
- const encodeFunc = ({
250
- [Opcodes.f64_const]: x => x,
251
- [Opcodes.if]: unsignedLEB128,
252
- [Opcodes.loop]: unsignedLEB128
253
- })[inst[0]] ?? signedLEB128;
254
- out.push([ ...inst, ...immediates.flatMap(x => encodeFunc(x)) ]);
255
- }
256
-
257
- return out;
258
- },
259
-
260
- __Porffor_bs: str => makeString(scope, str, global, name, true),
261
- __Porffor_s: str => makeString(scope, str, global, name, false)
262
- };
263
-
264
- const func = decl.tag.name;
265
- // hack for inline asm
266
- if (!funcs[func]) return cacheAst(decl, todo(scope, 'tagged template expressions not implemented', true));
267
-
268
- const { quasis, expressions } = decl.quasi;
269
- let str = quasis[0].value.raw;
270
-
271
- for (let i = 0; i < expressions.length; i++) {
272
- const e = expressions[i];
273
- if (!e.name) {
274
- if (e.type === 'BinaryExpression' && e.operator === '+' && e.left.type === 'Identifier' && e.right.type === 'Literal') {
275
- str += lookupName(scope, e.left.name)[0].idx + e.right.value;
276
- } else todo(scope, 'unsupported expression in intrinsic');
277
- } else str += lookupName(scope, e.name)[0].idx;
278
-
279
- str += quasis[i + 1].value.raw;
280
- }
281
-
282
- return cacheAst(decl, funcs[func](str));
283
- }
284
-
285
213
  default:
286
214
  // ignore typescript nodes
287
215
  if (decl.type.startsWith('TS') ||
@@ -601,18 +529,21 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
601
529
  [ Opcodes.i32_eqz ], */
602
530
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
603
531
  ] ],
604
- // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
605
- // [ 'default', [
606
- // // other types are always truthy
607
- // ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
608
- // ...number(1, intOut ? Valtype.i32 : valtypeBinary)
609
- // ] ]
532
+
610
533
  ...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
611
534
  // always truthy :))
612
535
  ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
613
536
  ...number(1, intOut ? Valtype.i32 : valtypeBinary)
614
537
  ] ] ] : []),
538
+
615
539
  [ 'default', def ]
540
+
541
+ // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
542
+ // [ 'default', [
543
+ // // other types are always truthy
544
+ // ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
545
+ // ...number(1, intOut ? Valtype.i32 : valtypeBinary)
546
+ // ] ]
616
547
  ], intOut ? Valtype.i32 : valtypeBinary)
617
548
  ];
618
549
  };
@@ -666,18 +597,21 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
666
597
  [ Opcodes.i32_eqz ],
667
598
  ...(intOut ? [] : [ Opcodes.i32_from_u ])
668
599
  ] ],
669
- // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
670
- // [ 'default', [
671
- // // other types are always truthy
672
- // ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
673
- // ...number(0, intOut ? Valtype.i32 : valtypeBinary)
674
- // ] ]
600
+
675
601
  ...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
676
602
  // always truthy :))
677
603
  ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
678
604
  ...number(0, intOut ? Valtype.i32 : valtypeBinary)
679
605
  ] ] ] : []),
606
+
680
607
  [ 'default', def ]
608
+
609
+ // [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
610
+ // [ 'default', [
611
+ // // other types are always truthy
612
+ // ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
613
+ // ...number(0, intOut ? Valtype.i32 : valtypeBinary)
614
+ // ] ]
681
615
  ], intOut ? Valtype.i32 : valtypeBinary)
682
616
  ];
683
617
  };
@@ -749,7 +683,8 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
749
683
  // todo: niche null hell with 0
750
684
 
751
685
  if ((knownLeft === TYPES.string || knownRight === TYPES.string) ||
752
- (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)) {
686
+ (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) ||
687
+ (knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)) {
753
688
  if (op === '+') {
754
689
  // string concat (a + b)
755
690
  return concatStrings(scope, left, right, leftType, rightType);
@@ -887,6 +822,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
887
822
  // switch primitive types to primitive object types
888
823
  if (checkType === TYPES.number) checkType = TYPES.numberobject;
889
824
  if (checkType === TYPES.boolean) checkType = TYPES.booleanobject;
825
+ if (checkType === TYPES.string) checkType = TYPES.stringobject;
890
826
 
891
827
  // currently unsupported types
892
828
  if ([TYPES.string].includes(checkType)) {
@@ -1269,6 +1205,14 @@ const getNodeType = (scope, node) => {
1269
1205
 
1270
1206
  if (node.type === 'CallExpression' || node.type === 'NewExpression') {
1271
1207
  const name = node.callee.name;
1208
+
1209
+ // hack: special primitive object types
1210
+ if (node.type === 'NewExpression') {
1211
+ if (name === 'Number') return TYPES.numberobject;
1212
+ if (name === 'Boolean') return TYPES.booleanobject;
1213
+ if (name === 'String') return TYPES.stringobject;
1214
+ }
1215
+
1272
1216
  if (name == null) {
1273
1217
  // iife
1274
1218
  if (scope.locals['#last_type']) return getLastType(scope);
@@ -1375,11 +1319,14 @@ const getNodeType = (scope, node) => {
1375
1319
 
1376
1320
  if ((knownLeft != null || knownRight != null) && !(
1377
1321
  (knownLeft === TYPES.string || knownRight === TYPES.string) ||
1378
- (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
1322
+ (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) ||
1323
+ (knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)
1379
1324
  )) return TYPES.number;
1380
1325
 
1381
- if (knownLeft === TYPES.string || knownRight === TYPES.string)
1382
- return TYPES.string;
1326
+ if (
1327
+ (knownLeft === TYPES.string || knownRight === TYPES.string) ||
1328
+ (knownLeft === TYPES.stringobject || knownRight === TYPES.stringobject)
1329
+ ) return TYPES.string;
1383
1330
 
1384
1331
  // guess bytestring, could really be bytestring or string
1385
1332
  if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring)
@@ -1727,6 +1674,7 @@ const aliasPrimObjsBC = bc => {
1727
1674
 
1728
1675
  add(TYPES.boolean, TYPES.booleanobject);
1729
1676
  add(TYPES.number, TYPES.numberobject);
1677
+ add(TYPES.string, TYPES.stringobject);
1730
1678
  };
1731
1679
 
1732
1680
  const createThisArg = (scope, decl) => {
@@ -1803,6 +1751,8 @@ const createThisArg = (scope, decl) => {
1803
1751
  };
1804
1752
 
1805
1753
  const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1754
+ if (decl.type === 'NewExpression') decl._new = true;
1755
+
1806
1756
  let out = [];
1807
1757
  let name = decl.callee.name;
1808
1758
 
@@ -2100,6 +2050,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2100
2050
  };
2101
2051
  }
2102
2052
 
2053
+ // alias primitive prototype with primitive object types
2054
+ aliasPrimObjsBC(protoBC);
2055
+
2103
2056
  return [
2104
2057
  ...(usePointerCache ? [
2105
2058
  ...rawPointer,
@@ -2583,11 +2536,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2583
2536
  return out;
2584
2537
  };
2585
2538
 
2586
- const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
2587
- ...decl,
2588
- _new: true
2589
- }, _global, _name);
2590
-
2591
2539
  const generateThis = (scope, decl) => {
2592
2540
  if (!scope.constr) {
2593
2541
  // this in a non-constructor context is a reference to globalThis
@@ -5885,6 +5833,92 @@ export const generateTemplate = (scope, decl) => {
5885
5833
  return generate(scope, current);
5886
5834
  };
5887
5835
 
5836
+ const generateTaggedTemplate = (scope, decl, global = false, name = undefined) => {
5837
+ const intrinsics = {
5838
+ __Porffor_wasm: str => {
5839
+ let out = [];
5840
+
5841
+ for (const line of str.split('\n')) {
5842
+ const asm = line.trim().split(';;')[0].split(' ').filter(x => x);
5843
+ if (!asm[0]) continue; // blank
5844
+
5845
+ if (asm[0] === 'local') {
5846
+ const [ name, type ] = asm.slice(1);
5847
+ scope.locals[name] = { idx: scope.localInd++, type: Valtype[type] };
5848
+ continue;
5849
+ }
5850
+
5851
+ if (asm[0] === 'returns') {
5852
+ scope.returns = asm.slice(1).map(x => Valtype[x]);
5853
+ continue;
5854
+ }
5855
+
5856
+ let inst = Opcodes[asm[0].replace('.', '_')];
5857
+ if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
5858
+ if (!Array.isArray(inst)) inst = [ inst ];
5859
+
5860
+ const immediates = asm.slice(1).map(x => {
5861
+ const int = parseInt(x);
5862
+ if (Number.isNaN(int)) {
5863
+ if (builtinFuncs[x]) {
5864
+ if (funcIndex[x] == null) includeBuiltin(scope, x);
5865
+ return funcIndex[x];
5866
+ }
5867
+
5868
+ return scope.locals[x]?.idx ?? globals[x].idx;
5869
+ }
5870
+ return int;
5871
+ });
5872
+
5873
+ const encodeFunc = ({
5874
+ [Opcodes.f64_const]: x => x,
5875
+ [Opcodes.if]: unsignedLEB128,
5876
+ [Opcodes.loop]: unsignedLEB128
5877
+ })[inst[0]] ?? signedLEB128;
5878
+ out.push([ ...inst, ...immediates.flatMap(x => encodeFunc(x)) ]);
5879
+ }
5880
+
5881
+ return out;
5882
+ },
5883
+
5884
+ __Porffor_bs: str => makeString(scope, str, global, name, true),
5885
+ __Porffor_s: str => makeString(scope, str, global, name, false)
5886
+ };
5887
+
5888
+ const { quasis, expressions } = decl.quasi;
5889
+ if (intrinsics[decl.tag.name]) {
5890
+ let str = quasis[0].value.raw;
5891
+
5892
+ for (let i = 0; i < expressions.length; i++) {
5893
+ const e = expressions[i];
5894
+ if (!e.name) {
5895
+ if (e.type === 'BinaryExpression' && e.operator === '+' && e.left.type === 'Identifier' && e.right.type === 'Literal') {
5896
+ str += lookupName(scope, e.left.name)[0].idx + e.right.value;
5897
+ } else todo(scope, 'unsupported expression in intrinsic');
5898
+ } else str += lookupName(scope, e.name)[0].idx;
5899
+
5900
+ str += quasis[i + 1].value.raw;
5901
+ }
5902
+
5903
+ return cacheAst(decl, intrinsics[decl.tag.name](str));
5904
+ }
5905
+
5906
+ return generate(scope, {
5907
+ type: 'CallExpression',
5908
+ callee: decl.tag,
5909
+ arguments: [
5910
+ { // strings
5911
+ type: 'ArrayExpression',
5912
+ elements: quasis.map(x => ({
5913
+ type: 'Literal',
5914
+ value: x.value.cooked
5915
+ }))
5916
+ },
5917
+ ...expressions
5918
+ ]
5919
+ });
5920
+ };
5921
+
5888
5922
  globalThis._uniqId = 0;
5889
5923
  const uniqId = () => '_' + globalThis._uniqId++;
5890
5924
 
@@ -6195,6 +6229,7 @@ const generateFunc = (scope, decl) => {
6195
6229
  ].includes(typeAnno.type)) {
6196
6230
  let types = [ typeAnno.type ];
6197
6231
  if (typeAnno.type === TYPES.number) types.push(TYPES.numberobject);
6232
+ if (typeAnno.type === TYPES.string) types.push(TYPES.stringobject);
6198
6233
 
6199
6234
  prelude.push(
6200
6235
  ...typeIsNotOneOf([ [ Opcodes.local_get, func.locals[name].idx + 1 ] ], types),
package/compiler/types.js CHANGED
@@ -76,6 +76,7 @@ registerInternalType('Promise');
76
76
 
77
77
  registerInternalType('BooleanObject');
78
78
  registerInternalType('NumberObject');
79
+ registerInternalType('StringObject');
79
80
 
80
81
  registerInternalType('Error');
81
82
  registerInternalType('AggregateError');
package/compiler/wrap.js CHANGED
@@ -159,6 +159,8 @@ ${flags & 0b0001 ? ` get func idx: ${get}
159
159
  return Array.from(read(Uint8Array, memory, value + 4, length)).map(x => String.fromCharCode(x)).join('');
160
160
  }
161
161
 
162
+ case TYPES.stringobject: return new String(porfToJSValue({ memory, funcs, pages }, value, TYPES.string));
163
+
162
164
  case TYPES.array: {
163
165
  let length = read(Uint32Array, memory, value, 1)[0];
164
166
  if (override) length = override;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.41.2+5b89877a2",
4
+ "version": "0.41.4+e41715a96",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
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.41.2+5b89877a2';
3
+ globalThis.version = '0.41.4+e41715a96';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {