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.
- package/compiler/assemble.js +5 -3
- package/compiler/builtins/console.ts +6 -1
- package/compiler/builtins/regexp.ts +424 -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/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);
|
@@ -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
|
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 +=
|
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
|
-
//
|
671
|
-
|
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
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
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
|
-
|
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
|
};
|
package/compiler/builtins.js
CHANGED
@@ -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, {
|
824
|
+
wasm: (scope, { allocLargePage, funcs }) => [
|
825
825
|
[ Opcodes.local_get, 0 ],
|
826
|
-
|
826
|
+
[ null, () => [
|
827
|
+
number(funcs.bytesPerFuncLut(), Valtype.i32)
|
828
|
+
] ],
|
827
829
|
[ Opcodes.i32_mul ],
|
828
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(
|
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, {
|
839
|
+
wasm: (scope, { allocLargePage, funcs }) => [
|
838
840
|
[ Opcodes.local_get, 0 ],
|
839
|
-
|
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(
|
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, {
|
856
|
+
wasm: (scope, { allocLargePage, funcs }) => [
|
853
857
|
[ Opcodes.local_get, 0 ],
|
854
|
-
|
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(
|
864
|
+
number(allocLargePage(scope, 'func lut'), Valtype.i32),
|
859
865
|
[ Opcodes.i32_add ]
|
860
866
|
],
|
861
867
|
table: true
|