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.
- package/compiler/assemble.js +5 -3
- package/compiler/builtins/console.ts +6 -1
- package/compiler/builtins/regexp.ts +427 -45
- package/compiler/builtins.js +15 -9
- package/compiler/builtins_precompiled.js +388 -351
- package/compiler/codegen.js +38 -26
- package/compiler/wrap.js +2 -2
- package/foo.js +4 -0
- package/package.json +1 -1
- package/runtime/index.js +1 -1
package/compiler/assemble.js
CHANGED
@@ -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,
|
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
|
@@ -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
|
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 +
|
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.
|
291
|
+
Porffor.array.fastPushI32(groupStack, captureIndex);
|
279
292
|
captureIndex += 1;
|
280
293
|
} else {
|
281
|
-
Porffor.array.
|
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
|
293
|
-
if (
|
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,
|
316
|
+
Porffor.wasm.i32.store8(bcPtr, capturePop, 0, 1);
|
296
317
|
bcPtr += 2;
|
297
318
|
}
|
298
319
|
|
299
|
-
|
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
|
-
|
313
|
-
Porffor.array.fastPush(altStackPos, bcPtr);
|
314
|
-
Porffor.array.fastPush(altStackGroupDepth, groupDepth);
|
327
|
+
altDepth[groupDepth] += 1;
|
315
328
|
|
316
|
-
|
317
|
-
Porffor.wasm.
|
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
|
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 +=
|
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
|
-
//
|
671
|
-
|
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
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
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
|
-
|
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
|
};
|