porffor 0.58.19 → 0.59.0

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/AGENT.md CHANGED
@@ -1,13 +1,22 @@
1
- you are an assistant coder for Porffor - a WIP js/ts -> wasm/native ahead-of-time compiler. the codebase is written in js and ts.
1
+ you are an assistant coder for Porffor - an early javascript and typescript to webassembly and native ahead-of-time compiler. the codebase is written in js and ts.
2
2
 
3
3
  IMPORTANT:
4
4
  - built-ins apis (Date, String.prototype, etc) are written in ts inside `compiler/builtins`
5
5
  - once you update a file inside that directory, you MUST run `./porf precompile` to compile to make your changes effective
6
6
 
7
- test your work using the test262 tools available, iterate independently but do not get stuck on one chain of thought or approach. paths for test262 tools should be relative to the 'test262/test' directory (e.g., 'built-ins/RegExp' instead of 'test262/test/built-ins/RegExp').
7
+ Test your work using the test262 tools available, iterate independently but do not get stuck on one chain of thought or approach. Paths for test262 tools should be relative to the 'test262/test' directory (e.g., 'built-ins/RegExp' NOT 'test262/test/built-ins/RegExp').
8
8
 
9
- - always use single quotes instead of double quotes (unless needed)
10
- - after finishing, check if your work/diff could be simplified
11
- - to just evaluate code in the engine, use the command: `./porf -p "..."`
12
- - to get an overview of the most failing directories, use the command: `node test262/fails.cjs`
13
- - when working in `compiler/builtins`, inline code instead of using utility/helper functions
9
+ You can also do the following via bash/shell commands:
10
+ - To get an overview of the most failing directories, use the command: `node test262/fails.cjs`
11
+ - To just evaluate code in the engine, use the command: `./porf -p "..."`
12
+
13
+ ## Code Style
14
+ - After finishing, check if your work/diff could be simplified
15
+ - Always use single quotes (unless double is required)
16
+ - 2-space indentation, LF line endings, no trailing whitespace
17
+ - Built-in APIs in `compiler/builtins/` written in TypeScript
18
+ - Inline code in built-ins, avoid helper functions
19
+ - Use semicolons
20
+ - Do not use trailing commas
21
+ - Use const/let, avoid var
22
+ - Follow existing naming: camelCase for variables, PascalCase for types
@@ -208,20 +208,9 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
208
208
  const bytesPerFunc = funcs.bytesPerFuncLut();
