porffor 0.58.12 → 0.58.14

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);
@@ -411,6 +432,8 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
411
432
  }
412
433
 
413
434
  if (char == 123) { // {n,m}
435
+ if (!lastWasAtom) throw new SyntaxError('Regex parser: quantifier without atom');
436
+
414
437
  // parse n
415
438
  let n: i32 = 0;
416
439
  let m: i32 = -1;
@@ -481,12 +504,12 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
481
504
  }
482
505
 
483
506
  // emit n times
507
+ const atomSize: i32 = bcPtr - lastAtomStart;
484
508
  for (let i: i32 = 1; i < n; i++) {
485
- let len: i32 = bcPtr - lastAtomStart;
486
- for (let j: i32 = 0; j < len; ++j) {
509
+ for (let j: i32 = 0; j < atomSize; ++j) {
487
510
  Porffor.wasm.i32.store8(bcPtr + j, Porffor.wasm.i32.load8_u(lastAtomStart + j, 0, 0), 0, 0);
488
511
  }
489
- bcPtr += len;
512
+ bcPtr += atomSize;
490
513
  }
491
514
 
492
515
  if (m == n) {
@@ -505,7 +528,6 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
505
528
  } else {
506
529
  // {n,m} - exactly between n and m matches
507
530
  // Create chain of forks, each executing atom inline
508
- const atomSize: i32 = bcPtr - lastAtomStart;
509
531
  for (let i: i32 = n; i < m; i++) {
510
532
  Porffor.wasm.i32.store8(bcPtr, 0x21, 0, 0); // fork
511
533
  if (lazyBrace) {
@@ -525,6 +547,7 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
525
547
  }
526
548
  }
527
549
 
550
+ lastWasAtom = false;
528
551
  continue;
529
552
  }
530
553
  } else {
@@ -664,29 +687,338 @@ export const __Porffor_regex_construct = (patternStr: bytestring, flagsStr: byte
664
687
  if (groupDepth != 0) throw new SyntaxError('Regex parse: Unmatched (');
665
688
  if (inClass) throw new SyntaxError('Regex parse: Unmatched [');
666
689
 
690
+ let thisAltDepth: i32 = altDepth[groupDepth];
691
+ while (thisAltDepth-- > 0) {
692
+ const jumpPtr: i32 = altStack.pop();
693
+ Porffor.wasm.i32.store16(jumpPtr, bcPtr - jumpPtr, 0, 1);
694
+ }
695
+ altDepth[groupDepth] = 0;
696
+
667
697
  // Accept
668
698
  Porffor.wasm.i32.store8(bcPtr, 0x10, 0, 0);
669
699
 
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
- }
700
+ // Store capture count
701
+ Porffor.wasm.i32.store16(ptr, captureIndex - 1, 0, 6);
674
702
 
675
703
  return ptr as RegExp;
676
704
  };
677
705
 
