porffor 0.58.12 → 0.58.13

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.
@@ -205,6 +205,7 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
205
205
 
206
206
  // generate func lut data
207
207
  const bytes = [];
208
+ const bytesPerFunc = funcs.bytesPerFuncLut();
208
209
  for (let i = 0; i < indirectFuncs.length; i++) {
209
210
  const func = indirectFuncs[i].wrapperOf;
210
211
  let name = func.name;
@@ -233,14 +234,15 @@ export default (funcs, globals, tags, pages, data, noTreeshake = false) => {
233
234
  // eg: __String_prototype_toLowerCase -> toLowerCase
234
235
  if (name.startsWith('__')) name = name.split('_').pop();
235
236
 
236
- bytes.push(...new Uint8Array(new Int32Array([ Math.min(name.length, 48 - 5 - 4) ]).buffer));
237
-
238
- for (let i = 0; i < (48 - 3 - 4); i++) {
237
+ bytes.push(...new Uint8Array(new Int32Array([ Math.min(name.length, bytesPerFunc - 3 - 4) ]).buffer));
238
+ for (let i = 0; i < (bytesPerFunc - 3 - 4); i++) {
239
239
  const c = name.charCodeAt(i);
240
240
  bytes.push((c || 0) % 256);
241
241
  }
242
242
  }
243
243
 
244
+ if (Prefs.debugFuncLut) log('assemble', `func lut using ${bytes.length}/${pageSize * 2} (${bytesPerFunc} bytes per func)`);
245
+
244
246
  data.push({
245
247
  page: 'func lut',
246
248
  bytes
@@ -548,4 +548,9 @@ export const __console_timeEnd = (label: any) => {
548
548
 
549
549
  __console_timeLog(label);
550
550
  timeMap.delete(label);
551
- };
551
+ };
552
+
553
+ export const __Porffor_log = (arg: any) => {
554
+ __Porffor_consolePrint(arg);
555
+ Porffor.printStatic('\n');
556
+ };
@@ -1,9 +1,9 @@
1
1
  // @porf --valtype=i32
2
2
  import type {} from './porffor.d.ts';
3
3
 
4
- // regex memory structure:
5
- // source string ptr (u32)
6
- // flags (u16):
4
+ // regex memory structure (10):
5
+ // 0 @ source string ptr (u32)
6
+ // 4 @ flags (u16):
7
7
  // g, global - 0b00000001
8
8
  // i, ignore case - 0b00000010
9
9
  // m, multiline - 0b00000100
@@ -12,6 +12,8 @@ import type {} from './porffor.d.ts';
12
12
  // y, sticky - 0b00100000
13
13
  // d, has indices - 0b01000000
14
14
  // v, unicode sets - 0b10000000
15
+ // 6 @ capture count (u16)
16
+ // 8 @ last index (u16)
15
17
  // bytecode (variable):
16
18
  // op (u8)
17
19
  // depends on op (variable)
@@ -48,7 +50,14 @@ import type {} from './porffor.d.ts';
48
50
  // end capture - 0x31:
49
51
  // index (u8)
50
52
 
51
- export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: bytestring): RegExp => {
53
+ export const __Porffor_array_fastPushI32 = (arr: any[], el: any): i32 => {
54
+ let len: i32 = arr.length;
55
+ arr[len] = el;
56
+ arr.length = ++len;
57
+ return len;
58
+ };
59
+
60
+ export const __Porffor_regex_compile = (patternStr: bytestring, flagsStr: bytestring): RegExp => {
52
61
  const ptr: i32 = Porffor.allocate();
53
62
  Porffor.wasm.i32.store(ptr, patternStr, 0, 0);
54
63
 
@@ -99,19 +108,21 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
99
108
  }
100
109
  Porffor.wasm.i32.store16(ptr, flags, 0, 4);
101
110
 
102
- let bcPtr: i32 = ptr + 6;
111
+ let bcPtr: i32 = ptr + 10;
103
112
  const bcStart: i32 = bcPtr;
104
113
  let patternPtr: i32 = patternStr;
105
114
  let patternEndPtr: i32 = patternPtr + patternStr.length;
106
115
 
107
- let groupDepth: i32 = 0;
108
- let captureIndex: i32 = 1;
109
116
  let lastWasAtom: boolean = false;
110
117
  let lastAtomStart: i32 = 0;
111
- let groupStack: i32[] = [];
112
- let altStackPos: i32[] = [];
113
- let altStackGroupDepth: i32[] = [];
114
118
  let inClass: boolean = false;
119
+ let captureIndex: i32 = 1;
120
+
121
+ let groupDepth: i32 = 0;
122
+ // todo: free all at the end (or statically allocate but = [] causes memory corruption)
123
+ const groupStack: i32[] = Porffor.allocateBytes(6144);
124
+ const altDepth: i32[] = Porffor.allocateBytes(6144); // number of |s so far at each depth
125
+ const altStack: i32[] = Porffor.allocateBytes(6144);
115
126
 
116
127
  while (patternPtr < patternEndPtr) {
117
128
  let char: i32 = Porffor.wasm.i32.load8_u(patternPtr, 0, 4);
@@ -269,16 +280,18 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
269
280
  }
270
281
  }
271
282
 
283
+ Porffor.array.fastPushI32(groupStack, lastAtomStart);
284
+
272
285
  groupDepth += 1;
273
286
  if (!ncg) {
274
287
  Porffor.wasm.i32.store8(bcPtr, 0x30, 0, 0); // start capture
275
288
  Porffor.wasm.i32.store8(bcPtr, captureIndex, 0, 1);
276
289
  bcPtr += 2;
277
290
 
278
- Porffor.array.fastPush(groupStack, captureIndex);
291
+ Porffor.array.fastPushI32(groupStack, captureIndex);
279
292
  captureIndex += 1;
280
293
  } else {
281
- Porffor.array.fastPush(groupStack, -1);
294
+ Porffor.array.fastPushI32(groupStack, -1);
282
295
  }
283
296
 
284
297
  lastWasAtom = false;
@@ -287,37 +300,46 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
287
300
 
288
301
  if (char == 41) { // ')'
289
302
  if (groupDepth == 0) throw new SyntaxError('Regex parse: unmatched )');
303
+
304
+ let thisAltDepth: i32 = altDepth[groupDepth];
305
+ while (thisAltDepth-- > 0) {
306
+ const jumpPtr: i32 = altStack.pop();
307
+ Porffor.wasm.i32.store16(jumpPtr, bcPtr - jumpPtr, 0, 1);
308
+ }
309
+ altDepth[groupDepth] = 0;
310
+
290
311
  groupDepth -= 1;
291
312
 
292
- const popped: i32 = groupStack.pop()!;
293
- if (popped != -1) {
313
+ const capturePop: i32 = groupStack.pop();
314
+ if (capturePop != -1) {
294
315
  Porffor.wasm.i32.store8(bcPtr, 0x31, 0, 0); // end capture
295
- Porffor.wasm.i32.store8(bcPtr, popped, 0, 1);
316
+ Porffor.wasm.i32.store8(bcPtr, capturePop, 0, 1);
296
317
  bcPtr += 2;
297
318
  }
298
319
 
299
- // Patch alternation jumps for this group
300
- for (let i: i32 = altStackPos.length - 1; i >= 0; --i) {
301
- if (altStackGroupDepth[i] < groupDepth + 1) break;
302
- Porffor.wasm.i32.store16(altStackPos[i], bcPtr - altStackPos[i] - 5, 0, 3); // patch branch2
303
- altStackPos.pop();
304
- altStackGroupDepth.pop();
305
- }
306
-
320
+ const groupStartPtr: i32 = groupStack.pop();
307
321
  lastWasAtom = true;
322
+ lastAtomStart = groupStartPtr;
308
323
  continue;
309
324
  }
310
325
 
311
326
  if (char == 124) { // '|'
312
- // alternation: fork to choose between alternatives
313
- Porffor.array.fastPush(altStackPos, bcPtr);
314
- Porffor.array.fastPush(altStackGroupDepth, groupDepth);
327
+ altDepth[groupDepth] += 1;
315
328
 
316
- Porffor.wasm.i32.store8(bcPtr, 0x21, 0, 0); // fork
317
- Porffor.wasm.i32.store16(bcPtr, 5, 0, 1); // branch1 (next instruction)
318
- Porffor.wasm.i32.store16(bcPtr, 0, 0, 3); // branch2 (to patch later)
329
+ const atomSize: i32 = bcPtr - lastAtomStart;
330
+ Porffor.wasm.memory.copy(lastAtomStart + 5, lastAtomStart, atomSize, 0, 0);
319
331
  bcPtr += 5;
320
332
 
333
+ Porffor.wasm.i32.store8(lastAtomStart, 0x21, 0, 0); // fork
334
+ Porffor.wasm.i32.store16(lastAtomStart, 5, 0, 1); // branch1: after fork
335
+
336
+ Porffor.wasm.i32.store8(bcPtr, 0x20, 0, 0); // jump
337
+ Porffor.array.fastPushI32(altStack, bcPtr); // target: to be written in later
338
+ bcPtr += 3;
339
+
340
+ Porffor.wasm.i32.store16(lastAtomStart, bcPtr - lastAtomStart, 0, 3); // fork branch2: after jump
341
+
342
+ lastAtomStart = bcPtr;
321
343
  lastWasAtom = false;
322
344
  continue;
323
345
  }
@@ -356,7 +378,6 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
356
378
 
357
379
  // Calculate atom size and move it forward to make space for quantifier logic
358
380
  const atomSize: i32 = bcPtr - lastAtomStart;
359
-
360
381
  if (char == 42) { // * (zero or more)
361
382
  // Move atom forward to make space for fork BEFORE it
362
383
  Porffor.wasm.memory.copy(lastAtomStart + 5, lastAtomStart, atomSize, 0, 0);
@@ -481,12 +502,12 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
481
502
  }
482
503
 
483
504
  // emit n times
505
+ const atomSize: i32 = bcPtr - lastAtomStart;
484
506
  for (let i: i32 = 1; i < n; i++) {
485
- let len: i32 = bcPtr - lastAtomStart;
486
- for (let j: i32 = 0; j < len; ++j) {
507
+ for (let j: i32 = 0; j < atomSize; ++j) {
487
508
  Porffor.wasm.i32.store8(bcPtr + j, Porffor.wasm.i32.load8_u(lastAtomStart + j, 0, 0), 0, 0);
488
509
  }
489
- bcPtr += len;
510
+ bcPtr += atomSize;
490
511
  }
491
512
 
492
513
  if (m == n) {
@@ -505,7 +526,6 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
505
526
  } else {
506
527
  // {n,m} - exactly between n and m matches
507
528
  // Create chain of forks, each executing atom inline
508
- const atomSize: i32 = bcPtr - lastAtomStart;
509
529
  for (let i: i32 = n; i < m; i++) {
510
530
  Porffor.wasm.i32.store8(bcPtr, 0x21, 0, 0); // fork
511
531
  if (lazyBrace) {
@@ -664,29 +684,338 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
664
684
  if (groupDepth != 0) throw new SyntaxError('Regex parse: Unmatched (');
665
685
  if (inClass) throw new SyntaxError('Regex parse: Unmatched [');
666
686
 
687
+ let thisAltDepth: i32 = altDepth[groupDepth];
688
+ while (thisAltDepth-- > 0) {
689
+ const jumpPtr: i32 = altStack.pop();
690
+ Porffor.wasm.i32.store16(jumpPtr, bcPtr - jumpPtr, 0, 1);
691
+ }
692
+ altDepth[groupDepth] = 0;
693
+
667
694
  // Accept
668
695
  Porffor.wasm.i32.store8(bcPtr, 0x10, 0, 0);
669
696
 
670
- // Patch any remaining alternation jumps at the end of the pattern
671
- for (let i: i32 = 0; i < altStackPos.length; i++) {
672
- Porffor.wasm.i32.store16(altStackPos[i], bcPtr - altStackPos[i] - 5, 0, 3);
673
- }
697
+ // Store capture count
698
+ Porffor.wasm.i32.store16(ptr, captureIndex - 1, 0, 6);
674
699
 
675
700
  return ptr as RegExp;
676
701
  };
677
702
 
678
703
 
679
- export const RegExp = function (patternStr: any, flagsStr: any = ''): RegExp {
680
- if (Porffor.fastOr(
681
- Porffor.type(patternStr) != Porffor.TYPES.bytestring,
682
- Porffor.type(flagsStr) != Porffor.TYPES.bytestring
683
- )) {
684
- throw new TypeError('Invalid regular expression');
704
+ export const __Porffor_regex_interpret = (regexp: RegExp, input: i32, isTest: boolean): any => {
705
+ const bcBase: i32 = regexp + 10;
706
+ const flags: i32 = Porffor.wasm.i32.load16_u(regexp, 0, 4);
707
+ const totalCaptures: i32 = Porffor.wasm.i32.load16_u(regexp, 0, 6);
708
+
709
+ const ignoreCase: boolean = (flags & 0b00000010) != 0;
710
+ const multiline: boolean = (flags & 0b00000100) != 0;
711
+ const dotAll: boolean = (flags & 0b00001000) != 0;
712
+ const global: boolean = (flags & 0b00000001) != 0;
713
+ const sticky: boolean = (flags & 0b00100000) != 0;
714
+
715
+ const inputLen: i32 = Porffor.wasm.i32.load(input, 0, 0);
716
+ let searchStart: i32 = 0;
717
+ if (global || sticky) {
718
+ searchStart = Porffor.wasm.i32.load(regexp, 0, 8);
685
719
  }
686
720
 
687
- return __Porffor_regex_construct(patternStr, flagsStr);
721
+ if (searchStart > inputLen) {
722
+ if (global || sticky) Porffor.wasm.i32.store(regexp, 0, 0, 8);
723
+ return null;
724
+ }
725
+
726
+ // todo: free all at the end (or statically allocate but = [] causes memory corruption)
727
+ const backtrackStack: i32[] = Porffor.allocate();
728
+ const captures: i32[] = Porffor.allocateBytes(6144);
729
+
730
+ for (let i: i32 = searchStart; i <= inputLen; i++) {
731
+ if (sticky && i != searchStart) {
732
+ if (isTest) return false;
733
+ return null;
734
+ }
735
+
736
+ backtrackStack.length = 0;
737
+ captures.length = 0;
738
+
739
+ let pc: i32 = bcBase;
740
+ let sp: i32 = i;
741
+
742
+ let matched: boolean = false;
743
+ let finalSp: i32 = -1;
744
+
745
+ while (true) {
746
+ const op: i32 = Porffor.wasm.i32.load8_u(pc, 0, 0);
747
+ if (op == 0x10) { // accept
748
+ matched = true;
749
+ finalSp = sp;
750
+ break;
751
+ }
752
+
753
+ let backtrack: boolean = false;
754
+
755
+ if (op == 0x01) { // single
756
+ if (sp >= inputLen) {
757
+ // Porffor.log(`single: oob`);
758
+ backtrack = true;
759
+ } else {
760
+ let c1: i32 = Porffor.wasm.i32.load8_u(pc, 0, 1);
761
+ let c2: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
762
+ if (ignoreCase) {
763
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
764
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
765
+ }
766
+ if (c1 == c2) {
767
+ // Porffor.log(`single: matched ${c1}`);
768
+ pc += 2;
769
+ sp += 1;
770
+ } else {
771
+ // Porffor.log(`single: failed, expected ${c1}, got ${c2}`);
772
+ backtrack = true;
773
+ }
774
+ }
775
+ } else if (op == 0x02 || op == 0x03) { // class or negated class
776
+ if (sp >= inputLen) {
777
+ backtrack = true;
778
+ } else {
779
+ let char: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
780
+ let classPc: i32 = pc + 1;
781
+ let charInClass: boolean = false;
782
+ while (true) {
783
+ const marker: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 0);
784
+ if (marker == 0xFF) break; // end of class
785
+
786
+ if (marker == 0x00) { // range
787
+ let from: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
788
+ let to: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 2);
789
+ let cCheck: i32 = char;
790
+ if (ignoreCase) {
791
+ if (from >= 97 && from <= 122) from -= 32;
792
+ if (to >= 97 && to <= 122) to -= 32;
793
+ if (cCheck >= 97 && cCheck <= 122) cCheck -= 32;
794
+ }
795
+ if (cCheck >= from && cCheck <= to) {
796
+ charInClass = true;
797
+ break;
798
+ }
799
+ classPc += 3;
800
+ } else if (marker == 0x01) { // char
801
+ let c1: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
802
+ let c2: i32 = char;
803
+ if (ignoreCase) {
804
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
805
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
806
+ }
807
+ if (c1 == c2) {
808
+ charInClass = true;
809
+ break;
810
+ }
811
+ classPc += 2;
812
+ } else if (marker == 0x02) { // predefined
813
+ const classId: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
814
+ let isMatch: boolean = false;
815
+ if (classId == 1) isMatch = char >= 48 && char <= 57;
816
+ else if (classId == 2) isMatch = !(char >= 48 && char <= 57);
817
+ else if (classId == 3) isMatch = Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
818
+ else if (classId == 4) isMatch = !Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
819
+ else if (classId == 5) isMatch = (char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95;
820
+ else if (classId == 6) isMatch = !((char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95);
821
+
822
+ if (isMatch) {
823
+ charInClass = true;
824
+ break;
825
+ }
826
+ classPc += 2;
827
+ }
828
+ }
829
+
830
+ if (op == 0x03) charInClass = !charInClass;
831
+
832
+ if (charInClass) {
833
+ while (Porffor.wasm.i32.load8_u(classPc, 0, 0) != 0xFF) {
834
+ const marker: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 0);
835
+ if (marker == 0x00) classPc += 3;
836
+ else if (marker == 0x01) classPc += 2;
837
+ else if (marker == 0x02) classPc += 2;
838
+ }
839
+ pc = classPc + 1;
840
+ sp += 1;
841
+ } else {
842
+ backtrack = true;
843
+ }
844
+ }
845
+ } else if (op == 0x04) { // predefined class
846
+ if (sp >= inputLen) {
847
+ backtrack = true;
848
+ } else {
849
+ const classId: i32 = Porffor.wasm.i32.load8_u(pc, 0, 1);
850
+ const char: i32 = Porffor.wasm.i32.load8_u(input + 4 + sp, 0, 0);
851
+ let isMatch: boolean = false;
852
+ if (classId == 1) isMatch = char >= 48 && char <= 57;
853
+ else if (classId == 2) isMatch = !(char >= 48 && char <= 57);
854
+ else if (classId == 3) isMatch = Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
855
+ else if (classId == 4) isMatch = !Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
856
+ else if (classId == 5) isMatch = (char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95;
857
+ else if (classId == 6) isMatch = !((char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95);
858
+
859
+ if (isMatch) {
860
+ pc += 2;
861
+ sp += 1;
862
+ } else {
863
+ backtrack = true;
864
+ }
865
+ }
866
+ } else if (op == 0x05) { // start
867
+ if (sp == 0 || (multiline && sp > 0 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) == 10)) {
868
+ pc += 1;
869
+ } else {
870
+ backtrack = true;
871
+ }
872
+ } else if (op == 0x06) { // end
873
+ if (sp == inputLen || (multiline && sp < inputLen && Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 10)) {
874
+ pc += 1;
875
+ } else {
876
+ backtrack = true;
877
+ }
878
+ } else if (op == 0x07) { // word boundary
879
+ 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);
880
+ 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);
881
+ if (prevIsWord != nextIsWord) {
882
+ pc += 1;
883
+ } else {
884
+ backtrack = true;
885
+ }
886
+ } else if (op == 0x08) { // non-word boundary
887
+ 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);
888
+ 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);
889
+ if (prevIsWord == nextIsWord) {
890
+ pc += 1;
891
+ } else {
892
+ backtrack = true;
893
+ }
894
+ } else if (op == 0x09) { // dot
895
+ if (sp >= inputLen || (!dotAll && Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 10)) {
896
+ backtrack = true;
897
+ } else {
898
+ pc += 1;
899
+ sp += 1;
900
+ }
901
+ } else if (op == 0x0a) { // back reference
902
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
903
+ const arrIndex = (capIndex - 1) * 2;
904
+ if (arrIndex + 1 >= captures.length) { // reference to group that hasn't been seen
905
+ pc += 2;
906
+ } else {
907
+ const capStart = captures[arrIndex];
908
+ const capEnd = captures[arrIndex + 1];
909
+ if (capStart == -1 || capEnd == -1) { // reference to unmatched group
910
+ pc += 2;
911
+ } else {
912
+ const capLen = capEnd - capStart;
913
+ if (sp + capLen > inputLen) {
914
+ backtrack = true;
915
+ } else {
916
+ let matches = true;
917
+ for (let k = 0; k < capLen; k++) {
918
+ let c1 = Porffor.wasm.i32.load8_u(input + capStart + k, 0, 4);
919
+ let c2 = Porffor.wasm.i32.load8_u(input + sp + k, 0, 4);
920
+ if (ignoreCase) {
921
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
922
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
923
+ }
924
+ if (c1 != c2) {
925
+ matches = false;
926
+ break;
927
+ }
928
+ }
929
+ if (matches) {
930
+ sp += capLen;
931
+ pc += 2;
932
+ } else {
933
+ backtrack = true;
934
+ }
935
+ }
936
+ }
937
+ }
938
+ } else if (op == 0x20) { // jump
939
+ pc += Porffor.wasm.i32.load16_s(pc, 0, 1);
940
+ } else if (op == 0x21) { // fork
941
+ const branch1Offset = Porffor.wasm.i32.load16_s(pc, 0, 1);
942
+ const branch2Offset = Porffor.wasm.i32.load16_s(pc, 0, 3);
943
+
944
+ Porffor.array.fastPushI32(backtrackStack, pc + branch2Offset);
945
+ Porffor.array.fastPushI32(backtrackStack, sp);
946
+ Porffor.array.fastPushI32(backtrackStack, captures.length);
947
+
948
+ pc += branch1Offset;
949
+ } else if (op == 0x30) { // start capture
950
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
951
+ const arrIndex = capIndex + 255; // + 255 offset for temp start, as it could never end properly
952
+ captures[arrIndex] = sp;
953
+ // Porffor.log(`startCapture: captures[${arrIndex}] = ${sp} | captures.length = ${captures.length}`);
954
+ pc += 2;
955
+ } else if (op == 0x31) { // end capture
956
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
957
+ const arrIndex = (capIndex - 1) * 2 + 1;
958
+ while (captures.length <= arrIndex) Porffor.array.fastPushI32(captures, -1);
959
+ captures[arrIndex - 1] = captures[capIndex + 255];
960
+ captures[arrIndex] = sp;
961
+ // Porffor.log(`endCapture: captures[${arrIndex}] = ${sp} | captures.length = ${captures.length}`);
962
+ pc += 2;
963
+ } else { // unknown op
964
+ backtrack = true;
965
+ }
966
+
967
+ if (backtrack) {
968
+ if (backtrackStack.length == 0) break;
969
+ // Porffor.log(`backtrack! before: captures.length = ${captures.length}, sp = ${sp}, pc = ${pc}`);
970
+ captures.length = backtrackStack.pop();
971
+ sp = backtrackStack.pop();
972
+ pc = backtrackStack.pop();
973
+ // Porffor.log(`backtrack! after: captures.length = ${captures.length}, sp = ${sp}, pc = ${pc}`);
974
+ }
975
+ }
976
+
977
+ if (matched) {
978
+ if (isTest) return true;
979
+
980
+ const matchStart: i32 = i;
981
+ if (global || sticky) {
982
+ Porffor.wasm.i32.store(regexp, finalSp, 0, 8);
983
+ }
984
+
985
+ const result: any[] = Porffor.allocateBytes(4096);
986
+ Porffor.array.fastPush(result, __ByteString_prototype_substring(input, matchStart, finalSp));
987
+
988
+ for (let k = 0; k < totalCaptures; k++) {
989
+ const arrIdx = k * 2;
990
+ if (arrIdx + 1 < captures.length) {
991
+ const capStart = captures[arrIdx];
992
+ const capEnd = captures[arrIdx + 1];
993
+ if (capStart != -1 && capEnd != -1) {
994
+ Porffor.array.fastPush(result, __ByteString_prototype_substring(input, capStart, capEnd));
995
+ } else {
996
+ Porffor.array.fastPush(result, undefined);
997
+ }
998
+ } else {
999
+ Porffor.array.fastPush(result, undefined);
1000
+ }
1001
+ }
1002
+
1003
+ result.index = matchStart;
1004
+ result.input = input;
1005
+
1006
+ return result;
1007
+ }
1008
+ }
1009
+
1010
+ if (global || sticky) {
1011
+ Porffor.wasm.i32.store(regexp, 0, 0, 8);
1012
+ }
1013
+
1014
+ if (isTest) return false;
1015
+ return null;
688
1016
  };
689
1017
 
1018
+
690
1019
  export const __RegExp_prototype_source$get = (_this: RegExp) => {
691
1020
  return Porffor.wasm.i32.load(_this, 0, 0) as bytestring;
692
1021
  };
@@ -766,4 +1095,54 @@ export const __RegExp_prototype_unicodeSets$get = (_this: RegExp) => {
766
1095
 
767
1096
  export const __RegExp_prototype_toString = (_this: RegExp) => {
768
1097
  return '/' + _this.source + '/' + _this.flags;
1098
+ };
1099
+
1100
+
1101
+ export const RegExp = function (pattern: any, flags: any = undefined): RegExp {
1102
+ let patternSrc, flagsSrc;
1103
+ if (Porffor.type(pattern) === Porffor.TYPES.regexp) {
1104
+ patternSrc = __RegExp_prototype_source$get(pattern);
1105
+ if (flags === undefined) {
1106
+ flagsSrc = __RegExp_prototype_flags$get(pattern);
1107
+ } else {
1108
+ flagsSrc = flags;
1109
+ }
1110
+ } else {
1111
+ patternSrc = pattern;
1112
+ flagsSrc = flags;
1113
+ }
1114
+
1115
+ if (patternSrc === undefined) patternSrc = '';
1116
+ if (flagsSrc === undefined) flagsSrc = '';
1117
+
1118
+ if (Porffor.type(patternSrc) !== Porffor.TYPES.bytestring || Porffor.type(flagsSrc) !== Porffor.TYPES.bytestring) {
1119
+ throw new TypeError('Invalid regular expression');
1120
+ }
1121
+
1122
+ return __Porffor_regex_compile(patternSrc, flagsSrc);
1123
+ };
1124
+
1125
+
1126
+ export const __RegExp_prototype_exec = (_this: RegExp, input: bytestring) => {
1127
+ return __Porffor_regex_interpret(_this, input, false);
1128
+ };
1129
+
1130
+ export const __RegExp_prototype_test = (_this: RegExp, input: bytestring) => {
1131
+ return __Porffor_regex_interpret(_this, input, true);
1132
+ };
1133
+
1134
+ export const __String_prototype_match = (_this: string, regexp: RegExp) => {
1135
+ if (Porffor.type(regexp) !== Porffor.TYPES.regexp) {
1136
+ regexp = new RegExp(regexp);
1137
+ }
1138
+
1139
+ return regexp.exec(_this);
1140
+ };
1141
+
1142
+ export const __ByteString_prototype_match = (_this: bytestring, regexp: RegExp) => {
1143
+ if (Porffor.type(regexp) !== Porffor.TYPES.regexp) {
1144
+ regexp = new RegExp(regexp);
1145
+ }
1146
+
1147
+ return regexp.exec(_this);
769
1148
  };
@@ -821,11 +821,13 @@ export const BuiltinFuncs = function() {
821
821
  params: [ Valtype.i32 ],
822
822
  returns: [ Valtype.i32 ],
823
823
  returnType: TYPES.number,
824
- wasm: (scope, { allocPage }) => [
824
+ wasm: (scope, { allocLargePage, funcs }) => [
825
825
  [ Opcodes.local_get, 0 ],
826
- number(48, Valtype.i32),
826
+ [ null, () => [
827
+ number(funcs.bytesPerFuncLut(), Valtype.i32)
828
+ ] ],
827
829
  [ Opcodes.i32_mul ],
828
- [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ]
830
+ [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocLargePage(scope, 'func lut')) ]
829
831
  ],
830
832
  table: true
831
833
  };
@@ -834,13 +836,15 @@ export const BuiltinFuncs = function() {
834
836
  params: [ Valtype.i32 ],
835
837
  returns: [ Valtype.i32 ],
836
838
  returnType: TYPES.number,
837
- wasm: (scope, { allocPage }) => [
839
+ wasm: (scope, { allocLargePage, funcs }) => [
838
840
  [ Opcodes.local_get, 0 ],
839
- number(48, Valtype.i32),
841
+ [ null, () => [
842
+ number(funcs.bytesPerFuncLut(), Valtype.i32)
843
+ ] ],
840
844
  [ Opcodes.i32_mul ],
841
845
  number(2, Valtype.i32),
842
846
  [ Opcodes.i32_add ],
843
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')) ]
847
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocLargePage(scope, 'func lut')) ]
844
848
  ],
845
849
  table: true
846
850
  };
@@ -849,13 +853,15 @@ export const BuiltinFuncs = function() {
849
853
  params: [ Valtype.i32 ],
850
854
  returns: [ Valtype.i32 ],
851
855
  returnType: TYPES.bytestring,
852
- wasm: (scope, { allocPage }) => [
856
+ wasm: (scope, { allocLargePage, funcs }) => [
853
857
  [ Opcodes.local_get, 0 ],
854
- number(48, Valtype.i32),
858
+ [ null, () => [
859
+ number(funcs.bytesPerFuncLut(), Valtype.i32)
860
+ ] ],
855
861
  [ Opcodes.i32_mul ],
856
862
  number(3, Valtype.i32),
857
863
  [ Opcodes.i32_add ],
858
- number(allocPage(scope, 'func lut'), Valtype.i32),
864
+ number(allocLargePage(scope, 'func lut'), Valtype.i32),
859
865
  [ Opcodes.i32_add ]
860
866
  ],
861
867
  table: true