209
209
  for (let i = 0; i < indirectFuncs.length; i++) {
210
210
  const func = indirectFuncs[i].wrapperOf;
211
- let name = func.name;
212
211
 
213
212
  // userland exposed .length
214
- let length = func.jsLength;
215
- if (length == null) {
216
- length = func.params.length;
217
- if (func.constr) length -= 4;
218
- if (func.method) length -= 2;
219
- if (!func.internal || func.typedParams) length = Math.floor(length / 2);
220
-
221
- // remove _this from internal prototype funcs
222
- if (func.internal && name.includes('_prototype_')) length--;
223
- }
224
-
213
+ const length = func.jsLength;
225
214
  bytes.push(length % 256, (length / 256 | 0) % 256);
226
215
 
227
216
  let flags = 0b00000000; // 8 flag bits
@@ -229,8 +218,8 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
229
218
  if (func.constr) flags |= 0b10;
230
219
  bytes.push(flags);
231
220
 
221
+ let name = func.name;
232
222
  if (name.startsWith('#')) name = '';
233
-
234
223
  // eg: __String_prototype_toLowerCase -> toLowerCase
235
224
  if (name.startsWith('__')) name = name.split('_').pop();
236
225
 
@@ -787,11 +787,11 @@ export const __Porffor_regex_interpret = (regexp: RegExp, input: i32, isTest: bo
787
787
  const inputLen: i32 = Porffor.wasm.i32.load(input, 0, 0);
788
788
  let searchStart: i32 = 0;
789
789
  if (global || sticky) {
790
- searchStart = Porffor.wasm.i32.load(regexp, 0, 8);
790
+ searchStart = Porffor.wasm.i32.load16_u(regexp, 0, 8);
791
791
  }
792
792
 
793
793
  if (searchStart > inputLen) {
794
- if (global || sticky) Porffor.wasm.i32.store(regexp, 0, 0, 8);
794
+ if (global || sticky) Porffor.wasm.i32.store16(regexp, 0, 0, 8);
795
795
  return null;
796
796
  }
797
797
 
@@ -919,7 +919,7 @@ export const __Porffor_regex_interpret = (regexp: RegExp, input: i32, isTest: bo
919
919
  backtrack = true;
920
920
  } else {
921
921
  const classId: i32 = Porffor.wasm.i32.load8_u(pc, 0, 1);
922
- const char: i32 = Porffor.wasm.i32.load8_u(input + 4 + sp, 0, 0);
922
+ const char: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
923
923
  let isMatch: boolean = false;
924
924
  if (classId == 1) isMatch = char >= 48 && char <= 57;
925
925
  else if (classId == 2) isMatch = !(char >= 48 && char <= 57);
@@ -948,16 +948,56 @@ export const __Porffor_regex_interpret = (regexp: RegExp, input: i32, isTest: bo
948
948
  backtrack = true;
949
949
  }
950
950
  } else if (op == 0x07) { // word boundary
951
- const prevIsWord = sp > 0 && ((Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 65 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 90) || (Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 97 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 122) || (Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 48 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 57) || Porffor.wasm.i32.load8_u(input + sp, 0, 3) == 95);
952
- const nextIsWord = sp < inputLen && ((Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 65 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 90) || (Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 97 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 122) || (Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 48 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 57) || Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 95);
951
+ let prevIsWord: boolean = false;
952
+ if (sp > 0) {
953
+ const prevChar: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 3);
954
+ prevIsWord = Porffor.fastOr(
955
+ prevChar >= 65 && prevChar <= 90, // A-Z
956
+ prevChar >= 97 && prevChar <= 122, // a-z
957
+ prevChar >= 48 && prevChar <= 57, // 0-9
958
+ prevChar == 95 // _
959
+ );
960
+ }
961
+
962
+ let nextIsWord: boolean = false;
963
+ if (sp < inputLen) {
964
+ const nextChar: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
965
+ nextIsWord = Porffor.fastOr(
966
+ nextChar >= 65 && nextChar <= 90, // A-Z
967
+ nextChar >= 97 && nextChar <= 122, // a-z
968
+ nextChar >= 48 && nextChar <= 57, // 0-9
969
+ nextChar == 95 // _
970
+ );
971
+ }
972
+
953
973
  if (prevIsWord != nextIsWord) {
954
974
  pc += 1;
955
975
  } else {
956
976
  backtrack = true;
957
977
  }
958
978
  } else if (op == 0x08) { // non-word boundary
959
- const prevIsWord = sp > 0 && ((Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 65 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 90) || (Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 97 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 122) || (Porffor.wasm.i32.load8_u(input + sp, 0, 3) >= 48 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) <= 57) || Porffor.wasm.i32.load8_u(input + sp, 0, 3) == 95);
960
- const nextIsWord = sp < inputLen && ((Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 65 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 90) || (Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 97 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 122) || (Porffor.wasm.i32.load8_u(input + sp, 0, 4) >= 48 && Porffor.wasm.i32.load8_u(input + sp, 0, 4) <= 57) || Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 95);
979
+ let prevIsWord: boolean = false;
980
+ if (sp > 0) {
981
+ const prevChar: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 3);
982
+ prevIsWord = Porffor.fastOr(
983
+ prevChar >= 65 && prevChar <= 90, // A-Z
984
+ prevChar >= 97 && prevChar <= 122, // a-z
985
+ prevChar >= 48 && prevChar <= 57, // 0-9
986
+ prevChar == 95 // _
987
+ );
988
+ }
989
+
990
+ let nextIsWord: boolean = false;
991
+ if (sp < inputLen) {
992
+ const nextChar: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
993
+ nextIsWord = Porffor.fastOr(
994
+ nextChar >= 65 && nextChar <= 90, // A-Z
995
+ nextChar >= 97 && nextChar <= 122, // a-z
996
+ nextChar >= 48 && nextChar <= 57, // 0-9
997
+ nextChar == 95 // _
998
+ );
999
+ }
1000
+
961
1001
  if (prevIsWord == nextIsWord) {
962
1002
  pc += 1;
963
1003
  } else {
@@ -353,11 +353,9 @@ export const __Porffor_strcat = (a: any, b: any): any => {
353
353
  };
354
354
 
355
355
 
356
-
357
356
  export const __String_prototype_at = (_this: string, index: number) => {
358
357
  const len: i32 = _this.length;
359
358
 
360
- index |= 0;
361
359
  if (index < 0) index = len + index;
362
360
  if (Porffor.fastOr(index < 0, index >= len)) return undefined;
363
361
 
@@ -375,7 +373,6 @@ export const __String_prototype_at = (_this: string, index: number) => {
375
373
  export const __ByteString_prototype_at = (_this: bytestring, index: number) => {
376
374
  const len: i32 = _this.length;
377
375
 
378
- index |= 0;
379
376
  if (index < 0) index = len + index;
380
377
  if (Porffor.fastOr(index < 0, index >= len)) return undefined;
381
378
 
@@ -393,7 +390,6 @@ export const __ByteString_prototype_at = (_this: bytestring, index: number) => {
393
390
  export const __String_prototype_charAt = (_this: string, index: number) => {
394
391
  const len: i32 = _this.length;
395
392
 
396
- index |= 0;
397
393
  if (Porffor.fastOr(index < 0, index >= len)) return '';
398
394
 
399
395
  let out: string = Porffor.allocateBytes(8);
@@ -410,7 +406,6 @@ export const __String_prototype_charAt = (_this: string, index: number) => {
410
406
  export const __ByteString_prototype_charAt = (_this: bytestring, index: number) => {
411
407
  const len: i32 = _this.length;
412
408
 
413
- index |= 0;
414
409
  if (Porffor.fastOr(index < 0, index >= len)) return '';
415
410
 
416
411
  let out: bytestring = Porffor.allocateBytes(8);
@@ -522,7 +517,6 @@ export const __ByteString_prototype_toLocaleLowerCase = (_this: bytestring) => _
522
517
  export const __String_prototype_codePointAt = (_this: string, index: number) => {
523
518
  const len: i32 = _this.length;
524
519
 
525
- index |= 0;
526
520
  if (Porffor.fastOr(index < 0, index >= len)) return undefined;
527
521
 
528
522
  index *= 2;
@@ -545,7 +539,6 @@ export const __String_prototype_codePointAt = (_this: string, index: number) =>
545
539
  export const __ByteString_prototype_codePointAt = (_this: bytestring, index: number) => {
546
540
  const len: i32 = _this.length;
547
541
 
548
- index |= 0;
549
542
  if (Porffor.fastOr(index < 0, index >= len)) return undefined;
550
543
 
551
544
  // bytestrings cannot have surrogates, so just do charCodeAt
@@ -565,7 +558,6 @@ export const __String_prototype_startsWith = (_this: string, searchString: strin
565
558
  const len: i32 = _this.length;
566
559
  if (position > 0) {
567
560
  if (position > len) position = len;
568
- else position |= 0;
569
561
  } else position = 0;
570
562
 
571
563
  thisPtr += position * 2;
@@ -595,7 +587,6 @@ export const __ByteString_prototype_startsWith = (_this: bytestring, searchStrin
595
587
  const len: i32 = _this.length;
596
588
  if (position > 0) {
597
589
  if (position > len) position = len;
598
- else position |= 0;
599
590
  } else position = 0;
600
591
 
601
592
  thisPtr += position;
@@ -628,7 +619,6 @@ export const __String_prototype_endsWith = (_this: string, searchString: string,
628
619
 
629
620
  if (endPosition > 0) {
630
621
  if (endPosition > len) endPosition = len;
631
- else endPosition |= 0;
632
622
  } else endPosition = 0;
633
623
 
634
624
  endPosition -= searchLen;
@@ -669,7 +659,6 @@ export const __ByteString_prototype_endsWith = (_this: bytestring, searchString:
669
659
 
670
660
  if (endPosition > 0) {
671
661
  if (endPosition > len) endPosition = len;
672
- else endPosition |= 0;
673
662
  } else endPosition = 0;
674
663
 
675
664
  endPosition -= searchLen;
@@ -702,7 +691,6 @@ export const __String_prototype_indexOf = (_this: string, searchString: string,
702
691
  const len: i32 = _this.length;
703
692
  if (position > 0) {
704
693
  if (position > len) position = len;
705
- else position |= 0;
706
694
  } else position = 0;
707
695
 
708
696
  const thisPtrEnd: i32 = thisPtr + (len * 2) - searchLenX2;
@@ -743,7 +731,6 @@ export const __ByteString_prototype_indexOf = (_this: bytestring, searchString:
743
731
  const len: i32 = _this.length;
744
732
  if (position > 0) {
745
733
  if (position > len) position = len;
746
- else position |= 0;
747
734
  } else position = 0;
748
735
 
749
736
  const thisPtrEnd: i32 = thisPtr + len - searchLen;
@@ -789,7 +776,6 @@ export const __String_prototype_lastIndexOf = (_this: string, searchString: stri
789
776
  if (position > 0) {
790
777
  const max: i32 = len - searchLen;
791
778
  if (position > max) position = max;
792
- else position |= 0;
793
779
  } else position = 0;
794
780
 
795
781
  const thisPtrStart: i32 = thisPtr;
@@ -835,7 +821,6 @@ export const __ByteString_prototype_lastIndexOf = (_this: bytestring, searchStri
835
821
  if (position > 0) {
836
822
  const max: i32 = len - searchLen;
837
823
  if (position > max) position = max;
838
- else position |= 0;
839
824
  } else position = 0;
840
825
 
841
826
  const thisPtrStart: i32 = thisPtr;
@@ -875,7 +860,6 @@ export const __String_prototype_includes = (_this: string, searchString: string,
875
860
  const len: i32 = _this.length;
876
861
  if (position > 0) {
877
862
  if (position > len) position = len;
878
- else position |= 0;
879
863
  } else position = 0;
880
864
 
881
865
  const thisPtrEnd: i32 = thisPtr + (len * 2) - searchLenX2;
@@ -916,7 +900,6 @@ export const __ByteString_prototype_includes = (_this: bytestring, searchString:
916
900
  const len: i32 = _this.length;
917
901
  if (position > 0) {
918
902
  if (position > len) position = len;
919
- else position |= 0;
920
903
  } else position = 0;
921
904
 
922
905
  const thisPtrEnd: i32 = thisPtr + len - searchLen;
@@ -952,7 +935,6 @@ export const __String_prototype_padStart = (_this: string, targetLength: number,
952
935
 
953
936
  const len: i32 = _this.length;
954
937
 
955
- targetLength |= 0;
956
938
 
957
939
  const todo: i32 = targetLength - len;
958
940
  if (todo > 0) {
@@ -997,7 +979,6 @@ export const __ByteString_prototype_padStart = (_this: bytestring, targetLength:
997
979
 
998
980
  const len: i32 = _this.length;
999
981
 
1000
- targetLength |= 0;
1001
982
 
1002
983
  const todo: i32 = targetLength - len;
1003
984
  if (todo > 0) {
@@ -1046,7 +1027,6 @@ export const __String_prototype_padEnd = (_this: string, targetLength: number, p
1046
1027
  outPtr += 2;
1047
1028
  }
1048
1029
 
1049
- targetLength |= 0;
1050
1030
 
1051
1031
  const todo: i32 = targetLength - len;
1052
1032
  if (todo > 0) {
@@ -1088,7 +1068,6 @@ export const __ByteString_prototype_padEnd = (_this: bytestring, targetLength: n
1088
1068
  Porffor.wasm.i32.store8(outPtr++, Porffor.wasm.i32.load8_u(thisPtr++, 0, 4), 0, 4);
1089
1069
  }
1090
1070
 
1091
- targetLength |= 0;
1092
1071
 
1093
1072
  const todo: i32 = targetLength - len;
1094
1073
  if (todo > 0) {
@@ -1123,8 +1102,6 @@ export const __String_prototype_substring = (_this: string, start: number, end:
1123
1102
  start = tmp;
1124
1103
  }
1125
1104
 
1126
- start |= 0;
1127
- end |= 0;
1128
1105
 
1129
1106
  if (start < 0) start = 0;
1130
1107
  if (start > len) start = len;
@@ -1161,8 +1138,6 @@ export const __ByteString_prototype_substring = (_this: bytestring, start: numbe
1161
1138
  start = tmp;
1162
1139
  }
1163
1140
 
1164
- start |= 0;
1165
- end |= 0;
1166
1141
 
1167
1142
  if (start < 0) start = 0;
1168
1143
  if (start > len) start = len;
@@ -1191,7 +1166,6 @@ export const __ByteString_prototype_substring = (_this: bytestring, start: numbe
1191
1166
  export const __String_prototype_substr = (_this: string, start: number, length: number) => {
1192
1167
  const len: i32 = _this.length;
1193
1168
 
1194
- start |= 0;
1195
1169
 
1196
1170
  if (start < 0) {
1197
1171
  start = len + start;
@@ -1200,7 +1174,6 @@ export const __String_prototype_substr = (_this: string, start: number, length:
1200
1174
 
1201
1175
  if (Porffor.wasm`local.get ${length+1}` == Porffor.TYPES.undefined) length = len - start;
1202
1176
 
1203
- length |= 0;
1204
1177
 
1205
1178
  if (start + length > len) length = len - start;
1206
1179
 
@@ -1228,7 +1201,6 @@ export const __String_prototype_substr = (_this: string, start: number, length:
1228
1201
  export const __ByteString_prototype_substr = (_this: bytestring, start: number, length: number) => {
1229
1202
  const len: i32 = _this.length;
1230
1203
 
1231
- start |= 0;
1232
1204
 
1233
1205
  if (start < 0) {
1234
1206
  start = len + start;
@@ -1237,7 +1209,6 @@ export const __ByteString_prototype_substr = (_this: bytestring, start: number,
1237
1209
 
1238
1210
  if (Porffor.wasm`local.get ${length+1}` == Porffor.TYPES.undefined) length = len - start;
1239
1211
 
1240
- length |= 0;
1241
1212
 
1242
1213
  if (start + length > len) length = len - start;
1243
1214
 
@@ -1264,8 +1235,6 @@ export const __String_prototype_slice = (_this: string, start: number, end: numb
1264
1235
  const len: i32 = _this.length;
1265
1236
  if (Porffor.wasm`local.get ${end+1}` == Porffor.TYPES.undefined) end = len;
1266
1237
 
1267
- start |= 0;
1268
- end |= 0;
1269
1238
 
1270
1239
  if (start < 0) {
1271
1240
  start = len + start;
@@ -1305,8 +1274,6 @@ export const __ByteString_prototype_slice = (_this: bytestring, start: number, e
1305
1274
  const len: i32 = _this.length;
1306
1275
  if (Porffor.wasm`local.get ${end+1}` == Porffor.TYPES.undefined) end = len;
1307
1276
 
1308
- start |= 0;
1309
- end |= 0;
1310
1277
 
1311
1278
  if (start < 0) {
1312
1279
  start = len + start;
@@ -1644,7 +1611,6 @@ export const __String_prototype_split = (_this: string, separator: any, limit: a
1644
1611
  let out: any[] = Porffor.allocate(), outLen: i32 = 0;
1645
1612
 
1646
1613
  if (Porffor.wasm`local.get ${limit+1}` == Porffor.TYPES.undefined) limit = Number.MAX_SAFE_INTEGER;
1647
- limit |= 0;
1648
1614
  if (limit < 0) limit = Number.MAX_SAFE_INTEGER;
1649
1615
 
1650
1616
  if (separator == null) {
@@ -1822,7 +1788,6 @@ i32.store8 0 12`;
1822
1788
  }
1823
1789
 
1824
1790
  if (Porffor.wasm`local.get ${limit+1}` == Porffor.TYPES.undefined) limit = Number.MAX_SAFE_INTEGER;
1825
- limit |= 0;
1826
1791
  if (limit < 0) limit = Number.MAX_SAFE_INTEGER;
1827
1792
 
1828
1793
  let tmp: bytestring = Porffor.allocate(), tmpLen: i32 = 0;
@@ -105,6 +105,58 @@ export const __String_fromCharCode = (...codes: any[]): bytestring|string => {
105
105
  return out;
106
106
  };
107
107
 
108
+ export const __String_fromCodePoint = (...codePoints: any[]): string => {
109
+ let out: string = Porffor.allocate();
110
+
111
+ const len: i32 = codePoints.length;
112
+ let outLength: i32 = 0;
113
+
114
+ for (let i: i32 = 0; i < len; i++) {
115
+ const codepoint: number = ecma262.ToNumber(codePoints[i]);
116
+
117
+ if (codepoint != (codepoint | 0)) {
118
+ throw new RangeError('Invalid code point');
119
+ }
120
+
121
+ // Check if code point is valid (0 to 0x10FFFF)
122
+ if (Porffor.fastOr(codepoint < 0, codepoint > 0x10FFFF)) {
123
+ throw new RangeError('Invalid code point');
124
+ }
125
+
126
+ if (codepoint <= 0xFFFF) {
127
+ // BMP code point - single 16-bit unit
128
+ outLength++;
129
+ } else {
130
+ // Supplementary code point - surrogate pair (2 units)
131
+ outLength += 2;
132
+ }
133
+ }
134
+
135
+ out.length = outLength;
136
+ let outIndex: i32 = 0;
137
+
138
+ for (let i: i32 = 0; i < len; i++) {
139
+ const codepoint: number = ecma262.ToNumber(codePoints[i]);
140
+
141
+ if (codepoint <= 0xFFFF) {
142
+ // BMP code point
143
+ Porffor.wasm.i32.store16(Porffor.wasm`local.get ${out}` + outIndex * 2, codepoint, 0, 4);
144
+ outIndex++;
145
+ } else {
146
+ // Supplementary code point - encode as surrogate pair
147
+ const cpMinusBase: i32 = codepoint - 0x10000;
148
+ const highSurrogate: i32 = 0xD800 + (cpMinusBase >> 10);
149
+ const lowSurrogate: i32 = 0xDC00 + (cpMinusBase & 0x3FF);
150
+
151
+ Porffor.wasm.i32.store16(Porffor.wasm`local.get ${out}` + outIndex * 2, highSurrogate, 0, 4);
152
+ Porffor.wasm.i32.store16(Porffor.wasm`local.get ${out}` + outIndex * 2, lowSurrogate, 0, 6);
153
+ outIndex += 2;
154
+ }
155
+ }
156
+
157
+ return out;
158
+ };
159
+
108
160
  // in f64 file as returns NaN which returns 0 in i32
109
161
  export const __String_prototype_charCodeAt = (_this: string, index: number) => {
110
162
  const len: i32 = _this.length;
@@ -122,4 +174,49 @@ export const __ByteString_prototype_charCodeAt = (_this: bytestring, index: numb
122
174
  if (Porffor.fastOr(index < 0, index >= len)) return NaN;
123
175
 
124
176
  return Porffor.wasm.i32.load8_u(Porffor.wasm`local.get ${_this}` + index, 0, 4);
177
+ };
178
+
179
+ // 22.1.2.4 String.raw ( template, ...substitutions )
180
+ // https://tc39.es/ecma262/#sec-string.raw
181
+ export const __String_raw = (template: any, ...substitutions: any[]): string => {
182
+ // 1. Let substitutionCount be the number of elements in substitutions.
183
+ const substitutionCount: i32 = substitutions.length;
184
+
185
+ // 2. Let cooked be ? ToObject(template).
186
+ // 3. Let literals be ? ToObject(? Get(cooked, "raw")).
187
+ const literals: any = template.raw;
188
+
189
+ // 4. Let literalCount be ? LengthOfArrayLike(literals).
190
+ const literalCount: number = ecma262.ToIntegerOrInfinity(Porffor.type(literals) == Porffor.TYPES.object ? (literals as object)['length'] : literals.length);
191
+
192
+ // 5. If literalCount ≤ 0, return the empty String.
193
+ if (literalCount <= 0) return '';
194
+
195
+ // 6. Let R be the empty String.
196
+ let R: string = '';
197
+
198
+ // 7. Let nextIndex be 0.
199
+ let nextIndex: i32 = 0;
200
+
201
+ // 8. Repeat,
202
+ while (true) {
203
+ // a. Let nextLiteralVal be ? Get(literals, ! ToString(𝔽(nextIndex))).
204
+ // b. Let nextLiteral be ? ToString(nextLiteralVal).
205
+ // c. Set R to the string-concatenation of R and nextLiteral.
206
+ R = __Porffor_concatStrings(R, literals[nextIndex]);
207
+
208
+ // d. If nextIndex + 1 = literalCount, return R.
209
+ if (nextIndex + 1 == literalCount) return R;
210
+
211
+ // e. If nextIndex < substitutionCount, then
212
+ if (nextIndex < substitutionCount) {
213
+ // i. Let nextSubVal be substitutions[nextIndex].
214
+ // ii. Let nextSub be ? ToString(nextSubVal).
215
+ // iii. Set R to the string-concatenation of R and nextSub.
216
+ R = __Porffor_concatStrings(R, substitutions[nextIndex]);
217
+ }
218
+
219
+ // f. Set nextIndex to nextIndex + 1.
220
+ nextIndex += 1;
221
+ }
125
222
  };
@@ -5,8 +5,11 @@ import { TYPES, TYPE_NAMES } from './types.js';
5
5
  import { number, unsignedLEB128 } from './encoding.js';
6
6
  import './prefs.js';
7
7
 
8
- export const importedFuncs = {};
9
- Object.defineProperty(importedFuncs, 'length', { configurable: true, writable: true, value: 0 });
8
+ export let importedFuncs;
9
+ export const setImports = (v = null) => {
10
+ importedFuncs = v ?? { length: 0 };
11
+ };
12
+ setImports();
10
13
 
11
14
  /**
12
15
  * Create an import function for the Porffor world to use.
@@ -18,51 +21,41 @@ Object.defineProperty(importedFuncs, 'length', { configurable: true, writable: t
18
21
  * @param {string} c - C source code to compile as import implementation
19
22
  */
20
23
  export const createImport = (name, params, returns, js = null, c = null) => {
21
- const lazy = () => {
22
- if (typeof params === 'function') params = params();
23
- if (typeof returns === 'function') returns = returns();
24
- if (typeof params === 'number') params = new Array(params).fill(valtypeBinary);
25
- if (typeof returns === 'number') returns = new Array(returns).fill(valtypeBinary);
26
- };
24
+ if (!globalThis.valtypeBinary) {
25
+ globalThis.valtype ??= Prefs.valtype ?? 'f64';
26
+ globalThis.valtypeBinary = Valtype[valtype];
27
+ }
28
+
29
+ if (typeof params === 'number') params = new Array(params).fill(valtypeBinary);
30
+ if (typeof returns === 'number') returns = new Array(returns).fill(valtypeBinary);
27
31
 
28
32
  if (name in importedFuncs) {
29
33
  // overwrite existing import
30
34
  const existing = importedFuncs[name];
31
- lazy();
32
-
33
- existing.params = params;
34
- existing.returns = returns;
35
- existing.js = js;
36
- existing.c = c;
35
+ const call = +existing;
36
+ const replacement = new Number(call);
37
+ replacement.name = name;
38
+ replacement.import = existing.import;
39
+ replacement.params = params;
40
+ replacement.returns = returns;
41
+ replacement.js = js;
42
+ replacement.c = c;
43
+
44
+ importedFuncs[name] = replacement;
37
45
  return;
38
46
  }
39
47
 
40
48
  const call = importedFuncs.length;
41
49
  const ident = String.fromCharCode(97 + importedFuncs.length);
42
- let obj;
43
- const get = () => {
44
- if (obj) return obj;
45
- lazy();
46
-
47
- obj = new Number(call);
48
- obj.name = name;
49
- obj.import = ident;
50
- obj.params = params;
51
- obj.returns = returns;
52
- obj.js = js;
53
- obj.c = c;
54
- return obj;
55
- };
56
50
 
57
- Object.defineProperty(importedFuncs, name, {
58
- get,
59
- configurable: true,
60
- enumerable: true
61
- });
62
- Object.defineProperty(importedFuncs, call, {
63
- get,
64
- configurable: true
65
- });
51
+ const obj = importedFuncs[name] = importedFuncs[call] = new Number(call);
52
+ obj.name = name;
53
+ obj.import = ident;
54
+ obj.params = params;
55
+ obj.returns = returns;
56
+ obj.js = js;
57
+ obj.c = c;
58
+
66
59
  importedFuncs.length = call + 1;
67
60
  };
68
61