678
706
 
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');
707
+ export const __Porffor_regex_interpret = (regexp: RegExp, input: i32, isTest: boolean): any => {
708
+ const bcBase: i32 = regexp + 10;
709
+ const flags: i32 = Porffor.wasm.i32.load16_u(regexp, 0, 4);
710
+ const totalCaptures: i32 = Porffor.wasm.i32.load16_u(regexp, 0, 6);
711
+
712
+ const ignoreCase: boolean = (flags & 0b00000010) != 0;
713
+ const multiline: boolean = (flags & 0b00000100) != 0;
714
+ const dotAll: boolean = (flags & 0b00001000) != 0;
715
+ const global: boolean = (flags & 0b00000001) != 0;
716
+ const sticky: boolean = (flags & 0b00100000) != 0;
717
+
718
+ const inputLen: i32 = Porffor.wasm.i32.load(input, 0, 0);
719
+ let searchStart: i32 = 0;
720
+ if (global || sticky) {
721
+ searchStart = Porffor.wasm.i32.load(regexp, 0, 8);
722
+ }
723
+
724
+ if (searchStart > inputLen) {
725
+ if (global || sticky) Porffor.wasm.i32.store(regexp, 0, 0, 8);
726
+ return null;
727
+ }
728
+
729
+ // todo: free all at the end (or statically allocate but = [] causes memory corruption)
730
+ const backtrackStack: i32[] = Porffor.allocate();
731
+ const captures: i32[] = Porffor.allocateBytes(6144);
732
+
733
+ for (let i: i32 = searchStart; i <= inputLen; i++) {
734
+ if (sticky && i != searchStart) {
735
+ if (isTest) return false;
736
+ return null;
737
+ }
738
+
739
+ backtrackStack.length = 0;
740
+ captures.length = 0;
741
+
742
+ let pc: i32 = bcBase;
743
+ let sp: i32 = i;
744
+
745
+ let matched: boolean = false;
746
+ let finalSp: i32 = -1;
747
+
748
+ while (true) {
749
+ const op: i32 = Porffor.wasm.i32.load8_u(pc, 0, 0);
750
+ if (op == 0x10) { // accept
751
+ matched = true;
752
+ finalSp = sp;
753
+ break;
754
+ }
755
+
756
+ let backtrack: boolean = false;
757
+
758
+ if (op == 0x01) { // single
759
+ if (sp >= inputLen) {
760
+ // Porffor.log(`single: oob`);
761
+ backtrack = true;
762
+ } else {
763
+ let c1: i32 = Porffor.wasm.i32.load8_u(pc, 0, 1);
764
+ let c2: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
765
+ if (ignoreCase) {
766
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
767
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
768
+ }
769
+ if (c1 == c2) {
770
+ // Porffor.log(`single: matched ${c1}`);
771
+ pc += 2;
772
+ sp += 1;
773
+ } else {
774
+ // Porffor.log(`single: failed, expected ${c1}, got ${c2}`);
775
+ backtrack = true;
776
+ }
777
+ }
778
+ } else if (op == 0x02 || op == 0x03) { // class or negated class
779
+ if (sp >= inputLen) {
780
+ backtrack = true;
781
+ } else {
782
+ let char: i32 = Porffor.wasm.i32.load8_u(input + sp, 0, 4);
783
+ let classPc: i32 = pc + 1;
784
+ let charInClass: boolean = false;
785
+ while (true) {
786
+ const marker: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 0);
787
+ if (marker == 0xFF) break; // end of class
788
+
789
+ if (marker == 0x00) { // range
790
+ let from: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
791
+ let to: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 2);
792
+ let cCheck: i32 = char;
793
+ if (ignoreCase) {
794
+ if (from >= 97 && from <= 122) from -= 32;
795
+ if (to >= 97 && to <= 122) to -= 32;
796
+ if (cCheck >= 97 && cCheck <= 122) cCheck -= 32;
797
+ }
798
+ if (cCheck >= from && cCheck <= to) {
799
+ charInClass = true;
800
+ break;
801
+ }
802
+ classPc += 3;
803
+ } else if (marker == 0x01) { // char
804
+ let c1: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
805
+ let c2: i32 = char;
806
+ if (ignoreCase) {
807
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
808
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
809
+ }
810
+ if (c1 == c2) {
811
+ charInClass = true;
812
+ break;
813
+ }
814
+ classPc += 2;
815
+ } else if (marker == 0x02) { // predefined
816
+ const classId: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 1);
817
+ let isMatch: boolean = false;
818
+ if (classId == 1) isMatch = char >= 48 && char <= 57;
819
+ else if (classId == 2) isMatch = !(char >= 48 && char <= 57);
820
+ else if (classId == 3) isMatch = Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
821
+ else if (classId == 4) isMatch = !Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
822
+ else if (classId == 5) isMatch = (char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95;
823
+ else if (classId == 6) isMatch = !((char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95);
824
+
825
+ if (isMatch) {
826
+ charInClass = true;
827
+ break;
828
+ }
829
+ classPc += 2;
830
+ }
831
+ }
832
+
833
+ if (op == 0x03) charInClass = !charInClass;
834
+
835
+ if (charInClass) {
836
+ while (Porffor.wasm.i32.load8_u(classPc, 0, 0) != 0xFF) {
837
+ const marker: i32 = Porffor.wasm.i32.load8_u(classPc, 0, 0);
838
+ if (marker == 0x00) classPc += 3;
839
+ else if (marker == 0x01) classPc += 2;
840
+ else if (marker == 0x02) classPc += 2;
841
+ }
842
+ pc = classPc + 1;
843
+ sp += 1;
844
+ } else {
845
+ backtrack = true;
846
+ }
847
+ }
848
+ } else if (op == 0x04) { // predefined class
849
+ if (sp >= inputLen) {
850
+ backtrack = true;
851
+ } else {
852
+ const classId: i32 = Porffor.wasm.i32.load8_u(pc, 0, 1);
853
+ const char: i32 = Porffor.wasm.i32.load8_u(input + 4 + sp, 0, 0);
854
+ let isMatch: boolean = false;
855
+ if (classId == 1) isMatch = char >= 48 && char <= 57;
856
+ else if (classId == 2) isMatch = !(char >= 48 && char <= 57);
857
+ else if (classId == 3) isMatch = Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
858
+ else if (classId == 4) isMatch = !Porffor.fastOr(char == 32, char == 9, char == 10, char == 13, char == 11, char == 12);
859
+ else if (classId == 5) isMatch = (char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95;
860
+ else if (classId == 6) isMatch = !((char >= 65 && char <= 90) || (char >= 97 && char <= 122) || (char >= 48 && char <= 57) || char == 95);
861
+
862
+ if (isMatch) {
863
+ pc += 2;
864
+ sp += 1;
865
+ } else {
866
+ backtrack = true;
867
+ }
868
+ }
869
+ } else if (op == 0x05) { // start
870
+ if (sp == 0 || (multiline && sp > 0 && Porffor.wasm.i32.load8_u(input + sp, 0, 3) == 10)) {
871
+ pc += 1;
872
+ } else {
873
+ backtrack = true;
874
+ }
875
+ } else if (op == 0x06) { // end
876
+ if (sp == inputLen || (multiline && sp < inputLen && Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 10)) {
877
+ pc += 1;
878
+ } else {
879
+ backtrack = true;
880
+ }
881
+ } else if (op == 0x07) { // word boundary
882
+ 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);
883
+ 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);
884
+ if (prevIsWord != nextIsWord) {
885
+ pc += 1;
886
+ } else {
887
+ backtrack = true;
888
+ }
889
+ } else if (op == 0x08) { // non-word boundary
890
+ 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);
891
+ 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);
892
+ if (prevIsWord == nextIsWord) {
893
+ pc += 1;
894
+ } else {
895
+ backtrack = true;
896
+ }
897
+ } else if (op == 0x09) { // dot
898
+ if (sp >= inputLen || (!dotAll && Porffor.wasm.i32.load8_u(input + sp, 0, 4) == 10)) {
899
+ backtrack = true;
900
+ } else {
901
+ pc += 1;
902
+ sp += 1;
903
+ }
904
+ } else if (op == 0x0a) { // back reference
905
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
906
+ const arrIndex = (capIndex - 1) * 2;
907
+ if (arrIndex + 1 >= captures.length) { // reference to group that hasn't been seen
908
+ pc += 2;
909
+ } else {
910
+ const capStart = captures[arrIndex];
911
+ const capEnd = captures[arrIndex + 1];
912
+ if (capStart == -1 || capEnd == -1) { // reference to unmatched group
913
+ pc += 2;
914
+ } else {
915
+ const capLen = capEnd - capStart;
916
+ if (sp + capLen > inputLen) {
917
+ backtrack = true;
918
+ } else {
919
+ let matches = true;
920
+ for (let k = 0; k < capLen; k++) {
921
+ let c1 = Porffor.wasm.i32.load8_u(input + capStart + k, 0, 4);
922
+ let c2 = Porffor.wasm.i32.load8_u(input + sp + k, 0, 4);
923
+ if (ignoreCase) {
924
+ if (c1 >= 97 && c1 <= 122) c1 -= 32;
925
+ if (c2 >= 97 && c2 <= 122) c2 -= 32;
926
+ }
927
+ if (c1 != c2) {
928
+ matches = false;
929
+ break;
930
+ }
931
+ }
932
+ if (matches) {
933
+ sp += capLen;
934
+ pc += 2;
935
+ } else {
936
+ backtrack = true;
937
+ }
938
+ }
939
+ }
940
+ }
941
+ } else if (op == 0x20) { // jump
942
+ pc += Porffor.wasm.i32.load16_s(pc, 0, 1);
943
+ } else if (op == 0x21) { // fork
944
+ const branch1Offset = Porffor.wasm.i32.load16_s(pc, 0, 1);
945
+ const branch2Offset = Porffor.wasm.i32.load16_s(pc, 0, 3);
946
+
947
+ Porffor.array.fastPushI32(backtrackStack, pc + branch2Offset);
948
+ Porffor.array.fastPushI32(backtrackStack, sp);
949
+ Porffor.array.fastPushI32(backtrackStack, captures.length);
950
+
951
+ pc += branch1Offset;
952
+ } else if (op == 0x30) { // start capture
953
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
954
+ const arrIndex = capIndex + 255; // + 255 offset for temp start, as it could never end properly
955
+ captures[arrIndex] = sp;
956
+ // Porffor.log(`startCapture: captures[${arrIndex}] = ${sp} | captures.length = ${captures.length}`);
957
+ pc += 2;
958
+ } else if (op == 0x31) { // end capture
959
+ const capIndex = Porffor.wasm.i32.load8_u(pc, 0, 1);
960
+ const arrIndex = (capIndex - 1) * 2 + 1;
961
+ while (captures.length <= arrIndex) Porffor.array.fastPushI32(captures, -1);
962
+ captures[arrIndex - 1] = captures[capIndex + 255];
963
+ captures[arrIndex] = sp;
964
+ // Porffor.log(`endCapture: captures[${arrIndex}] = ${sp} | captures.length = ${captures.length}`);
965
+ pc += 2;
966
+ } else { // unknown op
967
+ backtrack = true;
968
+ }
969
+
970
+ if (backtrack) {
971
+ if (backtrackStack.length == 0) break;
972
+ // Porffor.log(`backtrack! before: captures.length = ${captures.length}, sp = ${sp}, pc = ${pc}`);
973
+ captures.length = backtrackStack.pop();
974
+ sp = backtrackStack.pop();
975
+ pc = backtrackStack.pop();
976
+ // Porffor.log(`backtrack! after: captures.length = ${captures.length}, sp = ${sp}, pc = ${pc}`);
977
+ }
978
+ }
979
+
980
+ if (matched) {
981
+ if (isTest) return true;
982
+
983
+ const matchStart: i32 = i;
984
+ if (global || sticky) {
985
+ Porffor.wasm.i32.store(regexp, finalSp, 0, 8);
986
+ }
987
+
988
+ const result: any[] = Porffor.allocateBytes(4096);
989
+ Porffor.array.fastPush(result, __ByteString_prototype_substring(input, matchStart, finalSp));
990
+
991
+ for (let k = 0; k < totalCaptures; k++) {
992
+ const arrIdx = k * 2;
993
+ if (arrIdx + 1 < captures.length) {
994
+ const capStart = captures[arrIdx];
995
+ const capEnd = captures[arrIdx + 1];
996
+ if (capStart != -1 && capEnd != -1) {
997
+ Porffor.array.fastPush(result, __ByteString_prototype_substring(input, capStart, capEnd));
998
+ } else {
999
+ Porffor.array.fastPush(result, undefined);
1000
+ }
1001
+ } else {
1002
+ Porffor.array.fastPush(result, undefined);
1003
+ }
1004
+ }
1005
+
1006
+ result.index = matchStart;
1007
+ result.input = input as bytestring;
1008
+
1009
+ return result;
1010
+ }
1011
+ }
1012
+
1013
+ if (global || sticky) {
1014
+ Porffor.wasm.i32.store(regexp, 0, 0, 8);
685
1015
  }
686
1016
 
687
- return __Porffor_regex_construct(patternStr, flagsStr);
1017
+ if (isTest) return false;
1018
+ return null;
688
1019
  };
689
1020
 
1021
+
690
1022
  export const __RegExp_prototype_source$get = (_this: RegExp) => {
691
1023
  return Porffor.wasm.i32.load(_this, 0, 0) as bytestring;
692
1024
  };
@@ -766,4 +1098,54 @@ export const __RegExp_prototype_unicodeSets$get = (_this: RegExp) => {
766
1098
 
767
1099
  export const __RegExp_prototype_toString = (_this: RegExp) => {
768
1100
  return '/' + _this.source + '/' + _this.flags;
1101
+ };
1102
+
1103
+
1104
+ export const RegExp = function (pattern: any, flags: any = undefined): RegExp {
1105
+ let patternSrc, flagsSrc;
1106
+ if (Porffor.type(pattern) === Porffor.TYPES.regexp) {
1107
+ patternSrc = __RegExp_prototype_source$get(pattern);
1108
+ if (flags === undefined) {
1109
+ flagsSrc = __RegExp_prototype_flags$get(pattern);
1110
+ } else {
1111
+ flagsSrc = flags;
1112
+ }
1113
+ } else {
1114
+ patternSrc = pattern;
1115
+ flagsSrc = flags;
1116
+ }
1117
+
1118
+ if (patternSrc === undefined) patternSrc = '';
1119
+ if (flagsSrc === undefined) flagsSrc = '';
1120
+
1121
+ if (Porffor.type(patternSrc) !== Porffor.TYPES.bytestring || Porffor.type(flagsSrc) !== Porffor.TYPES.bytestring) {
1122
+ throw new TypeError('Invalid regular expression');
1123
+ }
1124
+
1125
+ return __Porffor_regex_compile(patternSrc, flagsSrc);
1126
+ };
1127
+
1128
+
1129
+ export const __RegExp_prototype_exec = (_this: RegExp, input: bytestring) => {
1130
+ return __Porffor_regex_interpret(_this, input, false);
1131
+ };
1132
+
1133
+ export const __RegExp_prototype_test = (_this: RegExp, input: bytestring) => {
1134
+ return __Porffor_regex_interpret(_this, input, true);
1135
+ };
1136
+
1137
+ export const __String_prototype_match = (_this: string, regexp: RegExp) => {
1138
+ if (Porffor.type(regexp) !== Porffor.TYPES.regexp) {
1139
+ regexp = new RegExp(regexp);
1140
+ }
1141
+
1142
+ return regexp.exec(_this);
1143
+ };
1144
+
1145
+ export const __ByteString_prototype_match = (_this: bytestring, regexp: RegExp) => {
1146
+ if (Porffor.type(regexp) !== Porffor.TYPES.regexp) {
1147
+ regexp = new RegExp(regexp);
1148
+ }
1149
+
1150
+ return regexp.exec(_this);
769
1151
  };