cjs • Lines: 5792/*!
* re2js
* RE2JS is the JavaScript port of RE2, a regular expression engine that provides linear time matching
*
* @version v0.4.3
* @author Alexey Vasiliev
* @homepage https://github.com/le0pard/re2js#readme
* @repository github:le0pard/re2js
* @license MIT
*/
'use strict';
//// Parser flags.
class RE2Flags {
// Fold case during matching (case-insensitive).
static FOLD_CASE = 0x01;
// Treat pattern as a literal string instead of a regexp.
static LITERAL = 0x02;
// Allow character classes like [^a-z] and [[:space:]] to match newline.
static CLASS_NL = 0x04;
// Allow '.' to match newline.
static DOT_NL = 0x08;
// Treat ^ and $ as only matching at beginning and end of text, not
// around embedded newlines. (Perl's default).
static ONE_LINE = 0x10;
// Make repetition operators default to non-greedy.
static NON_GREEDY = 0x20;
// allow Perl extensions:
// non-capturing parens - (?: )
// non-greedy operators - *? +? ?? {}?
// flag edits - (?i) (?-i) (?i: )
// i - FoldCase
// m - !OneLine
// s - DotNL
// U - NonGreedy
// line ends: \A \z
// \Q and \E to disable/enable metacharacters
// (?P<name>expr) for named captures
// \C (any byte) is not supported.
static PERL_X = 0x40;
// Allow \p{Han}, \P{Han} for Unicode group and negation.
static UNICODE_GROUPS = 0x80;
// Regexp END_TEXT was $, not \z. Internal use only.
static WAS_DOLLAR = 0x100;
static MATCH_NL = (() => RE2Flags.CLASS_NL | RE2Flags.DOT_NL)();
// As close to Perl as possible.
static PERL = (() => RE2Flags.CLASS_NL | RE2Flags.ONE_LINE | RE2Flags.PERL_X | RE2Flags.UNICODE_GROUPS)();
// POSIX syntax.
static POSIX = 0;
//// Anchors
static UNANCHORED = 0;
static ANCHOR_START = 1;
static ANCHOR_BOTH = 2;
}
/**
* Various constants and helper for unicode codepoints.
*/
class Codepoint {
// codePointAt(0)
static CODES = (() => new Map([['\x07', 7], ['\b', 8], ['\t', 9], ['\n', 10], ['\v', 11], ['\f', 12], ['\r', 13], [' ', 32], ['"', 34], ['$', 36], ['&', 38], ['(', 40], [')', 41], ['*', 42], ['+', 43], ['-', 45], ['.', 46], ['0', 48], ['1', 49], ['2', 50], ['3', 51], ['4', 52], ['5', 53], ['6', 54], ['7', 55], ['8', 56], ['9', 57], [':', 58], ['<', 60], ['>', 62], ['?', 63], ['A', 65], ['B', 66], ['C', 67], ['F', 70], ['P', 80], ['Q', 81], ['U', 85], ['Z', 90], ['[', 91], ['\\', 92], [']', 93], ['^', 94], ['_', 95], ['a', 97], ['b', 98], ['f', 102], ['i', 105], ['m', 109], ['n', 110], ['r', 114], ['s', 115], ['t', 116], ['v', 118], ['x', 120], ['z', 122], ['{', 123], ['|', 124], ['}', 125]]))();
// convert unicode codepoint to upper case codepoint
// return same codepoint, if cannot do it (or codepoint not have upper variation)
static toUpperCase(codepoint) {
const s = String.fromCodePoint(codepoint).toUpperCase();
if (s.length > 1) {
return codepoint;
}
const sOrigin = String.fromCodePoint(s.codePointAt(0)).toLowerCase();
if (sOrigin.length > 1 || sOrigin.codePointAt(0) !== codepoint) {
return codepoint;
}
return s.codePointAt(0);
}
// convert unicode codepoint to lower case codepoint
// return same codepoint, if cannot do it (or codepoint not have lower variation)
static toLowerCase(codepoint) {
const s = String.fromCodePoint(codepoint).toLowerCase();
if (s.length > 1) {
return codepoint;
}
const sOrigin = String.fromCodePoint(s.codePointAt(0)).toUpperCase();
if (sOrigin.length > 1 || sOrigin.codePointAt(0) !== codepoint) {
return codepoint;
}
return s.codePointAt(0);
}
}
// GENERATED BY tools/scripts/genUnicodeTable.js; DO NOT EDIT.
// yarn node ./tools/scripts/genUnicodeTable.js > src/UnicodeTables.js
class UnicodeTables {
static CASE_ORBIT = (() => new Map([[75, 107], [107, 8490], [8490, 75], [83, 115], [115, 383], [383, 83], [181, 924], [924, 956], [956, 181], [197, 229], [229, 8491], [8491, 197], [452, 453], [453, 454], [454, 452], [455, 456], [456, 457], [457, 455], [458, 459], [459, 460], [460, 458], [497, 498], [498, 499], [499, 497], [837, 921], [921, 953], [953, 8126], [8126, 837], [914, 946], [946, 976], [976, 914], [917, 949], [949, 1013], [1013, 917], [920, 952], [952, 977], [977, 1012], [1012, 920], [922, 954], [954, 1008], [1008, 922], [928, 960], [960, 982], [982, 928], [929, 961], [961, 1009], [1009, 929], [931, 962], [962, 963], [963, 931], [934, 966], [966, 981], [981, 934], [937, 969], [969, 8486], [8486, 937], [1042, 1074], [1074, 7296], [7296, 1042], [1044, 1076], [1076, 7297], [7297, 1044], [1054, 1086], [1086, 7298], [7298, 1054], [1057, 1089], [1089, 7299], [7299, 1057], [1058, 1090], [1090, 7300], [7300, 7301], [7301, 1058], [1066, 1098], [1098, 7302], [7302, 1066], [1122, 1123], [1123, 7303], [7303, 1122], [7304, 42570], [42570, 42571], [42571, 7304], [7776, 7777], [7777, 7835], [7835, 7776], [223, 7838], [7838, 223], [8064, 8072], [8072, 8064], [8065, 8073], [8073, 8065], [8066, 8074], [8074, 8066], [8067, 8075], [8075, 8067], [8068, 8076], [8076, 8068], [8069, 8077], [8077, 8069], [8070, 8078], [8078, 8070], [8071, 8079], [8079, 8071], [8080, 8088], [8088, 8080], [8081, 8089], [8089, 8081], [8082, 8090], [8090, 8082], [8083, 8091], [8091, 8083], [8084, 8092], [8092, 8084], [8085, 8093], [8093, 8085], [8086, 8094], [8094, 8086], [8087, 8095], [8095, 8087], [8096, 8104], [8104, 8096], [8097, 8105], [8105, 8097], [8098, 8106], [8106, 8098], [8099, 8107], [8107, 8099], [8100, 8108], [8108, 8100], [8101, 8109], [8109, 8101], [8102, 8110], [8110, 8102], [8103, 8111], [8111, 8103], [8115, 8124], [8124, 8115], [8131, 8140], [8140, 8131], [912, 8147], [8147, 912], [944, 8163], [8163, 944], [8179, 8188], [8188, 8179], [64261, 64262], [64262, 64261], [66560, 66600], [66600, 66560], [66561, 66601], [66601, 66561], [66562, 66602], [66602, 66562], [66563, 66603], [66603, 66563], [66564, 66604], [66604, 66564], [66565, 66605], [66605, 66565], [66566, 66606], [66606, 66566], [66567, 66607], [66607, 66567], [66568, 66608], [66608, 66568], [66569, 66609], [66609, 66569], [66570, 66610], [66610, 66570], [66571, 66611], [66611, 66571], [66572, 66612], [66612, 66572], [66573, 66613], [66613, 66573], [66574, 66614], [66614, 66574], [66575, 66615], [66615, 66575], [66576, 66616], [66616, 66576], [66577, 66617], [66617, 66577], [66578, 66618], [66618, 66578], [66579, 66619], [66619, 66579], [66580, 66620], [66620, 66580], [66581, 66621], [66621, 66581], [66582, 66622], [66622, 66582], [66583, 66623], [66623, 66583], [66584, 66624], [66624, 66584], [66585, 66625], [66625, 66585], [66586, 66626], [66626, 66586], [66587, 66627], [66627, 66587], [66588, 66628], [66628, 66588], [66589, 66629], [66629, 66589], [66590, 66630], [66630, 66590], [66591, 66631], [66631, 66591], [66592, 66632], [66632, 66592], [66593, 66633], [66633, 66593], [66594, 66634], [66634, 66594], [66595, 66635], [66635, 66595], [66596, 66636], [66636, 66596], [66597, 66637], [66637, 66597], [66598, 66638], [66638, 66598], [66599, 66639], [66639, 66599], [66736, 66776], [66776, 66736], [66737, 66777], [66777, 66737], [66738, 66778], [66778, 66738], [66739, 66779], [66779, 66739], [66740, 66780], [66780, 66740], [66741, 66781], [66781, 66741], [66742, 66782], [66782, 66742], [66743, 66783], [66783, 66743], [66744, 66784], [66784, 66744], [66745, 66785], [66785, 66745], [66746, 66786], [66786, 66746], [66747, 66787], [66787, 66747], [66748, 66788], [66788, 66748], [66749, 66789], [66789, 66749], [66750, 66790], [66790, 66750], [66751, 66791], [66791, 66751], [66752, 66792], [66792, 66752], [66753, 66793], [66793, 66753], [66754, 66794], [66794, 66754], [66755, 66795], [66795, 66755], [66756, 66796], [66796, 66756], [66757, 66797], [66797, 66757], [66758, 66798], [66798, 66758], [66759, 66799], [66799, 66759], [66760, 66800], [66800, 66760], [66761, 66801], [66801, 66761], [66762, 66802], [66802, 66762], [66763, 66803], [66803, 66763], [66764, 66804], [66804, 66764], [66765, 66805], [66805, 66765], [66766, 66806], [66806, 66766], [66767, 66807], [66807, 66767], [66768, 66808], [66808, 66768], [66769, 66809], [66809, 66769], [66770, 66810], [66810, 66770], [66771, 66811], [66811, 66771], [66928, 66967], [66967, 66928], [66929, 66968], [66968, 66929], [66930, 66969], [66969, 66930], [66931, 66970], [66970, 66931], [66932, 66971], [66971, 66932], [66933, 66972], [66972, 66933], [66934, 66973], [66973, 66934], [66935, 66974], [66974, 66935], [66936, 66975], [66975, 66936], [66937, 66976], [66976, 66937], [66938, 66977], [66977, 66938], [66940, 66979], [66979, 66940], [66941, 66980], [66980, 66941], [66942, 66981], [66981, 66942], [66943, 66982], [66982, 66943], [66944, 66983], [66983, 66944], [66945, 66984], [66984, 66945], [66946, 66985], [66985, 66946], [66947, 66986], [66986, 66947], [66948, 66987], [66987, 66948], [66949, 66988], [66988, 66949], [66950, 66989], [66989, 66950], [66951, 66990], [66990, 66951], [66952, 66991], [66991, 66952], [66953, 66992], [66992, 66953], [66954, 66993], [66993, 66954], [66956, 66995], [66995, 66956], [66957, 66996], [66996, 66957], [66958, 66997], [66997, 66958], [66959, 66998], [66998, 66959], [66960, 66999], [66999, 66960], [66961, 67000], [67000, 66961], [66962, 67001], [67001, 66962], [66964, 67003], [67003, 66964], [66965, 67004], [67004, 66965], [68736, 68800], [68800, 68736], [68737, 68801], [68801, 68737], [68738, 68802], [68802, 68738], [68739, 68803], [68803, 68739], [68740, 68804], [68804, 68740], [68741, 68805], [68805, 68741], [68742, 68806], [68806, 68742], [68743, 68807], [68807, 68743], [68744, 68808], [68808, 68744], [68745, 68809], [68809, 68745], [68746, 68810], [68810, 68746], [68747, 68811], [68811, 68747], [68748, 68812], [68812, 68748], [68749, 68813], [68813, 68749], [68750, 68814], [68814, 68750], [68751, 68815], [68815, 68751], [68752, 68816], [68816, 68752], [68753, 68817], [68817, 68753], [68754, 68818], [68818, 68754], [68755, 68819], [68819, 68755], [68756, 68820], [68820, 68756], [68757, 68821], [68821, 68757], [68758, 68822], [68822, 68758], [68759, 68823], [68823, 68759], [68760, 68824], [68824, 68760], [68761, 68825], [68825, 68761], [68762, 68826], [68826, 68762], [68763, 68827], [68827, 68763], [68764, 68828], [68828, 68764], [68765, 68829], [68829, 68765], [68766, 68830], [68830, 68766], [68767, 68831], [68831, 68767], [68768, 68832], [68832, 68768], [68769, 68833], [68833, 68769], [68770, 68834], [68834, 68770], [68771, 68835], [68835, 68771], [68772, 68836], [68836, 68772], [68773, 68837], [68837, 68773], [68774, 68838], [68838, 68774], [68775, 68839], [68839, 68775], [68776, 68840], [68840, 68776], [68777, 68841], [68841, 68777], [68778, 68842], [68842, 68778], [68779, 68843], [68843, 68779], [68780, 68844], [68844, 68780], [68781, 68845], [68845, 68781], [68782, 68846], [68846, 68782], [68783, 68847], [68847, 68783], [68784, 68848], [68848, 68784], [68785, 68849], [68849, 68785], [68786, 68850], [68850, 68786], [71840, 71872], [71872, 71840], [71841, 71873], [71873, 71841], [71842, 71874], [71874, 71842], [71843, 71875], [71875, 71843], [71844, 71876], [71876, 71844], [71845, 71877], [71877, 71845], [71846, 71878], [71878, 71846], [71847, 71879], [71879, 71847], [71848, 71880], [71880, 71848], [71849, 71881], [71881, 71849], [71850, 71882], [71882, 71850], [71851, 71883], [71883, 71851], [71852, 71884], [71884, 71852], [71853, 71885], [71885, 71853], [71854, 71886], [71886, 71854], [71855, 71887], [71887, 71855], [71856, 71888], [71888, 71856], [71857, 71889], [71889, 71857], [71858, 71890], [71890, 71858], [71859, 71891], [71891, 71859], [71860, 71892], [71892, 71860], [71861, 71893], [71893, 71861], [71862, 71894], [71894, 71862], [71863, 71895], [71895, 71863], [71864, 71896], [71896, 71864], [71865, 71897], [71897, 71865], [71866, 71898], [71898, 71866], [71867, 71899], [71899, 71867], [71868, 71900], [71900, 71868], [71869, 71901], [71901, 71869], [71870, 71902], [71902, 71870], [71871, 71903], [71903, 71871], [93760, 93792], [93792, 93760], [93761, 93793], [93793, 93761], [93762, 93794], [93794, 93762], [93763, 93795], [93795, 93763], [93764, 93796], [93796, 93764], [93765, 93797], [93797, 93765], [93766, 93798], [93798, 93766], [93767, 93799], [93799, 93767], [93768, 93800], [93800, 93768], [93769, 93801], [93801, 93769], [93770, 93802], [93802, 93770], [93771, 93803], [93803, 93771], [93772, 93804], [93804, 93772], [93773, 93805], [93805, 93773], [93774, 93806], [93806, 93774], [93775, 93807], [93807, 93775], [93776, 93808], [93808, 93776], [93777, 93809], [93809, 93777], [93778, 93810], [93810, 93778], [93779, 93811], [93811, 93779], [93780, 93812], [93812, 93780], [93781, 93813], [93813, 93781], [93782, 93814], [93814, 93782], [93783, 93815], [93815, 93783], [93784, 93816], [93816, 93784], [93785, 93817], [93817, 93785], [93786, 93818], [93818, 93786], [93787, 93819], [93819, 93787], [93788, 93820], [93820, 93788], [93789, 93821], [93821, 93789], [93790, 93822], [93822, 93790], [93791, 93823], [93823, 93791], [125184, 125218], [125218, 125184], [125185, 125219], [125219, 125185], [125186, 125220], [125220, 125186], [125187, 125221], [125221, 125187], [125188, 125222], [125222, 125188], [125189, 125223], [125223, 125189], [125190, 125224], [125224, 125190], [125191, 125225], [125225, 125191], [125192, 125226], [125226, 125192], [125193, 125227], [125227, 125193], [125194, 125228], [125228, 125194], [125195, 125229], [125229, 125195], [125196, 125230], [125230, 125196], [125197, 125231], [125231, 125197], [125198, 125232], [125232, 125198], [125199, 125233], [125233, 125199], [125200, 125234], [125234, 125200], [125201, 125235], [125235, 125201], [125202, 125236], [125236, 125202], [125203, 125237], [125237, 125203], [125204, 125238], [125238, 125204], [125205, 125239], [125239, 125205], [125206, 125240], [125240, 125206], [125207, 125241], [125241, 125207], [125208, 125242], [125242, 125208], [125209, 125243], [125243, 125209], [125210, 125244], [125244, 125210], [125211, 125245], [125245, 125211], [125212, 125246], [125246, 125212], [125213, 125247], [125247, 125213], [125214, 125248], [125248, 125214], [125215, 125249], [125249, 125215], [125216, 125250], [125250, 125216], [125217, 125251], [125251, 125217]]))();
static C = [[0, 31, 1], [127, 159, 1], [173, 888, 715], [889, 896, 7], [897, 899, 1], [907, 909, 2], [930, 1328, 398], [1367, 1368, 1], [1419, 1420, 1], [1424, 1480, 56], [1481, 1487, 1], [1515, 1518, 1], [1525, 1541, 1], [1564, 1757, 193], [1806, 1807, 1], [1867, 1868, 1], [1970, 1983, 1], [2043, 2044, 1], [2094, 2095, 1], [2111, 2140, 29], [2141, 2143, 2], [2155, 2159, 1], [2191, 2199, 1], [2274, 2436, 162], [2445, 2446, 1], [2449, 2450, 1], [2473, 2481, 8], [2483, 2485, 1], [2490, 2491, 1], [2501, 2502, 1], [2505, 2506, 1], [2511, 2518, 1], [2520, 2523, 1], [2526, 2532, 6], [2533, 2559, 26], [2560, 2564, 4], [2571, 2574, 1], [2577, 2578, 1], [2601, 2609, 8], [2612, 2618, 3], [2619, 2621, 2], [2627, 2630, 1], [2633, 2634, 1], [2638, 2640, 1], [2642, 2648, 1], [2653, 2655, 2], [2656, 2661, 1], [2679, 2688, 1], [2692, 2702, 10], [2706, 2729, 23], [2737, 2740, 3], [2746, 2747, 1], [2758, 2766, 4], [2767, 2769, 2], [2770, 2783, 1], [2788, 2789, 1], [2802, 2808, 1], [2816, 2820, 4], [2829, 2830, 1], [2833, 2834, 1], [2857, 2865, 8], [2868, 2874, 6], [2875, 2885, 10], [2886, 2889, 3], [2890, 2894, 4], [2895, 2900, 1], [2904, 2907, 1], [2910, 2916, 6], [2917, 2936, 19], [2937, 2945, 1], [2948, 2955, 7], [2956, 2957, 1], [2961, 2966, 5], [2967, 2968, 1], [2971, 2973, 2], [2976, 2978, 1], [2981, 2983, 1], [2987, 2989, 1], [3002, 3005, 1], [3011, 3013, 1], [3017, 3022, 5], [3023, 3025, 2], [3026, 3030, 1], [3032, 3045, 1], [3067, 3071, 1], [3085, 3089, 4], [3113, 3130, 17], [3131, 3141, 10], [3145, 3150, 5], [3151, 3156, 1], [3159, 3163, 4], [3164, 3166, 2], [3167, 3172, 5], [3173, 3184, 11], [3185, 3190, 1], [3213, 3217, 4], [3241, 3252, 11], [3258, 3259, 1], [3269, 3273, 4], [3278, 3284, 1], [3287, 3292, 1], [3295, 3300, 5], [3301, 3312, 11], [3316, 3327, 1], [3341, 3345, 4], [3397, 3401, 4], [3408, 3411, 1], [3428, 3429, 1], [3456, 3460, 4], [3479, 3481, 1], [3506, 3516, 10], [3518, 3519, 1], [3527, 3529, 1], [3531, 3534, 1], [3541, 3543, 2], [3552, 3557, 1], [3568, 3569, 1], [3573, 3584, 1], [3643, 3646, 1], [3676, 3712, 1], [3715, 3717, 2], [3723, 3748, 25], [3750, 3774, 24], [3775, 3781, 6], [3783, 3791, 8], [3802, 3803, 1], [3808, 3839, 1], [3912, 3949, 37], [3950, 3952, 1], [3992, 4029, 37], [4045, 4059, 14], [4060, 4095, 1], [4294, 4296, 2], [4297, 4300, 1], [4302, 4303, 1], [4681, 4686, 5], [4687, 4695, 8], [4697, 4702, 5], [4703, 4745, 42], [4750, 4751, 1], [4785, 4790, 5], [4791, 4799, 8], [4801, 4806, 5], [4807, 4823, 16], [4881, 4886, 5], [4887, 4955, 68], [4956, 4989, 33], [4990, 4991, 1], [5018, 5023, 1], [5110, 5111, 1], [5118, 5119, 1], [5789, 5791, 1], [5881, 5887, 1], [5910, 5918, 1], [5943, 5951, 1], [5972, 5983, 1], [5997, 6001, 4], [6004, 6015, 1], [6110, 6111, 1], [6122, 6127, 1], [6138, 6143, 1], [6158, 6170, 12], [6171, 6175, 1], [6265, 6271, 1], [6315, 6319, 1], [6390, 6399, 1], [6431, 6444, 13], [6445, 6447, 1], [6460, 6463, 1], [6465, 6467, 1], [6510, 6511, 1], [6517, 6527, 1], [6572, 6575, 1], [6602, 6607, 1], [6619, 6621, 1], [6684, 6685, 1], [6751, 6781, 30], [6782, 6794, 12], [6795, 6799, 1], [6810, 6815, 1], [6830, 6831, 1], [6863, 6911, 1], [6989, 6991, 1], [7039, 7156, 117], [7157, 7163, 1], [7224, 7226, 1], [7242, 7244, 1], [7305, 7311, 1], [7355, 7356, 1], [7368, 7375, 1], [7419, 7423, 1], [7958, 7959, 1], [7966, 7967, 1], [8006, 8007, 1], [8014, 8015, 1], [8024, 8030, 2], [8062, 8063, 1], [8117, 8133, 16], [8148, 8149, 1], [8156, 8176, 20], [8177, 8181, 4], [8191, 8203, 12], [8204, 8207, 1], [8234, 8238, 1], [8288, 8303, 1], [8306, 8307, 1], [8335, 8349, 14], [8350, 8351, 1], [8385, 8399, 1], [8433, 8447, 1], [8588, 8591, 1], [9255, 9279, 1], [9291, 9311, 1], [11124, 11125, 1], [11158, 11508, 350], [11509, 11512, 1], [11558, 11560, 2], [11561, 11564, 1], [11566, 11567, 1], [11624, 11630, 1], [11633, 11646, 1], [11671, 11679, 1], [11687, 11743, 8], [11870, 11903, 1], [11930, 12020, 90], [12021, 12031, 1], [12246, 12271, 1], [12352, 12439, 87], [12440, 12544, 104], [12545, 12548, 1], [12592, 12687, 95], [12772, 12782, 1], [12831, 42125, 29294], [42126, 42127, 1], [42183, 42191, 1], [42540, 42559, 1], [42744, 42751, 1], [42955, 42959, 1], [42962, 42964, 2], [42970, 42993, 1], [43053, 43055, 1], [43066, 43071, 1], [43128, 43135, 1], [43206, 43213, 1], [43226, 43231, 1], [43348, 43358, 1], [43389, 43391, 1], [43470, 43482, 12], [43483, 43485, 1], [43519, 43575, 56], [43576, 43583, 1], [43598, 43599, 1], [43610, 43611, 1], [43715, 43738, 1], [43767, 43776, 1], [43783, 43784, 1], [43791, 43792, 1], [43799, 43807, 1], [43815, 43823, 8], [43884, 43887, 1], [44014, 44015, 1], [44026, 44031, 1], [55204, 55215, 1], [55239, 55242, 1], [55292, 63743, 1], [64110, 64111, 1], [64218, 64255, 1], [64263, 64274, 1], [64280, 64284, 1], [64311, 64317, 6], [64319, 64325, 3], [64451, 64466, 1], [64912, 64913, 1], [64968, 64974, 1], [64976, 65007, 1], [65050, 65055, 1], [65107, 65127, 20], [65132, 65135, 1], [65141, 65277, 136], [65278, 65280, 1], [65471, 65473, 1], [65480, 65481, 1], [65488, 65489, 1], [65496, 65497, 1], [65501, 65503, 1], [65511, 65519, 8], [65520, 65531, 1], [65534, 65535, 1], [65548, 65575, 27], [65595, 65598, 3], [65614, 65615, 1], [65630, 65663, 1], [65787, 65791, 1], [65795, 65798, 1], [65844, 65846, 1], [65935, 65949, 14], [65950, 65951, 1], [65953, 65999, 1], [66046, 66175, 1], [66205, 66207, 1], [66257, 66271, 1], [66300, 66303, 1], [66340, 66348, 1], [66379, 66383, 1], [66427, 66431, 1], [66462, 66500, 38], [66501, 66503, 1], [66518, 66559, 1], [66718, 66719, 1], [66730, 66735, 1], [66772, 66775, 1], [66812, 66815, 1], [66856, 66863, 1], [66916, 66926, 1], [66939, 66955, 16], [66963, 66966, 3], [66978, 66994, 16], [67002, 67005, 3], [67006, 67071, 1], [67383, 67391, 1], [67414, 67423, 1], [67432, 67455, 1], [67462, 67505, 43], [67515, 67583, 1], [67590, 67591, 1], [67593, 67638, 45], [67641, 67643, 1], [67645, 67646, 1], [67670, 67743, 73], [67744, 67750, 1], [67760, 67807, 1], [67827, 67830, 3], [67831, 67834, 1], [67868, 67870, 1], [67898, 67902, 1], [67904, 67967, 1], [68024, 68027, 1], [68048, 68049, 1], [68100, 68103, 3], [68104, 68107, 1], [68116, 68120, 4], [68150, 68151, 1], [68155, 68158, 1], [68169, 68175, 1], [68185, 68191, 1], [68256, 68287, 1], [68327, 68330, 1], [68343, 68351, 1], [68406, 68408, 1], [68438, 68439, 1], [68467, 68471, 1], [68498, 68504, 1], [68509, 68520, 1], [68528, 68607, 1], [68681, 68735, 1], [68787, 68799, 1], [68851, 68857, 1], [68904, 68911, 1], [68922, 69215, 1], [69247, 69290, 43], [69294, 69295, 1], [69298, 69372, 1], [69416, 69423, 1], [69466, 69487, 1], [69514, 69551, 1], [69580, 69599, 1], [69623, 69631, 1], [69710, 69713, 1], [69750, 69758, 1], [69821, 69827, 6], [69828, 69839, 1], [69865, 69871, 1], [69882, 69887, 1], [69941, 69960, 19], [69961, 69967, 1], [70007, 70015, 1], [70112, 70133, 21], [70134, 70143, 1], [70162, 70210, 48], [70211, 70271, 1], [70279, 70281, 2], [70286, 70302, 16], [70314, 70319, 1], [70379, 70383, 1], [70394, 70399, 1], [70404, 70413, 9], [70414, 70417, 3], [70418, 70441, 23], [70449, 70452, 3], [70458, 70469, 11], [70470, 70473, 3], [70474, 70478, 4], [70479, 70481, 2], [70482, 70486, 1], [70488, 70492, 1], [70500, 70501, 1], [70509, 70511, 1], [70517, 70655, 1], [70748, 70754, 6], [70755, 70783, 1], [70856, 70863, 1], [70874, 71039, 1], [71094, 71095, 1], [71134, 71167, 1], [71237, 71247, 1], [71258, 71263, 1], [71277, 71295, 1], [71354, 71359, 1], [71370, 71423, 1], [71451, 71452, 1], [71468, 71471, 1], [71495, 71679, 1], [71740, 71839, 1], [71923, 71934, 1], [71943, 71944, 1], [71946, 71947, 1], [71956, 71959, 3], [71990, 71993, 3], [71994, 72007, 13], [72008, 72015, 1], [72026, 72095, 1], [72104, 72105, 1], [72152, 72153, 1], [72165, 72191, 1], [72264, 72271, 1], [72355, 72367, 1], [72441, 72447, 1], [72458, 72703, 1], [72713, 72759, 46], [72774, 72783, 1], [72813, 72815, 1], [72848, 72849, 1], [72872, 72887, 15], [72888, 72959, 1], [72967, 72970, 3], [73015, 73017, 1], [73019, 73022, 3], [73032, 73039, 1], [73050, 73055, 1], [73062, 73065, 3], [73103, 73106, 3], [73113, 73119, 1], [73130, 73439, 1], [73465, 73471, 1], [73489, 73531, 42], [73532, 73533, 1], [73562, 73647, 1], [73649, 73663, 1], [73714, 73726, 1], [74650, 74751, 1], [74863, 74869, 6], [74870, 74879, 1], [75076, 77711, 1], [77811, 77823, 1], [78896, 78911, 1], [78934, 82943, 1], [83527, 92159, 1], [92729, 92735, 1], [92767, 92778, 11], [92779, 92781, 1], [92863, 92874, 11], [92875, 92879, 1], [92910, 92911, 1], [92918, 92927, 1], [92998, 93007, 1], [93018, 93026, 8], [93048, 93052, 1], [93072, 93759, 1], [93851, 93951, 1], [94027, 94030, 1], [94088, 94094, 1], [94112, 94175, 1], [94181, 94191, 1], [94194, 94207, 1], [100344, 100351, 1], [101590, 101631, 1], [101641, 110575, 1], [110580, 110588, 8], [110591, 110883, 292], [110884, 110897, 1], [110899, 110927, 1], [110931, 110932, 1], [110934, 110947, 1], [110952, 110959, 1], [111356, 113663, 1], [113771, 113775, 1], [113789, 113791, 1], [113801, 113807, 1], [113818, 113819, 1], [113824, 118527, 1], [118574, 118575, 1], [118599, 118607, 1], [118724, 118783, 1], [119030, 119039, 1], [119079, 119080, 1], [119155, 119162, 1], [119275, 119295, 1], [119366, 119487, 1], [119508, 119519, 1], [119540, 119551, 1], [119639, 119647, 1], [119673, 119807, 1], [119893, 119965, 72], [119968, 119969, 1], [119971, 119972, 1], [119975, 119976, 1], [119981, 119994, 13], [119996, 120004, 8], [120070, 120075, 5], [120076, 120085, 9], [120093, 120122, 29], [120127, 120133, 6], [120135, 120137, 1], [120145, 120486, 341], [120487, 120780, 293], [120781, 121484, 703], [121485, 121498, 1], [121504, 121520, 16], [121521, 122623, 1], [122655, 122660, 1], [122667, 122879, 1], [122887, 122905, 18], [122906, 122914, 8], [122917, 122923, 6], [122924, 122927, 1], [122990, 123022, 1], [123024, 123135, 1], [123181, 123183, 1], [123198, 123199, 1], [123210, 123213, 1], [123216, 123535, 1], [123567, 123583, 1], [123642, 123646, 1], [123648, 124111, 1], [124154, 124895, 1], [124903, 124908, 5], [124911, 124927, 16], [125125, 125126, 1], [125143, 125183, 1], [125260, 125263, 1], [125274, 125277, 1], [125280, 126064, 1], [126133, 126208, 1], [126270, 126463, 1], [126468, 126496, 28], [126499, 126501, 2], [126502, 126504, 2], [126515, 126520, 5], [126522, 126524, 2], [126525, 126529, 1], [126531, 126534, 1], [126536, 126540, 2], [126544, 126547, 3], [126549, 126550, 1], [126552, 126560, 2], [126563, 126565, 2], [126566, 126571, 5], [126579, 126589, 5], [126591, 126602, 11], [126620, 126624, 1], [126628, 126634, 6], [126652, 126703, 1], [126706, 126975, 1], [127020, 127023, 1], [127124, 127135, 1], [127151, 127152, 1], [127168, 127184, 16], [127222, 127231, 1], [127406, 127461, 1], [127491, 127503, 1], [127548, 127551, 1], [127561, 127567, 1], [127570, 127583, 1], [127590, 127743, 1], [128728, 128731, 1], [128749, 128751, 1], [128765, 128767, 1], [128887, 128890, 1], [128986, 128991, 1], [129004, 129007, 1], [129009, 129023, 1], [129036, 129039, 1], [129096, 129103, 1], [129114, 129119, 1], [129160, 129167, 1], [129198, 129199, 1], [129202, 129279, 1], [129620, 129631, 1], [129646, 129647, 1], [129661, 129663, 1], [129673, 129679, 1], [129726, 129734, 8], [129735, 129741, 1], [129756, 129759, 1], [129769, 129775, 1], [129785, 129791, 1], [129939, 129995, 56], [129996, 130031, 1], [130042, 131071, 1], [173792, 173823, 1], [177978, 177983, 1], [178206, 178207, 1], [183970, 183983, 1], [191457, 191471, 1], [192094, 194559, 1], [195102, 196607, 1], [201547, 201551, 1], [205744, 917759, 1], [918000, 1114111, 1]];
static Cc = [[0, 31, 1], [127, 159, 1]];
static Cf = [[173, 1536, 1363], [1537, 1541, 1], [1564, 1757, 193], [1807, 2192, 385], [2193, 2274, 81], [6158, 8203, 2045], [8204, 8207, 1], [8234, 8238, 1], [8288, 8292, 1], [8294, 8303, 1], [65279, 65529, 250], [65530, 65531, 1], [69821, 69837, 16], [78896, 78911, 1], [113824, 113827, 1], [119155, 119162, 1], [917505, 917536, 31], [917537, 917631, 1]];
static Co = [[57344, 63743, 1], [983040, 1048573, 1], [1048576, 1114109, 1]];
static Cs = [[55296, 57343, 1]];
static L = [[65, 90, 1], [97, 122, 1], [170, 181, 11], [186, 192, 6], [193, 214, 1], [216, 246, 1], [248, 705, 1], [710, 721, 1], [736, 740, 1], [748, 750, 2], [880, 884, 1], [886, 887, 1], [890, 893, 1], [895, 902, 7], [904, 906, 1], [908, 910, 2], [911, 929, 1], [931, 1013, 1], [1015, 1153, 1], [1162, 1327, 1], [1329, 1366, 1], [1369, 1376, 7], [1377, 1416, 1], [1488, 1514, 1], [1519, 1522, 1], [1568, 1610, 1], [1646, 1647, 1], [1649, 1747, 1], [1749, 1765, 16], [1766, 1774, 8], [1775, 1786, 11], [1787, 1788, 1], [1791, 1808, 17], [1810, 1839, 1], [1869, 1957, 1], [1969, 1994, 25], [1995, 2026, 1], [2036, 2037, 1], [2042, 2048, 6], [2049, 2069, 1], [2074, 2084, 10], [2088, 2112, 24], [2113, 2136, 1], [2144, 2154, 1], [2160, 2183, 1], [2185, 2190, 1], [2208, 2249, 1], [2308, 2361, 1], [2365, 2384, 19], [2392, 2401, 1], [2417, 2432, 1], [2437, 2444, 1], [2447, 2448, 1], [2451, 2472, 1], [2474, 2480, 1], [2482, 2486, 4], [2487, 2489, 1], [2493, 2510, 17], [2524, 2525, 1], [2527, 2529, 1], [2544, 2545, 1], [2556, 2565, 9], [2566, 2570, 1], [2575, 2576, 1], [2579, 2600, 1], [2602, 2608, 1], [2610, 2611, 1], [2613, 2614, 1], [2616, 2617, 1], [2649, 2652, 1], [2654, 2674, 20], [2675, 2676, 1], [2693, 2701, 1], [2703, 2705, 1], [2707, 2728, 1], [2730, 2736, 1], [2738, 2739, 1], [2741, 2745, 1], [2749, 2768, 19], [2784, 2785, 1], [2809, 2821, 12], [2822, 2828, 1], [2831, 2832, 1], [2835, 2856, 1], [2858, 2864, 1], [2866, 2867, 1], [2869, 2873, 1], [2877, 2908, 31], [2909, 2911, 2], [2912, 2913, 1], [2929, 2947, 18], [2949, 2954, 1], [2958, 2960, 1], [2962, 2965, 1], [2969, 2970, 1], [2972, 2974, 2], [2975, 2979, 4], [2980, 2984, 4], [2985, 2986, 1], [2990, 3001, 1], [3024, 3077, 53], [3078, 3084, 1], [3086, 3088, 1], [3090, 3112, 1], [3114, 3129, 1], [3133, 3160, 27], [3161, 3162, 1], [3165, 3168, 3], [3169, 3200, 31], [3205, 3212, 1], [3214, 3216, 1], [3218, 3240, 1], [3242, 3251, 1], [3253, 3257, 1], [3261, 3293, 32], [3294, 3296, 2], [3297, 3313, 16], [3314, 3332, 18], [3333, 3340, 1], [3342, 3344, 1], [3346, 3386, 1], [3389, 3406, 17], [3412, 3414, 1], [3423, 3425, 1], [3450, 3455, 1], [3461, 3478, 1], [3482, 3505, 1], [3507, 3515, 1], [3517, 3520, 3], [3521, 3526, 1], [3585, 3632, 1], [3634, 3635, 1], [3648, 3654, 1], [3713, 3714, 1], [3716, 3718, 2], [3719, 3722, 1], [3724, 3747, 1], [3749, 3751, 2], [3752, 3760, 1], [3762, 3763, 1], [3773, 3776, 3], [3777, 3780, 1], [3782, 3804, 22], [3805, 3807, 1], [3840, 3904, 64], [3905, 3911, 1], [3913, 3948, 1], [3976, 3980, 1], [4096, 4138, 1], [4159, 4176, 17], [4177, 4181, 1], [4186, 4189, 1], [4193, 4197, 4], [4198, 4206, 8], [4207, 4208, 1], [4213, 4225, 1], [4238, 4256, 18], [4257, 4293, 1], [4295, 4301, 6], [4304, 4346, 1], [4348, 4680, 1], [4682, 4685, 1], [4688, 4694, 1], [4696, 4698, 2], [4699, 4701, 1], [4704, 4744, 1], [4746, 4749, 1], [4752, 4784, 1], [4786, 4789, 1], [4792, 4798, 1], [4800, 4802, 2], [4803, 4805, 1], [4808, 4822, 1], [4824, 4880, 1], [4882, 4885, 1], [4888, 4954, 1], [4992, 5007, 1], [5024, 5109, 1], [5112, 5117, 1], [5121, 5740, 1], [5743, 5759, 1], [5761, 5786, 1], [5792, 5866, 1], [5873, 5880, 1], [5888, 5905, 1], [5919, 5937, 1], [5952, 5969, 1], [5984, 5996, 1], [5998, 6000, 1], [6016, 6067, 1], [6103, 6108, 5], [6176, 6264, 1], [6272, 6276, 1], [6279, 6312, 1], [6314, 6320, 6], [6321, 6389, 1], [6400, 6430, 1], [6480, 6509, 1], [6512, 6516, 1], [6528, 6571, 1], [6576, 6601, 1], [6656, 6678, 1], [6688, 6740, 1], [6823, 6917, 94], [6918, 6963, 1], [6981, 6988, 1], [7043, 7072, 1], [7086, 7087, 1], [7098, 7141, 1], [7168, 7203, 1], [7245, 7247, 1], [7258, 7293, 1], [7296, 7304, 1], [7312, 7354, 1], [7357, 7359, 1], [7401, 7404, 1], [7406, 7411, 1], [7413, 7414, 1], [7418, 7424, 6], [7425, 7615, 1], [7680, 7957, 1], [7960, 7965, 1], [7968, 8005, 1], [8008, 8013, 1], [8016, 8023, 1], [8025, 8031, 2], [8032, 8061, 1], [8064, 8116, 1], [8118, 8124, 1], [8126, 8130, 4], [8131, 8132, 1], [8134, 8140, 1], [8144, 8147, 1], [8150, 8155, 1], [8160, 8172, 1], [8178, 8180, 1], [8182, 8188, 1], [8305, 8319, 14], [8336, 8348, 1], [8450, 8455, 5], [8458, 8467, 1], [8469, 8473, 4], [8474, 8477, 1], [8484, 8490, 2], [8491, 8493, 1], [8495, 8505, 1], [8508, 8511, 1], [8517, 8521, 1], [8526, 8579, 53], [8580, 11264, 2684], [11265, 11492, 1], [11499, 11502, 1], [11506, 11507, 1], [11520, 11557, 1], [11559, 11565, 6], [11568, 11623, 1], [11631, 11648, 17], [11649, 11670, 1], [11680, 11686, 1], [11688, 11694, 1], [11696, 11702, 1], [11704, 11710, 1], [11712, 11718, 1], [11720, 11726, 1], [11728, 11734, 1], [11736, 11742, 1], [11823, 12293, 470], [12294, 12337, 43], [12338, 12341, 1], [12347, 12348, 1], [12353, 12438, 1], [12445, 12447, 1], [12449, 12538, 1], [12540, 12543, 1], [12549, 12591, 1], [12593, 12686, 1], [12704, 12735, 1], [12784, 12799, 1], [13312, 19903, 1], [19968, 42124, 1], [42192, 42237, 1], [42240, 42508, 1], [42512, 42527, 1], [42538, 42539, 1], [42560, 42606, 1], [42623, 42653, 1], [42656, 42725, 1], [42775, 42783, 1], [42786, 42888, 1], [42891, 42954, 1], [42960, 42961, 1], [42963, 42965, 2], [42966, 42969, 1], [42994, 43009, 1], [43011, 43013, 1], [43015, 43018, 1], [43020, 43042, 1], [43072, 43123, 1], [43138, 43187, 1], [43250, 43255, 1], [43259, 43261, 2], [43262, 43274, 12], [43275, 43301, 1], [43312, 43334, 1], [43360, 43388, 1], [43396, 43442, 1], [43471, 43488, 17], [43489, 43492, 1], [43494, 43503, 1], [43514, 43518, 1], [43520, 43560, 1], [43584, 43586, 1], [43588, 43595, 1], [43616, 43638, 1], [43642, 43646, 4], [43647, 43695, 1], [43697, 43701, 4], [43702, 43705, 3], [43706, 43709, 1], [43712, 43714, 2], [43739, 43741, 1], [43744, 43754, 1], [43762, 43764, 1], [43777, 43782, 1], [43785, 43790, 1], [43793, 43798, 1], [43808, 43814, 1], [43816, 43822, 1], [43824, 43866, 1], [43868, 43881, 1], [43888, 44002, 1], [44032, 55203, 1], [55216, 55238, 1], [55243, 55291, 1], [63744, 64109, 1], [64112, 64217, 1], [64256, 64262, 1], [64275, 64279, 1], [64285, 64287, 2], [64288, 64296, 1], [64298, 64310, 1], [64312, 64316, 1], [64318, 64320, 2], [64321, 64323, 2], [64324, 64326, 2], [64327, 64433, 1], [64467, 64829, 1], [64848, 64911, 1], [64914, 64967, 1], [65008, 65019, 1], [65136, 65140, 1], [65142, 65276, 1], [65313, 65338, 1], [65345, 65370, 1], [65382, 65470, 1], [65474, 65479, 1], [65482, 65487, 1], [65490, 65495, 1], [65498, 65500, 1], [65536, 65547, 1], [65549, 65574, 1], [65576, 65594, 1], [65596, 65597, 1], [65599, 65613, 1], [65616, 65629, 1], [65664, 65786, 1], [66176, 66204, 1], [66208, 66256, 1], [66304, 66335, 1], [66349, 66368, 1], [66370, 66377, 1], [66384, 66421, 1], [66432, 66461, 1], [66464, 66499, 1], [66504, 66511, 1], [66560, 66717, 1], [66736, 66771, 1], [66776, 66811, 1], [66816, 66855, 1], [66864, 66915, 1], [66928, 66938, 1], [66940, 66954, 1], [66956, 66962, 1], [66964, 66965, 1], [66967, 66977, 1], [66979, 66993, 1], [66995, 67001, 1], [67003, 67004, 1], [67072, 67382, 1], [67392, 67413, 1], [67424, 67431, 1], [67456, 67461, 1], [67463, 67504, 1], [67506, 67514, 1], [67584, 67589, 1], [67592, 67594, 2], [67595, 67637, 1], [67639, 67640, 1], [67644, 67647, 3], [67648, 67669, 1], [67680, 67702, 1], [67712, 67742, 1], [67808, 67826, 1], [67828, 67829, 1], [67840, 67861, 1], [67872, 67897, 1], [67968, 68023, 1], [68030, 68031, 1], [68096, 68112, 16], [68113, 68115, 1], [68117, 68119, 1], [68121, 68149, 1], [68192, 68220, 1], [68224, 68252, 1], [68288, 68295, 1], [68297, 68324, 1], [68352, 68405, 1], [68416, 68437, 1], [68448, 68466, 1], [68480, 68497, 1], [68608, 68680, 1], [68736, 68786, 1], [68800, 68850, 1], [68864, 68899, 1], [69248, 69289, 1], [69296, 69297, 1], [69376, 69404, 1], [69415, 69424, 9], [69425, 69445, 1], [69488, 69505, 1], [69552, 69572, 1], [69600, 69622, 1], [69635, 69687, 1], [69745, 69746, 1], [69749, 69763, 14], [69764, 69807, 1], [69840, 69864, 1], [69891, 69926, 1], [69956, 69959, 3], [69968, 70002, 1], [70006, 70019, 13], [70020, 70066, 1], [70081, 70084, 1], [70106, 70108, 2], [70144, 70161, 1], [70163, 70187, 1], [70207, 70208, 1], [70272, 70278, 1], [70280, 70282, 2], [70283, 70285, 1], [70287, 70301, 1], [70303, 70312, 1], [70320, 70366, 1], [70405, 70412, 1], [70415, 70416, 1], [70419, 70440, 1], [70442, 70448, 1], [70450, 70451, 1], [70453, 70457, 1], [70461, 70480, 19], [70493, 70497, 1], [70656, 70708, 1], [70727, 70730, 1], [70751, 70753, 1], [70784, 70831, 1], [70852, 70853, 1], [70855, 71040, 185], [71041, 71086, 1], [71128, 71131, 1], [71168, 71215, 1], [71236, 71296, 60], [71297, 71338, 1], [71352, 71424, 72], [71425, 71450, 1], [71488, 71494, 1], [71680, 71723, 1], [71840, 71903, 1], [71935, 71942, 1], [71945, 71948, 3], [71949, 71955, 1], [71957, 71958, 1], [71960, 71983, 1], [71999, 72001, 2], [72096, 72103, 1], [72106, 72144, 1], [72161, 72163, 2], [72192, 72203, 11], [72204, 72242, 1], [72250, 72272, 22], [72284, 72329, 1], [72349, 72368, 19], [72369, 72440, 1], [72704, 72712, 1], [72714, 72750, 1], [72768, 72818, 50], [72819, 72847, 1], [72960, 72966, 1], [72968, 72969, 1], [72971, 73008, 1], [73030, 73056, 26], [73057, 73061, 1], [73063, 73064, 1], [73066, 73097, 1], [73112, 73440, 328], [73441, 73458, 1], [73474, 73476, 2], [73477, 73488, 1], [73490, 73523, 1], [73648, 73728, 80], [73729, 74649, 1], [74880, 75075, 1], [77712, 77808, 1], [77824, 78895, 1], [78913, 78918, 1], [82944, 83526, 1], [92160, 92728, 1], [92736, 92766, 1], [92784, 92862, 1], [92880, 92909, 1], [92928, 92975, 1], [92992, 92995, 1], [93027, 93047, 1], [93053, 93071, 1], [93760, 93823, 1], [93952, 94026, 1], [94032, 94099, 67], [94100, 94111, 1], [94176, 94177, 1], [94179, 94208, 29], [94209, 100343, 1], [100352, 101589, 1], [101632, 101640, 1], [110576, 110579, 1], [110581, 110587, 1], [110589, 110590, 1], [110592, 110882, 1], [110898, 110928, 30], [110929, 110930, 1], [110933, 110948, 15], [110949, 110951, 1], [110960, 111355, 1], [113664, 113770, 1], [113776, 113788, 1], [113792, 113800, 1], [113808, 113817, 1], [119808, 119892, 1], [119894, 119964, 1], [119966, 119967, 1], [119970, 119973, 3], [119974, 119977, 3], [119978, 119980, 1], [119982, 119993, 1], [119995, 119997, 2], [119998, 120003, 1], [120005, 120069, 1], [120071, 120074, 1], [120077, 120084, 1], [120086, 120092, 1], [120094, 120121, 1], [120123, 120126, 1], [120128, 120132, 1], [120134, 120138, 4], [120139, 120144, 1], [120146, 120485, 1], [120488, 120512, 1], [120514, 120538, 1], [120540, 120570, 1], [120572, 120596, 1], [120598, 120628, 1], [120630, 120654, 1], [120656, 120686, 1], [120688, 120712, 1], [120714, 120744, 1], [120746, 120770, 1], [120772, 120779, 1], [122624, 122654, 1], [122661, 122666, 1], [122928, 122989, 1], [123136, 123180, 1], [123191, 123197, 1], [123214, 123536, 322], [123537, 123565, 1], [123584, 123627, 1], [124112, 124139, 1], [124896, 124902, 1], [124904, 124907, 1], [124909, 124910, 1], [124912, 124926, 1], [124928, 125124, 1], [125184, 125251, 1], [125259, 126464, 1205], [126465, 126467, 1], [126469, 126495, 1], [126497, 126498, 1], [126500, 126503, 3], [126505, 126514, 1], [126516, 126519, 1], [126521, 126523, 2], [126530, 126535, 5], [126537, 126541, 2], [126542, 126543, 1], [126545, 126546, 1], [126548, 126551, 3], [126553, 126561, 2], [126562, 126564, 2], [126567, 126570, 1], [126572, 126578, 1], [126580, 126583, 1], [126585, 126588, 1], [126590, 126592, 2], [126593, 126601, 1], [126603, 126619, 1], [126625, 126627, 1], [126629, 126633, 1], [126635, 126651, 1], [131072, 173791, 1], [173824, 177977, 1], [177984, 178205, 1], [178208, 183969, 1], [183984, 191456, 1], [191472, 192093, 1], [194560, 195101, 1], [196608, 201546, 1], [201552, 205743, 1]];
static foldL = [[837, 837, 1]];
static Ll = [[97, 122, 1], [181, 223, 42], [224, 246, 1], [248, 255, 1], [257, 311, 2], [312, 328, 2], [329, 375, 2], [378, 382, 2], [383, 384, 1], [387, 389, 2], [392, 396, 4], [397, 402, 5], [405, 409, 4], [410, 411, 1], [414, 417, 3], [419, 421, 2], [424, 426, 2], [427, 429, 2], [432, 436, 4], [438, 441, 3], [442, 445, 3], [446, 447, 1], [454, 460, 3], [462, 476, 2], [477, 495, 2], [496, 499, 3], [501, 505, 4], [507, 563, 2], [564, 569, 1], [572, 575, 3], [576, 578, 2], [583, 591, 2], [592, 659, 1], [661, 687, 1], [881, 883, 2], [887, 891, 4], [892, 893, 1], [912, 940, 28], [941, 974, 1], [976, 977, 1], [981, 983, 1], [985, 1007, 2], [1008, 1011, 1], [1013, 1019, 3], [1020, 1072, 52], [1073, 1119, 1], [1121, 1153, 2], [1163, 1215, 2], [1218, 1230, 2], [1231, 1327, 2], [1376, 1416, 1], [4304, 4346, 1], [4349, 4351, 1], [5112, 5117, 1], [7296, 7304, 1], [7424, 7467, 1], [7531, 7543, 1], [7545, 7578, 1], [7681, 7829, 2], [7830, 7837, 1], [7839, 7935, 2], [7936, 7943, 1], [7952, 7957, 1], [7968, 7975, 1], [7984, 7991, 1], [8000, 8005, 1], [8016, 8023, 1], [8032, 8039, 1], [8048, 8061, 1], [8064, 8071, 1], [8080, 8087, 1], [8096, 8103, 1], [8112, 8116, 1], [8118, 8119, 1], [8126, 8130, 4], [8131, 8132, 1], [8134, 8135, 1], [8144, 8147, 1], [8150, 8151, 1], [8160, 8167, 1], [8178, 8180, 1], [8182, 8183, 1], [8458, 8462, 4], [8463, 8467, 4], [8495, 8505, 5], [8508, 8509, 1], [8518, 8521, 1], [8526, 8580, 54], [11312, 11359, 1], [11361, 11365, 4], [11366, 11372, 2], [11377, 11379, 2], [11380, 11382, 2], [11383, 11387, 1], [11393, 11491, 2], [11492, 11500, 8], [11502, 11507, 5], [11520, 11557, 1], [11559, 11565, 6], [42561, 42605, 2], [42625, 42651, 2], [42787, 42799, 2], [42800, 42801, 1], [42803, 42865, 2], [42866, 42872, 1], [42874, 42876, 2], [42879, 42887, 2], [42892, 42894, 2], [42897, 42899, 2], [42900, 42901, 1], [42903, 42921, 2], [42927, 42933, 6], [42935, 42947, 2], [42952, 42954, 2], [42961, 42969, 2], [42998, 43002, 4], [43824, 43866, 1], [43872, 43880, 1], [43888, 43967, 1], [64256, 64262, 1], [64275, 64279, 1], [65345, 65370, 1], [66600, 66639, 1], [66776, 66811, 1], [66967, 66977, 1], [66979, 66993, 1], [66995, 67001, 1], [67003, 67004, 1], [68800, 68850, 1], [71872, 71903, 1], [93792, 93823, 1], [119834, 119859, 1], [119886, 119892, 1], [119894, 119911, 1], [119938, 119963, 1], [119990, 119993, 1], [119995, 119997, 2], [119998, 120003, 1], [120005, 120015, 1], [120042, 120067, 1], [120094, 120119, 1], [120146, 120171, 1], [120198, 120223, 1], [120250, 120275, 1], [120302, 120327, 1], [120354, 120379, 1], [120406, 120431, 1], [120458, 120485, 1], [120514, 120538, 1], [120540, 120545, 1], [120572, 120596, 1], [120598, 120603, 1], [120630, 120654, 1], [120656, 120661, 1], [120688, 120712, 1], [120714, 120719, 1], [120746, 120770, 1], [120772, 120777, 1], [120779, 122624, 1845], [122625, 122633, 1], [122635, 122654, 1], [122661, 122666, 1], [125218, 125251, 1]];
static foldLl = [[65, 90, 1], [192, 214, 1], [216, 222, 1], [256, 302, 2], [306, 310, 2], [313, 327, 2], [330, 376, 2], [377, 381, 2], [385, 386, 1], [388, 390, 2], [391, 393, 2], [394, 395, 1], [398, 401, 1], [403, 404, 1], [406, 408, 1], [412, 413, 1], [415, 416, 1], [418, 422, 2], [423, 425, 2], [428, 430, 2], [431, 433, 2], [434, 435, 1], [437, 439, 2], [440, 444, 4], [452, 453, 1], [455, 456, 1], [458, 459, 1], [461, 475, 2], [478, 494, 2], [497, 498, 1], [500, 502, 2], [503, 504, 1], [506, 562, 2], [570, 571, 1], [573, 574, 1], [577, 579, 2], [580, 582, 1], [584, 590, 2], [837, 880, 43], [882, 886, 4], [895, 902, 7], [904, 906, 1], [908, 910, 2], [911, 913, 2], [914, 929, 1], [931, 939, 1], [975, 984, 9], [986, 1006, 2], [1012, 1015, 3], [1017, 1018, 1], [1021, 1071, 1], [1120, 1152, 2], [1162, 1216, 2], [1217, 1229, 2], [1232, 1326, 2], [1329, 1366, 1], [4256, 4293, 1], [4295, 4301, 6], [5024, 5109, 1], [7312, 7354, 1], [7357, 7359, 1], [7680, 7828, 2], [7838, 7934, 2], [7944, 7951, 1], [7960, 7965, 1], [7976, 7983, 1], [7992, 7999, 1], [8008, 8013, 1], [8025, 8031, 2], [8040, 8047, 1], [8072, 8079, 1], [8088, 8095, 1], [8104, 8111, 1], [8120, 8124, 1], [8136, 8140, 1], [8152, 8155, 1], [8168, 8172, 1], [8184, 8188, 1], [8486, 8490, 4], [8491, 8498, 7], [8579, 11264, 2685], [11265, 11311, 1], [11360, 11362, 2], [11363, 11364, 1], [11367, 11373, 2], [11374, 11376, 1], [11378, 11381, 3], [11390, 11392, 1], [11394, 11490, 2], [11499, 11501, 2], [11506, 42560, 31054], [42562, 42604, 2], [42624, 42650, 2], [42786, 42798, 2], [42802, 42862, 2], [42873, 42877, 2], [42878, 42886, 2], [42891, 42893, 2], [42896, 42898, 2], [42902, 42922, 2], [42923, 42926, 1], [42928, 42932, 1], [42934, 42948, 2], [42949, 42951, 1], [42953, 42960, 7], [42966, 42968, 2], [42997, 65313, 22316], [65314, 65338, 1], [66560, 66599, 1], [66736, 66771, 1], [66928, 66938, 1], [66940, 66954, 1], [66956, 66962, 1], [66964, 66965, 1], [68736, 68786, 1], [71840, 71871, 1], [93760, 93791, 1], [125184, 125217, 1]];
static Lm = [[688, 705, 1], [710, 721, 1], [736, 740, 1], [748, 750, 2], [884, 890, 6], [1369, 1600, 231], [1765, 1766, 1], [2036, 2037, 1], [2042, 2074, 32], [2084, 2088, 4], [2249, 2417, 168], [3654, 3782, 128], [4348, 6103, 1755], [6211, 6823, 612], [7288, 7293, 1], [7468, 7530, 1], [7544, 7579, 35], [7580, 7615, 1], [8305, 8319, 14], [8336, 8348, 1], [11388, 11389, 1], [11631, 11823, 192], [12293, 12337, 44], [12338, 12341, 1], [12347, 12445, 98], [12446, 12540, 94], [12541, 12542, 1], [40981, 42232, 1251], [42233, 42237, 1], [42508, 42623, 115], [42652, 42653, 1], [42775, 42783, 1], [42864, 42888, 24], [42994, 42996, 1], [43000, 43001, 1], [43471, 43494, 23], [43632, 43741, 109], [43763, 43764, 1], [43868, 43871, 1], [43881, 65392, 21511], [65438, 65439, 1], [67456, 67461, 1], [67463, 67504, 1], [67506, 67514, 1], [92992, 92995, 1], [94099, 94111, 1], [94176, 94177, 1], [94179, 110576, 16397], [110577, 110579, 1], [110581, 110587, 1], [110589, 110590, 1], [122928, 122989, 1], [123191, 123197, 1], [124139, 125259, 1120]];
static Lo = [[170, 186, 16], [443, 448, 5], [449, 451, 1], [660, 1488, 828], [1489, 1514, 1], [1519, 1522, 1], [1568, 1599, 1], [1601, 1610, 1], [1646, 1647, 1], [1649, 1747, 1], [1749, 1774, 25], [1775, 1786, 11], [1787, 1788, 1], [1791, 1808, 17], [1810, 1839, 1], [1869, 1957, 1], [1969, 1994, 25], [1995, 2026, 1], [2048, 2069, 1], [2112, 2136, 1], [2144, 2154, 1], [2160, 2183, 1], [2185, 2190, 1], [2208, 2248, 1], [2308, 2361, 1], [2365, 2384, 19], [2392, 2401, 1], [2418, 2432, 1], [2437, 2444, 1], [2447, 2448, 1], [2451, 2472, 1], [2474, 2480, 1], [2482, 2486, 4], [2487, 2489, 1], [2493, 2510, 17], [2524, 2525, 1], [2527, 2529, 1], [2544, 2545, 1], [2556, 2565, 9], [2566, 2570, 1], [2575, 2576, 1], [2579, 2600, 1], [2602, 2608, 1], [2610, 2611, 1], [2613, 2614, 1], [2616, 2617, 1], [2649, 2652, 1], [2654, 2674, 20], [2675, 2676, 1], [2693, 2701, 1], [2703, 2705, 1], [2707, 2728, 1], [2730, 2736, 1], [2738, 2739, 1], [2741, 2745, 1], [2749, 2768, 19], [2784, 2785, 1], [2809, 2821, 12], [2822, 2828, 1], [2831, 2832, 1], [2835, 2856, 1], [2858, 2864, 1], [2866, 2867, 1], [2869, 2873, 1], [2877, 2908, 31], [2909, 2911, 2], [2912, 2913, 1], [2929, 2947, 18], [2949, 2954, 1], [2958, 2960, 1], [2962, 2965, 1], [2969, 2970, 1], [2972, 2974, 2], [2975, 2979, 4], [2980, 2984, 4], [2985, 2986, 1], [2990, 3001, 1], [3024, 3077, 53], [3078, 3084, 1], [3086, 3088, 1], [3090, 3112, 1], [3114, 3129, 1], [3133, 3160, 27], [3161, 3162, 1], [3165, 3168, 3], [3169, 3200, 31], [3205, 3212, 1], [3214, 3216, 1], [3218, 3240, 1], [3242, 3251, 1], [3253, 3257, 1], [3261, 3293, 32], [3294, 3296, 2], [3297, 3313, 16], [3314, 3332, 18], [3333, 3340, 1], [3342, 3344, 1], [3346, 3386, 1], [3389, 3406, 17], [3412, 3414, 1], [3423, 3425, 1], [3450, 3455, 1], [3461, 3478, 1], [3482, 3505, 1], [3507, 3515, 1], [3517, 3520, 3], [3521, 3526, 1], [3585, 3632, 1], [3634, 3635, 1], [3648, 3653, 1], [3713, 3714, 1], [3716, 3718, 2], [3719, 3722, 1], [3724, 3747, 1], [3749, 3751, 2], [3752, 3760, 1], [3762, 3763, 1], [3773, 3776, 3], [3777, 3780, 1], [3804, 3807, 1], [3840, 3904, 64], [3905, 3911, 1], [3913, 3948, 1], [3976, 3980, 1], [4096, 4138, 1], [4159, 4176, 17], [4177, 4181, 1], [4186, 4189, 1], [4193, 4197, 4], [4198, 4206, 8], [4207, 4208, 1], [4213, 4225, 1], [4238, 4352, 114], [4353, 4680, 1], [4682, 4685, 1], [4688, 4694, 1], [4696, 4698, 2], [4699, 4701, 1], [4704, 4744, 1], [4746, 4749, 1], [4752, 4784, 1], [4786, 4789, 1], [4792, 4798, 1], [4800, 4802, 2], [4803, 4805, 1], [4808, 4822, 1], [4824, 4880, 1], [4882, 4885, 1], [4888, 4954, 1], [4992, 5007, 1], [5121, 5740, 1], [5743, 5759, 1], [5761, 5786, 1], [5792, 5866, 1], [5873, 5880, 1], [5888, 5905, 1], [5919, 5937, 1], [5952, 5969, 1], [5984, 5996, 1], [5998, 6000, 1], [6016, 6067, 1], [6108, 6176, 68], [6177, 6210, 1], [6212, 6264, 1], [6272, 6276, 1], [6279, 6312, 1], [6314, 6320, 6], [6321, 6389, 1], [6400, 6430, 1], [6480, 6509, 1], [6512, 6516, 1], [6528, 6571, 1], [6576, 6601, 1], [6656, 6678, 1], [6688, 6740, 1], [6917, 6963, 1], [6981, 6988, 1], [7043, 7072, 1], [7086, 7087, 1], [7098, 7141, 1], [7168, 7203, 1], [7245, 7247, 1], [7258, 7287, 1], [7401, 7404, 1], [7406, 7411, 1], [7413, 7414, 1], [7418, 8501, 1083], [8502, 8504, 1], [11568, 11623, 1], [11648, 11670, 1], [11680, 11686, 1], [11688, 11694, 1], [11696, 11702, 1], [11704, 11710, 1], [11712, 11718, 1], [11720, 11726, 1], [11728, 11734, 1], [11736, 11742, 1], [12294, 12348, 54], [12353, 12438, 1], [12447, 12449, 2], [12450, 12538, 1], [12543, 12549, 6], [12550, 12591, 1], [12593, 12686, 1], [12704, 12735, 1], [12784, 12799, 1], [13312, 19903, 1], [19968, 40980, 1], [40982, 42124, 1], [42192, 42231, 1], [42240, 42507, 1], [42512, 42527, 1], [42538, 42539, 1], [42606, 42656, 50], [42657, 42725, 1], [42895, 42999, 104], [43003, 43009, 1], [43011, 43013, 1], [43015, 43018, 1], [43020, 43042, 1], [43072, 43123, 1], [43138, 43187, 1], [43250, 43255, 1], [43259, 43261, 2], [43262, 43274, 12], [43275, 43301, 1], [43312, 43334, 1], [43360, 43388, 1], [43396, 43442, 1], [43488, 43492, 1], [43495, 43503, 1], [43514, 43518, 1], [43520, 43560, 1], [43584, 43586, 1], [43588, 43595, 1], [43616, 43631, 1], [43633, 43638, 1], [43642, 43646, 4], [43647, 43695, 1], [43697, 43701, 4], [43702, 43705, 3], [43706, 43709, 1], [43712, 43714, 2], [43739, 43740, 1], [43744, 43754, 1], [43762, 43777, 15], [43778, 43782, 1], [43785, 43790, 1], [43793, 43798, 1], [43808, 43814, 1], [43816, 43822, 1], [43968, 44002, 1], [44032, 55203, 1], [55216, 55238, 1], [55243, 55291, 1], [63744, 64109, 1], [64112, 64217, 1], [64285, 64287, 2], [64288, 64296, 1], [64298, 64310, 1], [64312, 64316, 1], [64318, 64320, 2], [64321, 64323, 2], [64324, 64326, 2], [64327, 64433, 1], [64467, 64829, 1], [64848, 64911, 1], [64914, 64967, 1], [65008, 65019, 1], [65136, 65140, 1], [65142, 65276, 1], [65382, 65391, 1], [65393, 65437, 1], [65440, 65470, 1], [65474, 65479, 1], [65482, 65487, 1], [65490, 65495, 1], [65498, 65500, 1], [65536, 65547, 1], [65549, 65574, 1], [65576, 65594, 1], [65596, 65597, 1], [65599, 65613, 1], [65616, 65629, 1], [65664, 65786, 1], [66176, 66204, 1], [66208, 66256, 1], [66304, 66335, 1], [66349, 66368, 1], [66370, 66377, 1], [66384, 66421, 1], [66432, 66461, 1], [66464, 66499, 1], [66504, 66511, 1], [66640, 66717, 1], [66816, 66855, 1], [66864, 66915, 1], [67072, 67382, 1], [67392, 67413, 1], [67424, 67431, 1], [67584, 67589, 1], [67592, 67594, 2], [67595, 67637, 1], [67639, 67640, 1], [67644, 67647, 3], [67648, 67669, 1], [67680, 67702, 1], [67712, 67742, 1], [67808, 67826, 1], [67828, 67829, 1], [67840, 67861, 1], [67872, 67897, 1], [67968, 68023, 1], [68030, 68031, 1], [68096, 68112, 16], [68113, 68115, 1], [68117, 68119, 1], [68121, 68149, 1], [68192, 68220, 1], [68224, 68252, 1], [68288, 68295, 1], [68297, 68324, 1], [68352, 68405, 1], [68416, 68437, 1], [68448, 68466, 1], [68480, 68497, 1], [68608, 68680, 1], [68864, 68899, 1], [69248, 69289, 1], [69296, 69297, 1], [69376, 69404, 1], [69415, 69424, 9], [69425, 69445, 1], [69488, 69505, 1], [69552, 69572, 1], [69600, 69622, 1], [69635, 69687, 1], [69745, 69746, 1], [69749, 69763, 14], [69764, 69807, 1], [69840, 69864, 1], [69891, 69926, 1], [69956, 69959, 3], [69968, 70002, 1], [70006, 70019, 13], [70020, 70066, 1], [70081, 70084, 1], [70106, 70108, 2], [70144, 70161, 1], [70163, 70187, 1], [70207, 70208, 1], [70272, 70278, 1], [70280, 70282, 2], [70283, 70285, 1], [70287, 70301, 1], [70303, 70312, 1], [70320, 70366, 1], [70405, 70412, 1], [70415, 70416, 1], [70419, 70440, 1], [70442, 70448, 1], [70450, 70451, 1], [70453, 70457, 1], [70461, 70480, 19], [70493, 70497, 1], [70656, 70708, 1], [70727, 70730, 1], [70751, 70753, 1], [70784, 70831, 1], [70852, 70853, 1], [70855, 71040, 185], [71041, 71086, 1], [71128, 71131, 1], [71168, 71215, 1], [71236, 71296, 60], [71297, 71338, 1], [71352, 71424, 72], [71425, 71450, 1], [71488, 71494, 1], [71680, 71723, 1], [71935, 71942, 1], [71945, 71948, 3], [71949, 71955, 1], [71957, 71958, 1], [71960, 71983, 1], [71999, 72001, 2], [72096, 72103, 1], [72106, 72144, 1], [72161, 72163, 2], [72192, 72203, 11], [72204, 72242, 1], [72250, 72272, 22], [72284, 72329, 1], [72349, 72368, 19], [72369, 72440, 1], [72704, 72712, 1], [72714, 72750, 1], [72768, 72818, 50], [72819, 72847, 1], [72960, 72966, 1], [72968, 72969, 1], [72971, 73008, 1], [73030, 73056, 26], [73057, 73061, 1], [73063, 73064, 1], [73066, 73097, 1], [73112, 73440, 328], [73441, 73458, 1], [73474, 73476, 2], [73477, 73488, 1], [73490, 73523, 1], [73648, 73728, 80], [73729, 74649, 1], [74880, 75075, 1], [77712, 77808, 1], [77824, 78895, 1], [78913, 78918, 1], [82944, 83526, 1], [92160, 92728, 1], [92736, 92766, 1], [92784, 92862, 1], [92880, 92909, 1], [92928, 92975, 1], [93027, 93047, 1], [93053, 93071, 1], [93952, 94026, 1], [94032, 94208, 176], [94209, 100343, 1], [100352, 101589, 1], [101632, 101640, 1], [110592, 110882, 1], [110898, 110928, 30], [110929, 110930, 1], [110933, 110948, 15], [110949, 110951, 1], [110960, 111355, 1], [113664, 113770, 1], [113776, 113788, 1], [113792, 113800, 1], [113808, 113817, 1], [122634, 123136, 502], [123137, 123180, 1], [123214, 123536, 322], [123537, 123565, 1], [123584, 123627, 1], [124112, 124138, 1], [124896, 124902, 1], [124904, 124907, 1], [124909, 124910, 1], [124912, 124926, 1], [124928, 125124, 1], [126464, 126467, 1], [126469, 126495, 1], [126497, 126498, 1], [126500, 126503, 3], [126505, 126514, 1], [126516, 126519, 1], [126521, 126523, 2], [126530, 126535, 5], [126537, 126541, 2], [126542, 126543, 1], [126545, 126546, 1], [126548, 126551, 3], [126553, 126561, 2], [126562, 126564, 2], [126567, 126570, 1], [126572, 126578, 1], [126580, 126583, 1], [126585, 126588, 1], [126590, 126592, 2], [126593, 126601, 1], [126603, 126619, 1], [126625, 126627, 1], [126629, 126633, 1], [126635, 126651, 1], [131072, 173791, 1], [173824, 177977, 1], [177984, 178205, 1], [178208, 183969, 1], [183984, 191456, 1], [191472, 192093, 1], [194560, 195101, 1], [196608, 201546, 1], [201552, 205743, 1]];
static Lt = [[453, 459, 3], [498, 8072, 7574], [8073, 8079, 1], [8088, 8095, 1], [8104, 8111, 1], [8124, 8140, 16], [8188, 8188, 1]];
static foldLt = [[452, 454, 2], [455, 457, 2], [458, 460, 2], [497, 499, 2], [8064, 8071, 1], [8080, 8087, 1], [8096, 8103, 1], [8115, 8131, 16], [8179, 8179, 1]];
static Lu = [[65, 90, 1], [192, 214, 1], [216, 222, 1], [256, 310, 2], [313, 327, 2], [330, 376, 2], [377, 381, 2], [385, 386, 1], [388, 390, 2], [391, 393, 2], [394, 395, 1], [398, 401, 1], [403, 404, 1], [406, 408, 1], [412, 413, 1], [415, 416, 1], [418, 422, 2], [423, 425, 2], [428, 430, 2], [431, 433, 2], [434, 435, 1], [437, 439, 2], [440, 444, 4], [452, 461, 3], [463, 475, 2], [478, 494, 2], [497, 500, 3], [502, 504, 1], [506, 562, 2], [570, 571, 1], [573, 574, 1], [577, 579, 2], [580, 582, 1], [584, 590, 2], [880, 882, 2], [886, 895, 9], [902, 904, 2], [905, 906, 1], [908, 910, 2], [911, 913, 2], [914, 929, 1], [931, 939, 1], [975, 978, 3], [979, 980, 1], [984, 1006, 2], [1012, 1015, 3], [1017, 1018, 1], [1021, 1071, 1], [1120, 1152, 2], [1162, 1216, 2], [1217, 1229, 2], [1232, 1326, 2], [1329, 1366, 1], [4256, 4293, 1], [4295, 4301, 6], [5024, 5109, 1], [7312, 7354, 1], [7357, 7359, 1], [7680, 7828, 2], [7838, 7934, 2], [7944, 7951, 1], [7960, 7965, 1], [7976, 7983, 1], [7992, 7999, 1], [8008, 8013, 1], [8025, 8031, 2], [8040, 8047, 1], [8120, 8123, 1], [8136, 8139, 1], [8152, 8155, 1], [8168, 8172, 1], [8184, 8187, 1], [8450, 8455, 5], [8459, 8461, 1], [8464, 8466, 1], [8469, 8473, 4], [8474, 8477, 1], [8484, 8490, 2], [8491, 8493, 1], [8496, 8499, 1], [8510, 8511, 1], [8517, 8579, 62], [11264, 11311, 1], [11360, 11362, 2], [11363, 11364, 1], [11367, 11373, 2], [11374, 11376, 1], [11378, 11381, 3], [11390, 11392, 1], [11394, 11490, 2], [11499, 11501, 2], [11506, 42560, 31054], [42562, 42604, 2], [42624, 42650, 2], [42786, 42798, 2], [42802, 42862, 2], [42873, 42877, 2], [42878, 42886, 2], [42891, 42893, 2], [42896, 42898, 2], [42902, 42922, 2], [42923, 42926, 1], [42928, 42932, 1], [42934, 42948, 2], [42949, 42951, 1], [42953, 42960, 7], [42966, 42968, 2], [42997, 65313, 22316], [65314, 65338, 1], [66560, 66599, 1], [66736, 66771, 1], [66928, 66938, 1], [66940, 66954, 1], [66956, 66962, 1], [66964, 66965, 1], [68736, 68786, 1], [71840, 71871, 1], [93760, 93791, 1], [119808, 119833, 1], [119860, 119885, 1], [119912, 119937, 1], [119964, 119966, 2], [119967, 119973, 3], [119974, 119977, 3], [119978, 119980, 1], [119982, 119989, 1], [120016, 120041, 1], [120068, 120069, 1], [120071, 120074, 1], [120077, 120084, 1], [120086, 120092, 1], [120120, 120121, 1], [120123, 120126, 1], [120128, 120132, 1], [120134, 120138, 4], [120139, 120144, 1], [120172, 120197, 1], [120224, 120249, 1], [120276, 120301, 1], [120328, 120353, 1], [120380, 120405, 1], [120432, 120457, 1], [120488, 120512, 1], [120546, 120570, 1], [120604, 120628, 1], [120662, 120686, 1], [120720, 120744, 1], [120778, 125184, 4406], [125185, 125217, 1]];
static Upper = this.Lu;
static foldLu = [[97, 122, 1], [181, 223, 42], [224, 246, 1], [248, 255, 1], [257, 303, 2], [307, 311, 2], [314, 328, 2], [331, 375, 2], [378, 382, 2], [383, 384, 1], [387, 389, 2], [392, 396, 4], [402, 405, 3], [409, 410, 1], [414, 417, 3], [419, 421, 2], [424, 429, 5], [432, 436, 4], [438, 441, 3], [445, 447, 2], [453, 454, 1], [456, 457, 1], [459, 460, 1], [462, 476, 2], [477, 495, 2], [498, 499, 1], [501, 505, 4], [507, 543, 2], [547, 563, 2], [572, 575, 3], [576, 578, 2], [583, 591, 2], [592, 596, 1], [598, 599, 1], [601, 603, 2], [604, 608, 4], [609, 613, 2], [614, 616, 2], [617, 620, 1], [623, 625, 2], [626, 629, 3], [637, 640, 3], [642, 643, 1], [647, 652, 1], [658, 669, 11], [670, 837, 167], [881, 883, 2], [887, 891, 4], [892, 893, 1], [940, 943, 1], [945, 974, 1], [976, 977, 1], [981, 983, 1], [985, 1007, 2], [1008, 1011, 1], [1013, 1019, 3], [1072, 1119, 1], [1121, 1153, 2], [1163, 1215, 2], [1218, 1230, 2], [1231, 1327, 2], [1377, 1414, 1], [4304, 4346, 1], [4349, 4351, 1], [5112, 5117, 1], [7296, 7304, 1], [7545, 7549, 4], [7566, 7681, 115], [7683, 7829, 2], [7835, 7841, 6], [7843, 7935, 2], [7936, 7943, 1], [7952, 7957, 1], [7968, 7975, 1], [7984, 7991, 1], [8000, 8005, 1], [8017, 8023, 2], [8032, 8039, 1], [8048, 8061, 1], [8112, 8113, 1], [8126, 8144, 18], [8145, 8160, 15], [8161, 8165, 4], [8526, 8580, 54], [11312, 11359, 1], [11361, 11365, 4], [11366, 11372, 2], [11379, 11382, 3], [11393, 11491, 2], [11500, 11502, 2], [11507, 11520, 13], [11521, 11557, 1], [11559, 11565, 6], [42561, 42605, 2], [42625, 42651, 2], [42787, 42799, 2], [42803, 42863, 2], [42874, 42876, 2], [42879, 42887, 2], [42892, 42897, 5], [42899, 42900, 1], [42903, 42921, 2], [42933, 42947, 2], [42952, 42954, 2], [42961, 42967, 6], [42969, 42998, 29], [43859, 43888, 29], [43889, 43967, 1], [65345, 65370, 1], [66600, 66639, 1], [66776, 66811, 1], [66967, 66977, 1], [66979, 66993, 1], [66995, 67001, 1], [67003, 67004, 1], [68800, 68850, 1], [71872, 71903, 1], [93792, 93823, 1], [125218, 125251, 1]];
static M = [[768, 879, 1], [1155, 1161, 1], [1425, 1469, 1], [1471, 1473, 2], [1474, 1476, 2], [1477, 1479, 2], [1552, 1562, 1], [1611, 1631, 1], [1648, 1750, 102], [1751, 1756, 1], [1759, 1764, 1], [1767, 1768, 1], [1770, 1773, 1], [1809, 1840, 31], [1841, 1866, 1], [1958, 1968, 1], [2027, 2035, 1], [2045, 2070, 25], [2071, 2073, 1], [2075, 2083, 1], [2085, 2087, 1], [2089, 2093, 1], [2137, 2139, 1], [2200, 2207, 1], [2250, 2273, 1], [2275, 2307, 1], [2362, 2364, 1], [2366, 2383, 1], [2385, 2391, 1], [2402, 2403, 1], [2433, 2435, 1], [2492, 2494, 2], [2495, 2500, 1], [2503, 2504, 1], [2507, 2509, 1], [2519, 2530, 11], [2531, 2558, 27], [2561, 2563, 1], [2620, 2622, 2], [2623, 2626, 1], [2631, 2632, 1], [2635, 2637, 1], [2641, 2672, 31], [2673, 2677, 4], [2689, 2691, 1], [2748, 2750, 2], [2751, 2757, 1], [2759, 2761, 1], [2763, 2765, 1], [2786, 2787, 1], [2810, 2815, 1], [2817, 2819, 1], [2876, 2878, 2], [2879, 2884, 1], [2887, 2888, 1], [2891, 2893, 1], [2901, 2903, 1], [2914, 2915, 1], [2946, 3006, 60], [3007, 3010, 1], [3014, 3016, 1], [3018, 3021, 1], [3031, 3072, 41], [3073, 3076, 1], [3132, 3134, 2], [3135, 3140, 1], [3142, 3144, 1], [3146, 3149, 1], [3157, 3158, 1], [3170, 3171, 1], [3201, 3203, 1], [3260, 3262, 2], [3263, 3268, 1], [3270, 3272, 1], [3274, 3277, 1], [3285, 3286, 1], [3298, 3299, 1], [3315, 3328, 13], [3329, 3331, 1], [3387, 3388, 1], [3390, 3396, 1], [3398, 3400, 1], [3402, 3405, 1], [3415, 3426, 11], [3427, 3457, 30], [3458, 3459, 1], [3530, 3535, 5], [3536, 3540, 1], [3542, 3544, 2], [3545, 3551, 1], [3570, 3571, 1], [3633, 3636, 3], [3637, 3642, 1], [3655, 3662, 1], [3761, 3764, 3], [3765, 3772, 1], [3784, 3790, 1], [3864, 3865, 1], [3893, 3897, 2], [3902, 3903, 1], [3953, 3972, 1], [3974, 3975, 1], [3981, 3991, 1], [3993, 4028, 1], [4038, 4139, 101], [4140, 4158, 1], [4182, 4185, 1], [4190, 4192, 1], [4194, 4196, 1], [4199, 4205, 1], [4209, 4212, 1], [4226, 4237, 1], [4239, 4250, 11], [4251, 4253, 1], [4957, 4959, 1], [5906, 5909, 1], [5938, 5940, 1], [5970, 5971, 1], [6002, 6003, 1], [6068, 6099, 1], [6109, 6155, 46], [6156, 6157, 1], [6159, 6277, 118], [6278, 6313, 35], [6432, 6443, 1], [6448, 6459, 1], [6679, 6683, 1], [6741, 6750, 1], [6752, 6780, 1], [6783, 6832, 49], [6833, 6862, 1], [6912, 6916, 1], [6964, 6980, 1], [7019, 7027, 1], [7040, 7042, 1], [7073, 7085, 1], [7142, 7155, 1], [7204, 7223, 1], [7376, 7378, 1], [7380, 7400, 1], [7405, 7412, 7], [7415, 7417, 1], [7616, 7679, 1], [8400, 8432, 1], [11503, 11505, 1], [11647, 11744, 97], [11745, 11775, 1], [12330, 12335, 1], [12441, 12442, 1], [42607, 42610, 1], [42612, 42621, 1], [42654, 42655, 1], [42736, 42737, 1], [43010, 43014, 4], [43019, 43043, 24], [43044, 43047, 1], [43052, 43136, 84], [43137, 43188, 51], [43189, 43205, 1], [43232, 43249, 1], [43263, 43302, 39], [43303, 43309, 1], [43335, 43347, 1], [43392, 43395, 1], [43443, 43456, 1], [43493, 43561, 68], [43562, 43574, 1], [43587, 43596, 9], [43597, 43643, 46], [43644, 43645, 1], [43696, 43698, 2], [43699, 43700, 1], [43703, 43704, 1], [43710, 43711, 1], [43713, 43755, 42], [43756, 43759, 1], [43765, 43766, 1], [44003, 44010, 1], [44012, 44013, 1], [64286, 65024, 738], [65025, 65039, 1], [65056, 65071, 1], [66045, 66272, 227], [66422, 66426, 1], [68097, 68099, 1], [68101, 68102, 1], [68108, 68111, 1], [68152, 68154, 1], [68159, 68325, 166], [68326, 68900, 574], [68901, 68903, 1], [69291, 69292, 1], [69373, 69375, 1], [69446, 69456, 1], [69506, 69509, 1], [69632, 69634, 1], [69688, 69702, 1], [69744, 69747, 3], [69748, 69759, 11], [69760, 69762, 1], [69808, 69818, 1], [69826, 69888, 62], [69889, 69890, 1], [69927, 69940, 1], [69957, 69958, 1], [70003, 70016, 13], [70017, 70018, 1], [70067, 70080, 1], [70089, 70092, 1], [70094, 70095, 1], [70188, 70199, 1], [70206, 70209, 3], [70367, 70378, 1], [70400, 70403, 1], [70459, 70460, 1], [70462, 70468, 1], [70471, 70472, 1], [70475, 70477, 1], [70487, 70498, 11], [70499, 70502, 3], [70503, 70508, 1], [70512, 70516, 1], [70709, 70726, 1], [70750, 70832, 82], [70833, 70851, 1], [71087, 71093, 1], [71096, 71104, 1], [71132, 71133, 1], [71216, 71232, 1], [71339, 71351, 1], [71453, 71467, 1], [71724, 71738, 1], [71984, 71989, 1], [71991, 71992, 1], [71995, 71998, 1], [72000, 72002, 2], [72003, 72145, 142], [72146, 72151, 1], [72154, 72160, 1], [72164, 72193, 29], [72194, 72202, 1], [72243, 72249, 1], [72251, 72254, 1], [72263, 72273, 10], [72274, 72283, 1], [72330, 72345, 1], [72751, 72758, 1], [72760, 72767, 1], [72850, 72871, 1], [72873, 72886, 1], [73009, 73014, 1], [73018, 73020, 2], [73021, 73023, 2], [73024, 73029, 1], [73031, 73098, 67], [73099, 73102, 1], [73104, 73105, 1], [73107, 73111, 1], [73459, 73462, 1], [73472, 73473, 1], [73475, 73524, 49], [73525, 73530, 1], [73534, 73538, 1], [78912, 78919, 7], [78920, 78933, 1], [92912, 92916, 1], [92976, 92982, 1], [94031, 94033, 2], [94034, 94087, 1], [94095, 94098, 1], [94180, 94192, 12], [94193, 113821, 19628], [113822, 118528, 4706], [118529, 118573, 1], [118576, 118598, 1], [119141, 119145, 1], [119149, 119154, 1], [119163, 119170, 1], [119173, 119179, 1], [119210, 119213, 1], [119362, 119364, 1], [121344, 121398, 1], [121403, 121452, 1], [121461, 121476, 15], [121499, 121503, 1], [121505, 121519, 1], [122880, 122886, 1], [122888, 122904, 1], [122907, 122913, 1], [122915, 122916, 1], [122918, 122922, 1], [123023, 123184, 161], [123185, 123190, 1], [123566, 123628, 62], [123629, 123631, 1], [124140, 124143, 1], [125136, 125142, 1], [125252, 125258, 1], [917760, 917999, 1]];
static foldM = [[921, 953, 32], [8126, 8126, 1]];
static Mc = [[2307, 2363, 56], [2366, 2368, 1], [2377, 2380, 1], [2382, 2383, 1], [2434, 2435, 1], [2494, 2496, 1], [2503, 2504, 1], [2507, 2508, 1], [2519, 2563, 44], [2622, 2624, 1], [2691, 2750, 59], [2751, 2752, 1], [2761, 2763, 2], [2764, 2818, 54], [2819, 2878, 59], [2880, 2887, 7], [2888, 2891, 3], [2892, 2903, 11], [3006, 3007, 1], [3009, 3010, 1], [3014, 3016, 1], [3018, 3020, 1], [3031, 3073, 42], [3074, 3075, 1], [3137, 3140, 1], [3202, 3203, 1], [3262, 3264, 2], [3265, 3268, 1], [3271, 3272, 1], [3274, 3275, 1], [3285, 3286, 1], [3315, 3330, 15], [3331, 3390, 59], [3391, 3392, 1], [3398, 3400, 1], [3402, 3404, 1], [3415, 3458, 43], [3459, 3535, 76], [3536, 3537, 1], [3544, 3551, 1], [3570, 3571, 1], [3902, 3903, 1], [3967, 4139, 172], [4140, 4145, 5], [4152, 4155, 3], [4156, 4182, 26], [4183, 4194, 11], [4195, 4196, 1], [4199, 4205, 1], [4227, 4228, 1], [4231, 4236, 1], [4239, 4250, 11], [4251, 4252, 1], [5909, 5940, 31], [6070, 6078, 8], [6079, 6085, 1], [6087, 6088, 1], [6435, 6438, 1], [6441, 6443, 1], [6448, 6449, 1], [6451, 6456, 1], [6681, 6682, 1], [6741, 6743, 2], [6753, 6755, 2], [6756, 6765, 9], [6766, 6770, 1], [6916, 6965, 49], [6971, 6973, 2], [6974, 6977, 1], [6979, 6980, 1], [7042, 7073, 31], [7078, 7079, 1], [7082, 7143, 61], [7146, 7148, 1], [7150, 7154, 4], [7155, 7204, 49], [7205, 7211, 1], [7220, 7221, 1], [7393, 7415, 22], [12334, 12335, 1], [43043, 43044, 1], [43047, 43136, 89], [43137, 43188, 51], [43189, 43203, 1], [43346, 43347, 1], [43395, 43444, 49], [43445, 43450, 5], [43451, 43454, 3], [43455, 43456, 1], [43567, 43568, 1], [43571, 43572, 1], [43597, 43643, 46], [43645, 43755, 110], [43758, 43759, 1], [43765, 44003, 238], [44004, 44006, 2], [44007, 44009, 2], [44010, 44012, 2], [69632, 69634, 2], [69762, 69808, 46], [69809, 69810, 1], [69815, 69816, 1], [69932, 69957, 25], [69958, 70018, 60], [70067, 70069, 1], [70079, 70080, 1], [70094, 70188, 94], [70189, 70190, 1], [70194, 70195, 1], [70197, 70368, 171], [70369, 70370, 1], [70402, 70403, 1], [70462, 70463, 1], [70465, 70468, 1], [70471, 70472, 1], [70475, 70477, 1], [70487, 70498, 11], [70499, 70709, 210], [70710, 70711, 1], [70720, 70721, 1], [70725, 70832, 107], [70833, 70834, 1], [70841, 70843, 2], [70844, 70846, 1], [70849, 71087, 238], [71088, 71089, 1], [71096, 71099, 1], [71102, 71216, 114], [71217, 71218, 1], [71227, 71228, 1], [71230, 71340, 110], [71342, 71343, 1], [71350, 71456, 106], [71457, 71462, 5], [71724, 71726, 1], [71736, 71984, 248], [71985, 71989, 1], [71991, 71992, 1], [71997, 72000, 3], [72002, 72145, 143], [72146, 72147, 1], [72156, 72159, 1], [72164, 72249, 85], [72279, 72280, 1], [72343, 72751, 408], [72766, 72873, 107], [72881, 72884, 3], [73098, 73102, 1], [73107, 73108, 1], [73110, 73461, 351], [73462, 73475, 13], [73524, 73525, 1], [73534, 73535, 1], [73537, 94033, 20496], [94034, 94087, 1], [94192, 94193, 1], [119141, 119142, 1], [119149, 119154, 1]];
static Me = [[1160, 1161, 1], [6846, 8413, 1567], [8414, 8416, 1], [8418, 8420, 1], [42608, 42610, 1]];
static Mn = [[768, 879, 1], [1155, 1159, 1], [1425, 1469, 1], [1471, 1473, 2], [1474, 1476, 2], [1477, 1479, 2], [1552, 1562, 1], [1611, 1631, 1], [1648, 1750, 102], [1751, 1756, 1], [1759, 1764, 1], [1767, 1768, 1], [1770, 1773, 1], [1809, 1840, 31], [1841, 1866, 1], [1958, 1968, 1], [2027, 2035, 1], [2045, 2070, 25], [2071, 2073, 1], [2075, 2083, 1], [2085, 2087, 1], [2089, 2093, 1], [2137, 2139, 1], [2200, 2207, 1], [2250, 2273, 1], [2275, 2306, 1], [2362, 2364, 2], [2369, 2376, 1], [2381, 2385, 4], [2386, 2391, 1], [2402, 2403, 1], [2433, 2492, 59], [2497, 2500, 1], [2509, 2530, 21], [2531, 2558, 27], [2561, 2562, 1], [2620, 2625, 5], [2626, 2631, 5], [2632, 2635, 3], [2636, 2637, 1], [2641, 2672, 31], [2673, 2677, 4], [2689, 2690, 1], [2748, 2753, 5], [2754, 2757, 1], [2759, 2760, 1], [2765, 2786, 21], [2787, 2810, 23], [2811, 2815, 1], [2817, 2876, 59], [2879, 2881, 2], [2882, 2884, 1], [2893, 2901, 8], [2902, 2914, 12], [2915, 2946, 31], [3008, 3021, 13], [3072, 3076, 4], [3132, 3134, 2], [3135, 3136, 1], [3142, 3144, 1], [3146, 3149, 1], [3157, 3158, 1], [3170, 3171, 1], [3201, 3260, 59], [3263, 3270, 7], [3276, 3277, 1], [3298, 3299, 1], [3328, 3329, 1], [3387, 3388, 1], [3393, 3396, 1], [3405, 3426, 21], [3427, 3457, 30], [3530, 3538, 8], [3539, 3540, 1], [3542, 3633, 91], [3636, 3642, 1], [3655, 3662, 1], [3761, 3764, 3], [3765, 3772, 1], [3784, 3790, 1], [3864, 3865, 1], [3893, 3897, 2], [3953, 3966, 1], [3968, 3972, 1], [3974, 3975, 1], [3981, 3991, 1], [3993, 4028, 1], [4038, 4141, 103], [4142, 4144, 1], [4146, 4151, 1], [4153, 4154, 1], [4157, 4158, 1], [4184, 4185, 1], [4190, 4192, 1], [4209, 4212, 1], [4226, 4229, 3], [4230, 4237, 7], [4253, 4957, 704], [4958, 4959, 1], [5906, 5908, 1], [5938, 5939, 1], [5970, 5971, 1], [6002, 6003, 1], [6068, 6069, 1], [6071, 6077, 1], [6086, 6089, 3], [6090, 6099, 1], [6109, 6155, 46], [6156, 6157, 1], [6159, 6277, 118], [6278, 6313, 35], [6432, 6434, 1], [6439, 6440, 1], [6450, 6457, 7], [6458, 6459, 1], [6679, 6680, 1], [6683, 6742, 59], [6744, 6750, 1], [6752, 6754, 2], [6757, 6764, 1], [6771, 6780, 1], [6783, 6832, 49], [6833, 6845, 1], [6847, 6862, 1], [6912, 6915, 1], [6964, 6966, 2], [6967, 6970, 1], [6972, 6978, 6], [7019, 7027, 1], [7040, 7041, 1], [7074, 7077, 1], [7080, 7081, 1], [7083, 7085, 1], [7142, 7144, 2], [7145, 7149, 4], [7151, 7153, 1], [7212, 7219, 1], [7222, 7223, 1], [7376, 7378, 1], [7380, 7392, 1], [7394, 7400, 1], [7405, 7412, 7], [7416, 7417, 1], [7616, 7679, 1], [8400, 8412, 1], [8417, 8421, 4], [8422, 8432, 1], [11503, 11505, 1], [11647, 11744, 97], [11745, 11775, 1], [12330, 12333, 1], [12441, 12442, 1], [42607, 42612, 5], [42613, 42621, 1], [42654, 42655, 1], [42736, 42737, 1], [43010, 43014, 4], [43019, 43045, 26], [43046, 43052, 6], [43204, 43205, 1], [43232, 43249, 1], [43263, 43302, 39], [43303, 43309, 1], [43335, 43345, 1], [43392, 43394, 1], [43443, 43446, 3], [43447, 43449, 1], [43452, 43453, 1], [43493, 43561, 68], [43562, 43566, 1], [43569, 43570, 1], [43573, 43574, 1], [43587, 43596, 9], [43644, 43696, 52], [43698, 43700, 1], [43703, 43704, 1], [43710, 43711, 1], [43713, 43756, 43], [43757, 43766, 9], [44005, 44008, 3], [44013, 64286, 20273], [65024, 65039, 1], [65056, 65071, 1], [66045, 66272, 227], [66422, 66426, 1], [68097, 68099, 1], [68101, 68102, 1], [68108, 68111, 1], [68152, 68154, 1], [68159, 68325, 166], [68326, 68900, 574], [68901, 68903, 1], [69291, 69292, 1], [69373, 69375, 1], [69446, 69456, 1], [69506, 69509, 1], [69633, 69688, 55], [69689, 69702, 1], [69744, 69747, 3], [69748, 69759, 11], [69760, 69761, 1], [69811, 69814, 1], [69817, 69818, 1], [69826, 69888, 62], [69889, 69890, 1], [69927, 69931, 1], [69933, 69940, 1], [70003, 70016, 13], [70017, 70070, 53], [70071, 70078, 1], [70089, 70092, 1], [70095, 70191, 96], [70192, 70193, 1], [70196, 70198, 2], [70199, 70206, 7], [70209, 70367, 158], [70371, 70378, 1], [70400, 70401, 1], [70459, 70460, 1], [70464, 70502, 38], [70503, 70508, 1], [70512, 70516, 1], [70712, 70719, 1], [70722, 70724, 1], [70726, 70750, 24], [70835, 70840, 1], [70842, 70847, 5], [70848, 70850, 2], [70851, 71090, 239], [71091, 71093, 1], [71100, 71101, 1], [71103, 71104, 1], [71132, 71133, 1], [71219, 71226, 1], [71229, 71231, 2], [71232, 71339, 107], [71341, 71344, 3], [71345, 71349, 1], [71351, 71453, 102], [71454, 71455, 1], [71458, 71461, 1], [71463, 71467, 1], [71727, 71735, 1], [71737, 71738, 1], [71995, 71996, 1], [71998, 72003, 5], [72148, 72151, 1], [72154, 72155, 1], [72160, 72193, 33], [72194, 72202, 1], [72243, 72248, 1], [72251, 72254, 1], [72263, 72273, 10], [72274, 72278, 1], [72281, 72283, 1], [72330, 72342, 1], [72344, 72345, 1], [72752, 72758, 1], [72760, 72765, 1], [72767, 72850, 83], [72851, 72871, 1], [72874, 72880, 1], [72882, 72883, 1], [72885, 72886, 1], [73009, 73014, 1], [73018, 73020, 2], [73021, 73023, 2], [73024, 73029, 1], [73031, 73104, 73], [73105, 73109, 4], [73111, 73459, 348], [73460, 73472, 12], [73473, 73526, 53], [73527, 73530, 1], [73536, 73538, 2], [78912, 78919, 7], [78920, 78933, 1], [92912, 92916, 1], [92976, 92982, 1], [94031, 94095, 64], [94096, 94098, 1], [94180, 113821, 19641], [113822, 118528, 4706], [118529, 118573, 1], [118576, 118598, 1], [119143, 119145, 1], [119163, 119170, 1], [119173, 119179, 1], [119210, 119213, 1], [119362, 119364, 1], [121344, 121398, 1], [121403, 121452, 1], [121461, 121476, 15], [121499, 121503, 1], [121505, 121519, 1], [122880, 122886, 1], [122888, 122904, 1], [122907, 122913, 1], [122915, 122916, 1], [122918, 122922, 1], [123023, 123184, 161], [123185, 123190, 1], [123566, 123628, 62], [123629, 123631, 1], [124140, 124143, 1], [125136, 125142, 1], [125252, 125258, 1], [917760, 917999, 1]];
static foldMn = [[921, 953, 32], [8126, 8126, 1]];
static N = [[48, 57, 1], [178, 179, 1], [185, 188, 3], [189, 190, 1], [1632, 1641, 1], [1776, 1785, 1], [1984, 1993, 1], [2406, 2415, 1], [2534, 2543, 1], [2548, 2553, 1], [2662, 2671, 1], [2790, 2799, 1], [2918, 2927, 1], [2930, 2935, 1], [3046, 3058, 1], [3174, 3183, 1], [3192, 3198, 1], [3302, 3311, 1], [3416, 3422, 1], [3430, 3448, 1], [3558, 3567, 1], [3664, 3673, 1], [3792, 3801, 1], [3872, 3891, 1], [4160, 4169, 1], [4240, 4249, 1], [4969, 4988, 1], [5870, 5872, 1], [6112, 6121, 1], [6128, 6137, 1], [6160, 6169, 1], [6470, 6479, 1], [6608, 6618, 1], [6784, 6793, 1], [6800, 6809, 1], [6992, 7001, 1], [7088, 7097, 1], [7232, 7241, 1], [7248, 7257, 1], [8304, 8308, 4], [8309, 8313, 1], [8320, 8329, 1], [8528, 8578, 1], [8581, 8585, 1], [9312, 9371, 1], [9450, 9471, 1], [10102, 10131, 1], [11517, 12295, 778], [12321, 12329, 1], [12344, 12346, 1], [12690, 12693, 1], [12832, 12841, 1], [12872, 12879, 1], [12881, 12895, 1], [12928, 12937, 1], [12977, 12991, 1], [42528, 42537, 1], [42726, 42735, 1], [43056, 43061, 1], [43216, 43225, 1], [43264, 43273, 1], [43472, 43481, 1], [43504, 43513, 1], [43600, 43609, 1], [44016, 44025, 1], [65296, 65305, 1], [65799, 65843, 1], [65856, 65912, 1], [65930, 65931, 1], [66273, 66299, 1], [66336, 66339, 1], [66369, 66378, 9], [66513, 66517, 1], [66720, 66729, 1], [67672, 67679, 1], [67705, 67711, 1], [67751, 67759, 1], [67835, 67839, 1], [67862, 67867, 1], [68028, 68029, 1], [68032, 68047, 1], [68050, 68095, 1], [68160, 68168, 1], [68221, 68222, 1], [68253, 68255, 1], [68331, 68335, 1], [68440, 68447, 1], [68472, 68479, 1], [68521, 68527, 1], [68858, 68863, 1], [68912, 68921, 1], [69216, 69246, 1], [69405, 69414, 1], [69457, 69460, 1], [69573, 69579, 1], [69714, 69743, 1], [69872, 69881, 1], [69942, 69951, 1], [70096, 70105, 1], [70113, 70132, 1], [70384, 70393, 1], [70736, 70745, 1], [70864, 70873, 1], [71248, 71257, 1], [71360, 71369, 1], [71472, 71483, 1], [71904, 71922, 1], [72016, 72025, 1], [72784, 72812, 1], [73040, 73049, 1], [73120, 73129, 1], [73552, 73561, 1], [73664, 73684, 1], [74752, 74862, 1], [92768, 92777, 1], [92864, 92873, 1], [93008, 93017, 1], [93019, 93025, 1], [93824, 93846, 1], [119488, 119507, 1], [119520, 119539, 1], [119648, 119672, 1], [120782, 120831, 1], [123200, 123209, 1], [123632, 123641, 1], [124144, 124153, 1], [125127, 125135, 1], [125264, 125273, 1], [126065, 126123, 1], [126125, 126127, 1], [126129, 126132, 1], [126209, 126253, 1], [126255, 126269, 1], [127232, 127244, 1], [130032, 130041, 1]];
static Nd = [[48, 57, 1], [1632, 1641, 1], [1776, 1785, 1], [1984, 1993, 1], [2406, 2415, 1], [2534, 2543, 1], [2662, 2671, 1], [2790, 2799, 1], [2918, 2927, 1], [3046, 3055, 1], [3174, 3183, 1], [3302, 3311, 1], [3430, 3439, 1], [3558, 3567, 1], [3664, 3673, 1], [3792, 3801, 1], [3872, 3881, 1], [4160, 4169, 1], [4240, 4249, 1], [6112, 6121, 1], [6160, 6169, 1], [6470, 6479, 1], [6608, 6617, 1], [6784, 6793, 1], [6800, 6809, 1], [6992, 7001, 1], [7088, 7097, 1], [7232, 7241, 1], [7248, 7257, 1], [42528, 42537, 1], [43216, 43225, 1], [43264, 43273, 1], [43472, 43481, 1], [43504, 43513, 1], [43600, 43609, 1], [44016, 44025, 1], [65296, 65305, 1], [66720, 66729, 1], [68912, 68921, 1], [69734, 69743, 1], [69872, 69881, 1], [69942, 69951, 1], [70096, 70105, 1], [70384, 70393, 1], [70736, 70745, 1], [70864, 70873, 1], [71248, 71257, 1], [71360, 71369, 1], [71472, 71481, 1], [71904, 71913, 1], [72016, 72025, 1], [72784, 72793, 1], [73040, 73049, 1], [73120, 73129, 1], [73552, 73561, 1], [92768, 92777, 1], [92864, 92873, 1], [93008, 93017, 1], [120782, 120831, 1], [123200, 123209, 1], [123632, 123641, 1], [124144, 124153, 1], [125264, 125273, 1], [130032, 130041, 1]];
static Nl = [[5870, 5872, 1], [8544, 8578, 1], [8581, 8584, 1], [12295, 12321, 26], [12322, 12329, 1], [12344, 12346, 1], [42726, 42735, 1], [65856, 65908, 1], [66369, 66378, 9], [66513, 66517, 1], [74752, 74862, 1]];
static No = [[178, 179, 1], [185, 188, 3], [189, 190, 1], [2548, 2553, 1], [2930, 2935, 1], [3056, 3058, 1], [3192, 3198, 1], [3416, 3422, 1], [3440, 3448, 1], [3882, 3891, 1], [4969, 4988, 1], [6128, 6137, 1], [6618, 8304, 1686], [8308, 8313, 1], [8320, 8329, 1], [8528, 8543, 1], [8585, 9312, 727], [9313, 9371, 1], [9450, 9471, 1], [10102, 10131, 1], [11517, 12690, 1173], [12691, 12693, 1], [12832, 12841, 1], [12872, 12879, 1], [12881, 12895, 1], [12928, 12937, 1], [12977, 12991, 1], [43056, 43061, 1], [65799, 65843, 1], [65909, 65912, 1], [65930, 65931, 1], [66273, 66299, 1], [66336, 66339, 1], [67672, 67679, 1], [67705, 67711, 1], [67751, 67759, 1], [67835, 67839, 1], [67862, 67867, 1], [68028, 68029, 1], [68032, 68047, 1], [68050, 68095, 1], [68160, 68168, 1], [68221, 68222, 1], [68253, 68255, 1], [68331, 68335, 1], [68440, 68447, 1], [68472, 68479, 1], [68521, 68527, 1], [68858, 68863, 1], [69216, 69246, 1], [69405, 69414, 1], [69457, 69460, 1], [69573, 69579, 1], [69714, 69733, 1], [70113, 70132, 1], [71482, 71483, 1], [71914, 71922, 1], [72794, 72812, 1], [73664, 73684, 1], [93019, 93025, 1], [93824, 93846, 1], [119488, 119507, 1], [119520, 119539, 1], [119648, 119672, 1], [125127, 125135, 1], [126065, 126123, 1], [126125, 126127, 1], [126129, 126132, 1], [126209, 126253, 1], [126255, 126269, 1], [127232, 127244, 1]];
static P = [[33, 35, 1], [37, 42, 1], [44, 47, 1], [58, 59, 1], [63, 64, 1], [91, 93, 1], [95, 123, 28], [125, 161, 36], [167, 171, 4], [182, 183, 1], [187, 191, 4], [894, 903, 9], [1370, 1375, 1], [1417, 1418, 1], [1470, 1472, 2], [1475, 1478, 3], [1523, 1524, 1], [1545, 1546, 1], [1548, 1549, 1], [1563, 1565, 2], [1566, 1567, 1], [1642, 1645, 1], [1748, 1792, 44], [1793, 1805, 1], [2039, 2041, 1], [2096, 2110, 1], [2142, 2404, 262], [2405, 2416, 11], [2557, 2678, 121], [2800, 3191, 391], [3204, 3572, 368], [3663, 3674, 11], [3675, 3844, 169], [3845, 3858, 1], [3860, 3898, 38], [3899, 3901, 1], [3973, 4048, 75], [4049, 4052, 1], [4057, 4058, 1], [4170, 4175, 1], [4347, 4960, 613], [4961, 4968, 1], [5120, 5742, 622], [5787, 5788, 1], [5867, 5869, 1], [5941, 5942, 1], [6100, 6102, 1], [6104, 6106, 1], [6144, 6154, 1], [6468, 6469, 1], [6686, 6687, 1], [6816, 6822, 1], [6824, 6829, 1], [7002, 7008, 1], [7037, 7038, 1], [7164, 7167, 1], [7227, 7231, 1], [7294, 7295, 1], [7360, 7367, 1], [7379, 8208, 829], [8209, 8231, 1], [8240, 8259, 1], [8261, 8273, 1], [8275, 8286, 1], [8317, 8318, 1], [8333, 8334, 1], [8968, 8971, 1], [9001, 9002, 1], [10088, 10101, 1], [10181, 10182, 1], [10214, 10223, 1], [10627, 10648, 1], [10712, 10715, 1], [10748, 10749, 1], [11513, 11516, 1], [11518, 11519, 1], [11632, 11776, 144], [11777, 11822, 1], [11824, 11855, 1], [11858, 11869, 1], [12289, 12291, 1], [12296, 12305, 1], [12308, 12319, 1], [12336, 12349, 13], [12448, 12539, 91], [42238, 42239, 1], [42509, 42511, 1], [42611, 42622, 11], [42738, 42743, 1], [43124, 43127, 1], [43214, 43215, 1], [43256, 43258, 1], [43260, 43310, 50], [43311, 43359, 48], [43457, 43469, 1], [43486, 43487, 1], [43612, 43615, 1], [43742, 43743, 1], [43760, 43761, 1], [44011, 64830, 20819], [64831, 65040, 209], [65041, 65049, 1], [65072, 65106, 1], [65108, 65121, 1], [65123, 65128, 5], [65130, 65131, 1], [65281, 65283, 1], [65285, 65290, 1], [65292, 65295, 1], [65306, 65307, 1], [65311, 65312, 1], [65339, 65341, 1], [65343, 65371, 28], [65373, 65375, 2], [65376, 65381, 1], [65792, 65794, 1], [66463, 66512, 49], [66927, 67671, 744], [67871, 67903, 32], [68176, 68184, 1], [68223, 68336, 113], [68337, 68342, 1], [68409, 68415, 1], [68505, 68508, 1], [69293, 69461, 168], [69462, 69465, 1], [69510, 69513, 1], [69703, 69709, 1], [69819, 69820, 1], [69822, 69825, 1], [69952, 69955, 1], [70004, 70005, 1], [70085, 70088, 1], [70093, 70107, 14], [70109, 70111, 1], [70200, 70205, 1], [70313, 70731, 418], [70732, 70735, 1], [70746, 70747, 1], [70749, 70854, 105], [71105, 71127, 1], [71233, 71235, 1], [71264, 71276, 1], [71353, 71484, 131], [71485, 71486, 1], [71739, 72004, 265], [72005, 72006, 1], [72162, 72255, 93], [72256, 72262, 1], [72346, 72348, 1], [72350, 72354, 1], [72448, 72457, 1], [72769, 72773, 1], [72816, 72817, 1], [73463, 73464, 1], [73539, 73551, 1], [73727, 74864, 1137], [74865, 74868, 1], [77809, 77810, 1], [92782, 92783, 1], [92917, 92983, 66], [92984, 92987, 1], [92996, 93847, 851], [93848, 93850, 1], [94178, 113823, 19645], [121479, 121483, 1], [125278, 125279, 1]];
static Pc = [[95, 8255, 8160], [8256, 8276, 20], [65075, 65076, 1], [65101, 65103, 1], [65343, 65343, 1]];
static Pd = [[45, 1418, 1373], [1470, 5120, 3650], [6150, 8208, 2058], [8209, 8213, 1], [11799, 11802, 3], [11834, 11835, 1], [11840, 11869, 29], [12316, 12336, 20], [12448, 65073, 52625], [65074, 65112, 38], [65123, 65293, 170], [69293, 69293, 1]];
static Pe = [[41, 93, 52], [125, 3899, 3774], [3901, 5788, 1887], [8262, 8318, 56], [8334, 8969, 635], [8971, 9002, 31], [10089, 10101, 2], [10182, 10215, 33], [10217, 10223, 2], [10628, 10648, 2], [10713, 10715, 2], [10749, 11811, 1062], [11813, 11817, 2], [11862, 11868, 2], [12297, 12305, 2], [12309, 12315, 2], [12318, 12319, 1], [64830, 65048, 218], [65078, 65092, 2], [65096, 65114, 18], [65116, 65118, 2], [65289, 65341, 52], [65373, 65379, 3]];
static Pf = [[187, 8217, 8030], [8221, 8250, 29], [11779, 11781, 2], [11786, 11789, 3], [11805, 11809, 4]];
static Pi = [[171, 8216, 8045], [8219, 8220, 1], [8223, 8249, 26], [11778, 11780, 2], [11785, 11788, 3], [11804, 11808, 4]];
static Po = [[33, 35, 1], [37, 39, 1], [42, 46, 2], [47, 58, 11], [59, 63, 4], [64, 92, 28], [161, 167, 6], [182, 183, 1], [191, 894, 703], [903, 1370, 467], [1371, 1375, 1], [1417, 1472, 55], [1475, 1478, 3], [1523, 1524, 1], [1545, 1546, 1], [1548, 1549, 1], [1563, 1565, 2], [1566, 1567, 1], [1642, 1645, 1], [1748, 1792, 44], [1793, 1805, 1], [2039, 2041, 1], [2096, 2110, 1], [2142, 2404, 262], [2405, 2416, 11], [2557, 2678, 121], [2800, 3191, 391], [3204, 3572, 368], [3663, 3674, 11], [3675, 3844, 169], [3845, 3858, 1], [3860, 3973, 113], [4048, 4052, 1], [4057, 4058, 1], [4170, 4175, 1], [4347, 4960, 613], [4961, 4968, 1], [5742, 5867, 125], [5868, 5869, 1], [5941, 5942, 1], [6100, 6102, 1], [6104, 6106, 1], [6144, 6149, 1], [6151, 6154, 1], [6468, 6469, 1], [6686, 6687, 1], [6816, 6822, 1], [6824, 6829, 1], [7002, 7008, 1], [7037, 7038, 1], [7164, 7167, 1], [7227, 7231, 1], [7294, 7295, 1], [7360, 7367, 1], [7379, 8214, 835], [8215, 8224, 9], [8225, 8231, 1], [8240, 8248, 1], [8251, 8254, 1], [8257, 8259, 1], [8263, 8273, 1], [8275, 8277, 2], [8278, 8286, 1], [11513, 11516, 1], [11518, 11519, 1], [11632, 11776, 144], [11777, 11782, 5], [11783, 11784, 1], [11787, 11790, 3], [11791, 11798, 1], [11800, 11801, 1], [11803, 11806, 3], [11807, 11818, 11], [11819, 11822, 1], [11824, 11833, 1], [11836, 11839, 1], [11841, 11843, 2], [11844, 11855, 1], [11858, 11860, 1], [12289, 12291, 1], [12349, 12539, 190], [42238, 42239, 1], [42509, 42511, 1], [42611, 42622, 11], [42738, 42743, 1], [43124, 43127, 1], [43214, 43215, 1], [43256, 43258, 1], [43260, 43310, 50], [43311, 43359, 48], [43457, 43469, 1], [43486, 43487, 1], [43612, 43615, 1], [43742, 43743, 1], [43760, 43761, 1], [44011, 65040, 21029], [65041, 65046, 1], [65049, 65072, 23], [65093, 65094, 1], [65097, 65100, 1], [65104, 65106, 1], [65108, 65111, 1], [65119, 65121, 1], [65128, 65130, 2], [65131, 65281, 150], [65282, 65283, 1], [65285, 65287, 1], [65290, 65294, 2], [65295, 65306, 11], [65307, 65311, 4], [65312, 65340, 28], [65377, 65380, 3], [65381, 65792, 411], [65793, 65794, 1], [66463, 66512, 49], [66927, 67671, 744], [67871, 67903, 32], [68176, 68184, 1], [68223, 68336, 113], [68337, 68342, 1], [68409, 68415, 1], [68505, 68508, 1], [69461, 69465, 1], [69510, 69513, 1], [69703, 69709, 1], [69819, 69820, 1], [69822, 69825, 1], [69952, 69955, 1], [70004, 70005, 1], [70085, 70088, 1], [70093, 70107, 14], [70109, 70111, 1], [70200, 70205, 1], [70313, 70731, 418], [70732, 70735, 1], [70746, 70747, 1], [70749, 70854, 105], [71105, 71127, 1], [71233, 71235, 1], [71264, 71276, 1], [71353, 71484, 131], [71485, 71486, 1], [71739, 72004, 265], [72005, 72006, 1], [72162, 72255, 93], [72256, 72262, 1], [72346, 72348, 1], [72350, 72354, 1], [72448, 72457, 1], [72769, 72773, 1], [72816, 72817, 1], [73463, 73464, 1], [73539, 73551, 1], [73727, 74864, 1137], [74865, 74868, 1], [77809, 77810, 1], [92782, 92783, 1], [92917, 92983, 66], [92984, 92987, 1], [92996, 93847, 851], [93848, 93850, 1], [94178, 113823, 19645], [121479, 121483, 1], [125278, 125279, 1]];
static Ps = [[40, 91, 51], [123, 3898, 3775], [3900, 5787, 1887], [8218, 8222, 4], [8261, 8317, 56], [8333, 8968, 635], [8970, 9001, 31], [10088, 10100, 2], [10181, 10214, 33], [10216, 10222, 2], [10627, 10647, 2], [10712, 10714, 2], [10748, 11810, 1062], [11812, 11816, 2], [11842, 11861, 19], [11863, 11867, 2], [12296, 12304, 2], [12308, 12314, 2], [12317, 64831, 52514], [65047, 65077, 30], [65079, 65091, 2], [65095, 65113, 18], [65115, 65117, 2], [65288, 65339, 51], [65371, 65375, 4], [65378, 65378, 1]];
static S = [[36, 43, 7], [60, 62, 1], [94, 96, 2], [124, 126, 2], [162, 166, 1], [168, 169, 1], [172, 174, 2], [175, 177, 1], [180, 184, 4], [215, 247, 32], [706, 709, 1], [722, 735, 1], [741, 747, 1], [749, 751, 2], [752, 767, 1], [885, 900, 15], [901, 1014, 113], [1154, 1421, 267], [1422, 1423, 1], [1542, 1544, 1], [1547, 1550, 3], [1551, 1758, 207], [1769, 1789, 20], [1790, 2038, 248], [2046, 2047, 1], [2184, 2546, 362], [2547, 2554, 7], [2555, 2801, 246], [2928, 3059, 131], [3060, 3066, 1], [3199, 3407, 208], [3449, 3647, 198], [3841, 3843, 1], [3859, 3861, 2], [3862, 3863, 1], [3866, 3871, 1], [3892, 3896, 2], [4030, 4037, 1], [4039, 4044, 1], [4046, 4047, 1], [4053, 4056, 1], [4254, 4255, 1], [5008, 5017, 1], [5741, 6107, 366], [6464, 6622, 158], [6623, 6655, 1], [7009, 7018, 1], [7028, 7036, 1], [8125, 8127, 2], [8128, 8129, 1], [8141, 8143, 1], [8157, 8159, 1], [8173, 8175, 1], [8189, 8190, 1], [8260, 8274, 14], [8314, 8316, 1], [8330, 8332, 1], [8352, 8384, 1], [8448, 8449, 1], [8451, 8454, 1], [8456, 8457, 1], [8468, 8470, 2], [8471, 8472, 1], [8478, 8483, 1], [8485, 8489, 2], [8494, 8506, 12], [8507, 8512, 5], [8513, 8516, 1], [8522, 8525, 1], [8527, 8586, 59], [8587, 8592, 5], [8593, 8967, 1], [8972, 9000, 1], [9003, 9254, 1], [9280, 9290, 1], [9372, 9449, 1], [9472, 10087, 1], [10132, 10180, 1], [10183, 10213, 1], [10224, 10626, 1], [10649, 10711, 1], [10716, 10747, 1], [10750, 11123, 1], [11126, 11157, 1], [11159, 11263, 1], [11493, 11498, 1], [11856, 11857, 1], [11904, 11929, 1], [11931, 12019, 1], [12032, 12245, 1], [12272, 12287, 1], [12292, 12306, 14], [12307, 12320, 13], [12342, 12343, 1], [12350, 12351, 1], [12443, 12444, 1], [12688, 12689, 1], [12694, 12703, 1], [12736, 12771, 1], [12783, 12800, 17], [12801, 12830, 1], [12842, 12871, 1], [12880, 12896, 16], [12897, 12927, 1], [12938, 12976, 1], [12992, 13311, 1], [19904, 19967, 1], [42128, 42182, 1], [42752, 42774, 1], [42784, 42785, 1], [42889, 42890, 1], [43048, 43051, 1], [43062, 43065, 1], [43639, 43641, 1], [43867, 43882, 15], [43883, 64297, 20414], [64434, 64450, 1], [64832, 64847, 1], [64975, 65020, 45], [65021, 65023, 1], [65122, 65124, 2], [65125, 65126, 1], [65129, 65284, 155], [65291, 65308, 17], [65309, 65310, 1], [65342, 65344, 2], [65372, 65374, 2], [65504, 65510, 1], [65512, 65518, 1], [65532, 65533, 1], [65847, 65855, 1], [65913, 65929, 1], [65932, 65934, 1], [65936, 65948, 1], [65952, 66000, 48], [66001, 66044, 1], [67703, 67704, 1], [68296, 71487, 3191], [73685, 73713, 1], [92988, 92991, 1], [92997, 113820, 20823], [118608, 118723, 1], [118784, 119029, 1], [119040, 119078, 1], [119081, 119140, 1], [119146, 119148, 1], [119171, 119172, 1], [119180, 119209, 1], [119214, 119274, 1], [119296, 119361, 1], [119365, 119552, 187], [119553, 119638, 1], [120513, 120539, 26], [120571, 120597, 26], [120629, 120655, 26], [120687, 120713, 26], [120745, 120771, 26], [120832, 121343, 1], [121399, 121402, 1], [121453, 121460, 1], [121462, 121475, 1], [121477, 121478, 1], [123215, 123647, 432], [126124, 126128, 4], [126254, 126704, 450], [126705, 126976, 271], [126977, 127019, 1], [127024, 127123, 1], [127136, 127150, 1], [127153, 127167, 1], [127169, 127183, 1], [127185, 127221, 1], [127245, 127405, 1], [127462, 127490, 1], [127504, 127547, 1], [127552, 127560, 1], [127568, 127569, 1], [127584, 127589, 1], [127744, 128727, 1], [128732, 128748, 1], [128752, 128764, 1], [128768, 128886, 1], [128891, 128985, 1], [128992, 129003, 1], [129008, 129024, 16], [129025, 129035, 1], [129040, 129095, 1], [129104, 129113, 1], [129120, 129159, 1], [129168, 129197, 1], [129200, 129201, 1], [129280, 129619, 1], [129632, 129645, 1], [129648, 129660, 1], [129664, 129672, 1], [129680, 129725, 1], [129727, 129733, 1], [129742, 129755, 1], [129760, 129768, 1], [129776, 129784, 1], [129792, 129938, 1], [129940, 129994, 1]];
static Sc = [[36, 162, 126], [163, 165, 1], [1423, 1547, 124], [2046, 2047, 1], [2546, 2547, 1], [2555, 2801, 246], [3065, 3647, 582], [6107, 8352, 2245], [8353, 8384, 1], [43064, 65020, 21956], [65129, 65284, 155], [65504, 65505, 1], [65509, 65510, 1], [73693, 73696, 1], [123647, 126128, 2481]];
static Sk = [[94, 96, 2], [168, 175, 7], [180, 184, 4], [706, 709, 1], [722, 735, 1], [741, 747, 1], [749, 751, 2], [752, 767, 1], [885, 900, 15], [901, 2184, 1283], [8125, 8127, 2], [8128, 8129, 1], [8141, 8143, 1], [8157, 8159, 1], [8173, 8175, 1], [8189, 8190, 1], [12443, 12444, 1], [42752, 42774, 1], [42784, 42785, 1], [42889, 42890, 1], [43867, 43882, 15], [43883, 64434, 20551], [64435, 64450, 1], [65342, 65344, 2], [65507, 127995, 62488], [127996, 127999, 1]];
static Sm = [[43, 60, 17], [61, 62, 1], [124, 126, 2], [172, 177, 5], [215, 247, 32], [1014, 1542, 528], [1543, 1544, 1], [8260, 8274, 14], [8314, 8316, 1], [8330, 8332, 1], [8472, 8512, 40], [8513, 8516, 1], [8523, 8592, 69], [8593, 8596, 1], [8602, 8603, 1], [8608, 8614, 3], [8622, 8654, 32], [8655, 8658, 3], [8660, 8692, 32], [8693, 8959, 1], [8992, 8993, 1], [9084, 9115, 31], [9116, 9139, 1], [9180, 9185, 1], [9655, 9665, 10], [9720, 9727, 1], [9839, 10176, 337], [10177, 10180, 1], [10183, 10213, 1], [10224, 10239, 1], [10496, 10626, 1], [10649, 10711, 1], [10716, 10747, 1], [10750, 11007, 1], [11056, 11076, 1], [11079, 11084, 1], [64297, 65122, 825], [65124, 65126, 1], [65291, 65308, 17], [65309, 65310, 1], [65372, 65374, 2], [65506, 65513, 7], [65514, 65516, 1], [120513, 120539, 26], [120571, 120597, 26], [120629, 120655, 26], [120687, 120713, 26], [120745, 120771, 26], [126704, 126705, 1]];
static So = [[166, 169, 3], [174, 176, 2], [1154, 1421, 267], [1422, 1550, 128], [1551, 1758, 207], [1769, 1789, 20], [1790, 2038, 248], [2554, 2928, 374], [3059, 3064, 1], [3066, 3199, 133], [3407, 3449, 42], [3841, 3843, 1], [3859, 3861, 2], [3862, 3863, 1], [3866, 3871, 1], [3892, 3896, 2], [4030, 4037, 1], [4039, 4044, 1], [4046, 4047, 1], [4053, 4056, 1], [4254, 4255, 1], [5008, 5017, 1], [5741, 6464, 723], [6622, 6655, 1], [7009, 7018, 1], [7028, 7036, 1], [8448, 8449, 1], [8451, 8454, 1], [8456, 8457, 1], [8468, 8470, 2], [8471, 8478, 7], [8479, 8483, 1], [8485, 8489, 2], [8494, 8506, 12], [8507, 8522, 15], [8524, 8525, 1], [8527, 8586, 59], [8587, 8597, 10], [8598, 8601, 1], [8604, 8607, 1], [8609, 8610, 1], [8612, 8613, 1], [8615, 8621, 1], [8623, 8653, 1], [8656, 8657, 1], [8659, 8661, 2], [8662, 8691, 1], [8960, 8967, 1], [8972, 8991, 1], [8994, 9000, 1], [9003, 9083, 1], [9085, 9114, 1], [9140, 9179, 1], [9186, 9254, 1], [9280, 9290, 1], [9372, 9449, 1], [9472, 9654, 1], [9656, 9664, 1], [9666, 9719, 1], [9728, 9838, 1], [9840, 10087, 1], [10132, 10175, 1], [10240, 10495, 1], [11008, 11055, 1], [11077, 11078, 1], [11085, 11123, 1], [11126, 11157, 1], [11159, 11263, 1], [11493, 11498, 1], [11856, 11857, 1], [11904, 11929, 1], [11931, 12019, 1], [12032, 12245, 1], [12272, 12287, 1], [12292, 12306, 14], [12307, 12320, 13], [12342, 12343, 1], [12350, 12351, 1], [12688, 12689, 1], [12694, 12703, 1], [12736, 12771, 1], [12783, 12800, 17], [12801, 12830, 1], [12842, 12871, 1], [12880, 12896, 16], [12897, 12927, 1], [12938, 12976, 1], [12992, 13311, 1], [19904, 19967, 1], [42128, 42182, 1], [43048, 43051, 1], [43062, 43063, 1], [43065, 43639, 574], [43640, 43641, 1], [64832, 64847, 1], [64975, 65021, 46], [65022, 65023, 1], [65508, 65512, 4], [65517, 65518, 1], [65532, 65533, 1], [65847, 65855, 1], [65913, 65929, 1], [65932, 65934, 1], [65936, 65948, 1], [65952, 66000, 48], [66001, 66044, 1], [67703, 67704, 1], [68296, 71487, 3191], [73685, 73692, 1], [73697, 73713, 1], [92988, 92991, 1], [92997, 113820, 20823], [118608, 118723, 1], [118784, 119029, 1], [119040, 119078, 1], [119081, 119140, 1], [119146, 119148, 1], [119171, 119172, 1], [119180, 119209, 1], [119214, 119274, 1], [119296, 119361, 1], [119365, 119552, 187], [119553, 119638, 1], [120832, 121343, 1], [121399, 121402, 1], [121453, 121460, 1], [121462, 121475, 1], [121477, 121478, 1], [123215, 126124, 2909], [126254, 126976, 722], [126977, 127019, 1], [127024, 127123, 1], [127136, 127150, 1], [127153, 127167, 1], [127169, 127183, 1], [127185, 127221, 1], [127245, 127405, 1], [127462, 127490, 1], [127504, 127547, 1], [127552, 127560, 1], [127568, 127569, 1], [127584, 127589, 1], [127744, 127994, 1], [128000, 128727, 1], [128732, 128748, 1], [128752, 128764, 1], [128768, 128886, 1], [128891, 128985, 1], [128992, 129003, 1], [129008, 129024, 16], [129025, 129035, 1], [129040, 129095, 1], [129104, 129113, 1], [129120, 129159, 1], [129168, 129197, 1], [129200, 129201, 1], [129280, 129619, 1], [129632, 129645, 1], [129648, 129660, 1], [129664, 129672, 1], [129680, 129725, 1], [129727, 129733, 1], [129742, 129755, 1], [129760, 129768, 1], [129776, 129784, 1], [129792, 129938, 1], [129940, 129994, 1]];
static Z = [[32, 160, 128], [5760, 8192, 2432], [8193, 8202, 1], [8232, 8233, 1], [8239, 8287, 48], [12288, 12288, 1]];
static Zl = [[8232, 8232, 1]];
static Zp = [[8233, 8233, 1]];
static Zs = [[32, 160, 128], [5760, 8192, 2432], [8193, 8202, 1], [8239, 8287, 48], [12288, 12288, 1]];
static Adlam = [[125184, 125259, 1], [125264, 125273, 1], [125278, 125279, 1]];
static Ahom = [[71424, 71450, 1], [71453, 71467, 1], [71472, 71494, 1]];
static Anatolian_Hieroglyphs = [[82944, 83526, 1]];
static Arabic = [[1536, 1540, 1], [1542, 1547, 1], [1549, 1562, 1], [1564, 1566, 1], [1568, 1599, 1], [1601, 1610, 1], [1622, 1647, 1], [1649, 1756, 1], [1758, 1791, 1], [1872, 1919, 1], [2160, 2190, 1], [2192, 2193, 1], [2200, 2273, 1], [2275, 2303, 1], [64336, 64450, 1], [64467, 64829, 1], [64832, 64911, 1], [64914, 64967, 1], [64975, 65008, 33], [65009, 65023, 1], [65136, 65140, 1], [65142, 65276, 1], [69216, 69246, 1], [69373, 69375, 1], [126464, 126467, 1], [126469, 126495, 1], [126497, 126498, 1], [126500, 126503, 3], [126505, 126514, 1], [126516, 126519, 1], [126521, 126523, 2], [126530, 126535, 5], [126537, 126541, 2], [126542, 126543, 1], [126545, 126546, 1], [126548, 126551, 3], [126553, 126561, 2], [126562, 126564, 2], [126567, 126570, 1], [126572, 126578, 1], [126580, 126583, 1], [126585, 126588, 1], [126590, 126592, 2], [126593, 126601, 1], [126603, 126619, 1], [126625, 126627, 1], [126629, 126633, 1], [126635, 126651, 1], [126704, 126705, 1]];
static Armenian = [[1329, 1366, 1], [1369, 1418, 1], [1421, 1423, 1], [64275, 64279, 1]];
static Avestan = [[68352, 68405, 1], [68409, 68415, 1]];
static Balinese = [[6912, 6988, 1], [6992, 7038, 1]];
static Bamum = [[42656, 42743, 1], [92160, 92728, 1]];
static Bassa_Vah = [[92880, 92909, 1], [92912, 92917, 1]];
static Batak = [[7104, 7155, 1], [7164, 7167, 1]];
static Bengali = [[2432, 2435, 1], [2437, 2444, 1], [2447, 2448, 1], [2451, 2472, 1], [2474, 2480, 1], [2482, 2486, 4], [2487, 2489, 1], [2492, 2500, 1], [2503, 2504, 1], [2507, 2510, 1], [2519, 2524, 5], [2525, 2527, 2], [2528, 2531, 1], [2534, 2558, 1]];
static Bhaiksuki = [[72704, 72712, 1], [72714, 72758, 1], [72760, 72773, 1], [72784, 72812, 1]];
static Bopomofo = [[746, 747, 1], [12549, 12591, 1], [12704, 12735, 1]];
static Brahmi = [[69632, 69709, 1], [69714, 69749, 1], [69759, 69759, 1]];
static Braille = [[10240, 10495, 1]];
static Buginese = [[6656, 6683, 1], [6686, 6687, 1]];
static Buhid = [[5952, 5971, 1]];
static Canadian_Aboriginal = [[5120, 5759, 1], [6320, 6389, 1], [72368, 72383, 1]];
static Carian = [[66208, 66256, 1]];
static Caucasian_Albanian = [[66864, 66915, 1], [66927, 66927, 1]];
static Chakma = [[69888, 69940, 1], [69942, 69959, 1]];
static Cham = [[43520, 43574, 1], [43584, 43597, 1], [43600, 43609, 1], [43612, 43615, 1]];
static Cherokee = [[5024, 5109, 1], [5112, 5117, 1], [43888, 43967, 1]];
static Chorasmian = [[69552, 69579, 1]];
static Common = [[0, 64, 1], [91, 96, 1], [123, 169, 1], [171, 185, 1], [187, 191, 1], [215, 247, 32], [697, 735, 1], [741, 745, 1], [748, 767, 1], [884, 894, 10], [901, 903, 2], [1541, 1548, 7], [1563, 1567, 4], [1600, 1757, 157], [2274, 2404, 130], [2405, 3647, 1242], [4053, 4056, 1], [4347, 5867, 1520], [5868, 5869, 1], [5941, 5942, 1], [6146, 6147, 1], [6149, 7379, 1230], [7393, 7401, 8], [7402, 7404, 1], [7406, 7411, 1], [7413, 7415, 1], [7418, 8192, 774], [8193, 8203, 1], [8206, 8292, 1], [8294, 8304, 1], [8308, 8318, 1], [8320, 8334, 1], [8352, 8384, 1], [8448, 8485, 1], [8487, 8489, 1], [8492, 8497, 1], [8499, 8525, 1], [8527, 8543, 1], [8585, 8587, 1], [8592, 9254, 1], [9280, 9290, 1], [9312, 10239, 1], [10496, 11123, 1], [11126, 11157, 1], [11159, 11263, 1], [11776, 11869, 1], [12272, 12292, 1], [12294, 12296, 2], [12297, 12320, 1], [12336, 12343, 1], [12348, 12351, 1], [12443, 12444, 1], [12448, 12539, 91], [12540, 12688, 148], [12689, 12703, 1], [12736, 12771, 1], [12783, 12832, 49], [12833, 12895, 1], [12927, 13007, 1], [13055, 13144, 89], [13145, 13311, 1], [19904, 19967, 1], [42752, 42785, 1], [42888, 42890, 1], [43056, 43065, 1], [43310, 43471, 161], [43867, 43882, 15], [43883, 64830, 20947], [64831, 65040, 209], [65041, 65049, 1], [65072, 65106, 1], [65108, 65126, 1], [65128, 65131, 1], [65279, 65281, 2], [65282, 65312, 1], [65339, 65344, 1], [65371, 65381, 1], [65392, 65438, 46], [65439, 65504, 65], [65505, 65510, 1], [65512, 65518, 1], [65529, 65533, 1], [65792, 65794, 1], [65799, 65843, 1], [65847, 65855, 1], [65936, 65948, 1], [66000, 66044, 1], [66273, 66299, 1], [113824, 113827, 1], [118608, 118723, 1], [118784, 119029, 1], [119040, 119078, 1], [119081, 119142, 1], [119146, 119162, 1], [119171, 119172, 1], [119180, 119209, 1], [119214, 119274, 1], [119488, 119507, 1], [119520, 119539, 1], [119552, 119638, 1], [119648, 119672, 1], [119808, 119892, 1], [119894, 119964, 1], [119966, 119967, 1], [119970, 119973, 3], [119974, 119977, 3], [119978, 119980, 1], [119982, 119993, 1], [119995, 119997, 2], [119998, 120003, 1], [120005, 120069, 1], [120071, 120074, 1], [120077, 120084, 1], [120086, 120092, 1], [120094, 120121, 1], [120123, 120126, 1], [120128, 120132, 1], [120134, 120138, 4], [120139, 120144, 1], [120146, 120485, 1], [120488, 120779, 1], [120782, 120831, 1], [126065, 126132, 1], [126209, 126269, 1], [126976, 127019, 1], [127024, 127123, 1], [127136, 127150, 1], [127153, 127167, 1], [127169, 127183, 1], [127185, 127221, 1], [127232, 127405, 1], [127462, 127487, 1], [127489, 127490, 1], [127504, 127547, 1], [127552, 127560, 1], [127568, 127569, 1], [127584, 127589, 1], [127744, 128727, 1], [128732, 128748, 1], [128752, 128764, 1], [128768, 128886, 1], [128891, 128985, 1], [128992, 129003, 1], [129008, 129024, 16], [129025, 129035, 1], [129040, 129095, 1], [129104, 129113, 1], [129120, 129159, 1], [129168, 129197, 1], [129200, 129201, 1], [129280, 129619, 1], [129632, 129645, 1], [129648, 129660, 1], [129664, 129672, 1], [129680, 129725, 1], [129727, 129733, 1], [129742, 129755, 1], [129760, 129768, 1], [129776, 129784, 1], [129792, 129938, 1], [129940, 129994, 1], [130032, 130041, 1], [917505, 917536, 31], [917537, 917631, 1]];
static foldCommon = [[924, 956, 32]];
static Coptic = [[994, 1007, 1], [11392, 11507, 1], [11513, 11519, 1]];
static Cuneiform = [[73728, 74649, 1], [74752, 74862, 1], [74864, 74868, 1], [74880, 75075, 1]];
static Cypriot = [[67584, 67589, 1], [67592, 67594, 2], [67595, 67637, 1], [67639, 67640, 1], [67644, 67647, 3]];
static Cypro_Minoan = [[77712, 77810, 1]];
static Cyrillic = [[1024, 1156, 1], [1159, 1327, 1], [7296, 7304, 1], [7467, 7544, 77], [11744, 11775, 1], [42560, 42655, 1], [65070, 65071, 1], [122928, 122989, 1], [123023, 123023, 1]];
static Deseret = [[66560, 66639, 1]];
static Devanagari = [[2304, 2384, 1], [2389, 2403, 1], [2406, 2431, 1], [43232, 43263, 1], [72448, 72457, 1]];
static Dives_Akuru = [[71936, 71942, 1], [71945, 71948, 3], [71949, 71955, 1], [71957, 71958, 1], [71960, 71989, 1], [71991, 71992, 1], [71995, 72006, 1], [72016, 72025, 1]];
static Dogra = [[71680, 71739, 1]];
static Duployan = [[113664, 113770, 1], [113776, 113788, 1], [113792, 113800, 1], [113808, 113817, 1], [113820, 113823, 1]];
static Egyptian_Hieroglyphs = [[77824, 78933, 1]];
static Elbasan = [[66816, 66855, 1]];
static Elymaic = [[69600, 69622, 1]];
static Ethiopic = [[4608, 4680, 1], [4682, 4685, 1], [4688, 4694, 1], [4696, 4698, 2], [4699, 4701, 1], [4704, 4744, 1], [4746, 4749, 1], [4752, 4784, 1], [4786, 4789, 1], [4792, 4798, 1], [4800, 4802, 2], [4803, 4805, 1], [4808, 4822, 1], [4824, 4880, 1], [4882, 4885, 1], [4888, 4954, 1], [4957, 4988, 1], [4992, 5017, 1], [11648, 11670, 1], [11680, 11686, 1], [11688, 11694, 1], [11696, 11702, 1], [11704, 11710, 1], [11712, 11718, 1], [11720, 11726, 1], [11728, 11734, 1], [11736, 11742, 1], [43777, 43782, 1], [43785, 43790, 1], [43793, 43798, 1], [43808, 43814, 1], [43816, 43822, 1], [124896, 124902, 1], [124904, 124907, 1], [124909, 124910, 1], [124912, 124926, 1]];
static Georgian = [[4256, 4293, 1], [4295, 4301, 6], [4304, 4346, 1], [4348, 4351, 1], [7312, 7354, 1], [7357, 7359, 1], [11520, 11557, 1], [11559, 11565, 6]];
static Glagolitic = [[11264, 11359, 1], [122880, 122886, 1], [122888, 122904, 1], [122907, 122913, 1], [122915, 122916, 1], [122918, 122922, 1]];
static Gothic = [[66352, 66378, 1]];
static Grantha = [[70400, 70403, 1], [70405, 70412, 1], [70415, 70416, 1], [70419, 70440, 1], [70442, 70448, 1], [70450, 70451, 1], [70453, 70457, 1], [70460, 70468, 1], [70471, 70472, 1], [70475, 70477, 1], [70480, 70487, 7], [70493, 70499, 1], [70502, 70508, 1], [70512, 70516, 1]];
static Greek = [[880, 883, 1], [885, 887, 1], [890, 893, 1], [895, 900, 5], [902, 904, 2], [905, 906, 1], [908, 910, 2], [911, 929, 1], [931, 993, 1], [1008, 1023, 1], [7462, 7466, 1], [7517, 7521, 1], [7526, 7530, 1], [7615, 7936, 321], [7937, 7957, 1], [7960, 7965, 1], [7968, 8005, 1], [8008, 8013, 1], [8016, 8023, 1], [8025, 8031, 2], [8032, 8061, 1], [8064, 8116, 1], [8118, 8132, 1], [8134, 8147, 1], [8150, 8155, 1], [8157, 8175, 1], [8178, 8180, 1], [8182, 8190, 1], [8486, 43877, 35391], [65856, 65934, 1], [65952, 119296, 53344], [119297, 119365, 1]];
static foldGreek = [[181, 837, 656]];
static Gujarati = [[2689, 2691, 1], [2693, 2701, 1], [2703, 2705, 1], [2707, 2728, 1], [2730, 2736, 1], [2738, 2739, 1], [2741, 2745, 1], [2748, 2757, 1], [2759, 2761, 1], [2763, 2765, 1], [2768, 2784, 16], [2785, 2787, 1], [2790, 2801, 1], [2809, 2815, 1]];
static Gunjala_Gondi = [[73056, 73061, 1], [73063, 73064, 1], [73066, 73102, 1], [73104, 73105, 1], [73107, 73112, 1], [73120, 73129, 1]];
static Gurmukhi = [[2561, 2563, 1], [2565, 2570, 1], [2575, 2576, 1], [2579, 2600, 1], [2602, 2608, 1], [2610, 2611, 1], [2613, 2614, 1], [2616, 2617, 1], [2620, 2622, 2], [2623, 2626, 1], [2631, 2632, 1], [2635, 2637, 1], [2641, 2649, 8], [2650, 2652, 1], [2654, 2662, 8], [2663, 2678, 1]];
static Han = [[11904, 11929, 1], [11931, 12019, 1], [12032, 12245, 1], [12293, 12295, 2], [12321, 12329, 1], [12344, 12347, 1], [13312, 19903, 1], [19968, 40959, 1], [63744, 64109, 1], [64112, 64217, 1], [94178, 94179, 1], [94192, 94193, 1], [131072, 173791, 1], [173824, 177977, 1], [177984, 178205, 1], [178208, 183969, 1], [183984, 191456, 1], [191472, 192093, 1], [194560, 195101, 1], [196608, 201546, 1], [201552, 205743, 1]];
static Hangul = [[4352, 4607, 1], [12334, 12335, 1], [12593, 12686, 1], [12800, 12830, 1], [12896, 12926, 1], [43360, 43388, 1], [44032, 55203, 1], [55216, 55238, 1], [55243, 55291, 1], [65440, 65470, 1], [65474, 65479, 1], [65482, 65487, 1], [65490, 65495, 1], [65498, 65500, 1]];
static Hanifi_Rohingya = [[68864, 68903, 1], [68912, 68921, 1]];
static Hanunoo = [[5920, 5940, 1]];
static Hatran = [[67808, 67826, 1], [67828, 67829, 1], [67835, 67839, 1]];
static Hebrew = [[1425, 1479, 1], [1488, 1514, 1], [1519, 1524, 1], [64285, 64310, 1], [64312, 64316, 1], [64318, 64320, 2], [64321, 64323, 2], [64324, 64326, 2], [64327, 64335, 1]];
static Hiragana = [[12353, 12438, 1], [12445, 12447, 1], [110593, 110879, 1], [110898, 110928, 30], [110929, 110930, 1], [127488, 127488, 1]];
static Imperial_Aramaic = [[67648, 67669, 1], [67671, 67679, 1]];
static Inherited = [[768, 879, 1], [1157, 1158, 1], [1611, 1621, 1], [1648, 2385, 737], [2386, 2388, 1], [6832, 6862, 1], [7376, 7378, 1], [7380, 7392, 1], [7394, 7400, 1], [7405, 7412, 7], [7416, 7417, 1], [7616, 7679, 1], [8204, 8205, 1], [8400, 8432, 1], [12330, 12333, 1], [12441, 12442, 1], [65024, 65039, 1], [65056, 65069, 1], [66045, 66272, 227], [70459, 118528, 48069], [118529, 118573, 1], [118576, 118598, 1], [119143, 119145, 1], [119163, 119170, 1], [119173, 119179, 1], [119210, 119213, 1], [917760, 917999, 1]];
static foldInherited = [[921, 953, 32], [8126, 8126, 1]];
static Inscriptional_Pahlavi = [[68448, 68466, 1], [68472, 68479, 1]];
static Inscriptional_Parthian = [[68416, 68437, 1], [68440, 68447, 1]];
static Javanese = [[43392, 43469, 1], [43472, 43481, 1], [43486, 43487, 1]];
static Kaithi = [[69760, 69826, 1], [69837, 69837, 1]];
static Kannada = [[3200, 3212, 1], [3214, 3216, 1], [3218, 3240, 1], [3242, 3251, 1], [3253, 3257, 1], [3260, 3268, 1], [3270, 3272, 1], [3274, 3277, 1], [3285, 3286, 1], [3293, 3294, 1], [3296, 3299, 1], [3302, 3311, 1], [3313, 3315, 1]];
static Katakana = [[12449, 12538, 1], [12541, 12543, 1], [12784, 12799, 1], [13008, 13054, 1], [13056, 13143, 1], [65382, 65391, 1], [65393, 65437, 1], [110576, 110579, 1], [110581, 110587, 1], [110589, 110590, 1], [110592, 110880, 288], [110881, 110882, 1], [110933, 110948, 15], [110949, 110951, 1]];
static Kawi = [[73472, 73488, 1], [73490, 73530, 1], [73534, 73561, 1]];
static Kayah_Li = [[43264, 43309, 1], [43311, 43311, 1]];
static Kharoshthi = [[68096, 68099, 1], [68101, 68102, 1], [68108, 68115, 1], [68117, 68119, 1], [68121, 68149, 1], [68152, 68154, 1], [68159, 68168, 1], [68176, 68184, 1]];
static Khitan_Small_Script = [[94180, 101120, 6940], [101121, 101589, 1]];
static Khmer = [[6016, 6109, 1], [6112, 6121, 1], [6128, 6137, 1], [6624, 6655, 1]];
static Khojki = [[70144, 70161, 1], [70163, 70209, 1]];
static Khudawadi = [[70320, 70378, 1], [70384, 70393, 1]];
static Lao = [[3713, 3714, 1], [3716, 3718, 2], [3719, 3722, 1], [3724, 3747, 1], [3749, 3751, 2], [3752, 3773, 1], [3776, 3780, 1], [3782, 3784, 2], [3785, 3790, 1], [3792, 3801, 1], [3804, 3807, 1]];
static Latin = [[65, 90, 1], [97, 122, 1], [170, 186, 16], [192, 214, 1], [216, 246, 1], [248, 696, 1], [736, 740, 1], [7424, 7461, 1], [7468, 7516, 1], [7522, 7525, 1], [7531, 7543, 1], [7545, 7614, 1], [7680, 7935, 1], [8305, 8319, 14], [8336, 8348, 1], [8490, 8491, 1], [8498, 8526, 28], [8544, 8584, 1], [11360, 11391, 1], [42786, 42887, 1], [42891, 42954, 1], [42960, 42961, 1], [42963, 42965, 2], [42966, 42969, 1], [42994, 43007, 1], [43824, 43866, 1], [43868, 43876, 1], [43878, 43881, 1], [64256, 64262, 1], [65313, 65338, 1], [65345, 65370, 1], [67456, 67461, 1], [67463, 67504, 1], [67506, 67514, 1], [122624, 122654, 1], [122661, 122666, 1]];
static Lepcha = [[7168, 7223, 1], [7227, 7241, 1], [7245, 7247, 1]];
static Limbu = [[6400, 6430, 1], [6432, 6443, 1], [6448, 6459, 1], [6464, 6468, 4], [6469, 6479, 1]];
static Linear_A = [[67072, 67382, 1], [67392, 67413, 1], [67424, 67431, 1]];
static Linear_B = [[65536, 65547, 1], [65549, 65574, 1], [65576, 65594, 1], [65596, 65597, 1], [65599, 65613, 1], [65616, 65629, 1], [65664, 65786, 1]];
static Lisu = [[42192, 42239, 1], [73648, 73648, 1]];
static Lycian = [[66176, 66204, 1]];
static Lydian = [[67872, 67897, 1], [67903, 67903, 1]];
static Mahajani = [[69968, 70006, 1]];
static Makasar = [[73440, 73464, 1]];
static Malayalam = [[3328, 3340, 1], [3342, 3344, 1], [3346, 3396, 1], [3398, 3400, 1], [3402, 3407, 1], [3412, 3427, 1], [3430, 3455, 1]];
static Mandaic = [[2112, 2139, 1], [2142, 2142, 1]];
static Manichaean = [[68288, 68326, 1], [68331, 68342, 1]];
static Marchen = [[72816, 72847, 1], [72850, 72871, 1], [72873, 72886, 1]];
static Masaram_Gondi = [[72960, 72966, 1], [72968, 72969, 1], [72971, 73014, 1], [73018, 73020, 2], [73021, 73023, 2], [73024, 73031, 1], [73040, 73049, 1]];
static Medefaidrin = [[93760, 93850, 1]];
static Meetei_Mayek = [[43744, 43766, 1], [43968, 44013, 1], [44016, 44025, 1]];
static Mende_Kikakui = [[124928, 125124, 1], [125127, 125142, 1]];
static Meroitic_Cursive = [[68000, 68023, 1], [68028, 68047, 1], [68050, 68095, 1]];
static Meroitic_Hieroglyphs = [[67968, 67999, 1]];
static Miao = [[93952, 94026, 1], [94031, 94087, 1], [94095, 94111, 1]];
static Modi = [[71168, 71236, 1], [71248, 71257, 1]];
static Mongolian = [[6144, 6145, 1], [6148, 6150, 2], [6151, 6169, 1], [6176, 6264, 1], [6272, 6314, 1], [71264, 71276, 1]];
static Mro = [[92736, 92766, 1], [92768, 92777, 1], [92782, 92783, 1]];
static Multani = [[70272, 70278, 1], [70280, 70282, 2], [70283, 70285, 1], [70287, 70301, 1], [70303, 70313, 1]];
static Myanmar = [[4096, 4255, 1], [43488, 43518, 1], [43616, 43647, 1]];
static Nabataean = [[67712, 67742, 1], [67751, 67759, 1]];
static Nag_Mundari = [[124112, 124153, 1]];
static Nandinagari = [[72096, 72103, 1], [72106, 72151, 1], [72154, 72164, 1]];
static New_Tai_Lue = [[6528, 6571, 1], [6576, 6601, 1], [6608, 6618, 1], [6622, 6623, 1]];
static Newa = [[70656, 70747, 1], [70749, 70753, 1]];
static Nko = [[1984, 2042, 1], [2045, 2047, 1]];
static Nushu = [[94177, 110960, 16783], [110961, 111355, 1]];
static Nyiakeng_Puachue_Hmong = [[123136, 123180, 1], [123184, 123197, 1], [123200, 123209, 1], [123214, 123215, 1]];
static Ogham = [[5760, 5788, 1]];
static Ol_Chiki = [[7248, 7295, 1]];
static Old_Hungarian = [[68736, 68786, 1], [68800, 68850, 1], [68858, 68863, 1]];
static Old_Italic = [[66304, 66339, 1], [66349, 66351, 1]];
static Old_North_Arabian = [[68224, 68255, 1]];
static Old_Permic = [[66384, 66426, 1]];
static Old_Persian = [[66464, 66499, 1], [66504, 66517, 1]];
static Old_Sogdian = [[69376, 69415, 1]];
static Old_South_Arabian = [[68192, 68223, 1]];
static Old_Turkic = [[68608, 68680, 1]];
static Old_Uyghur = [[69488, 69513, 1]];
static Oriya = [[2817, 2819, 1], [2821, 2828, 1], [2831, 2832, 1], [2835, 2856, 1], [2858, 2864, 1], [2866, 2867, 1], [2869, 2873, 1], [2876, 2884, 1], [2887, 2888, 1], [2891, 2893, 1], [2901, 2903, 1], [2908, 2909, 1], [2911, 2915, 1], [2918, 2935, 1]];
static Osage = [[66736, 66771, 1], [66776, 66811, 1]];
static Osmanya = [[66688, 66717, 1], [66720, 66729, 1]];
static Pahawh_Hmong = [[92928, 92997, 1], [93008, 93017, 1], [93019, 93025, 1], [93027, 93047, 1], [93053, 93071, 1]];
static Palmyrene = [[67680, 67711, 1]];
static Pau_Cin_Hau = [[72384, 72440, 1]];
static Phags_Pa = [[43072, 43127, 1]];
static Phoenician = [[67840, 67867, 1], [67871, 67871, 1]];
static Psalter_Pahlavi = [[68480, 68497, 1], [68505, 68508, 1], [68521, 68527, 1]];
static Rejang = [[43312, 43347, 1], [43359, 43359, 1]];
static Runic = [[5792, 5866, 1], [5870, 5880, 1]];
static Samaritan = [[2048, 2093, 1], [2096, 2110, 1]];
static Saurashtra = [[43136, 43205, 1], [43214, 43225, 1]];
static Sharada = [[70016, 70111, 1]];
static Shavian = [[66640, 66687, 1]];
static Siddham = [[71040, 71093, 1], [71096, 71133, 1]];
static SignWriting = [[120832, 121483, 1], [121499, 121503, 1], [121505, 121519, 1]];
static Sinhala = [[3457, 3459, 1], [3461, 3478, 1], [3482, 3505, 1], [3507, 3515, 1], [3517, 3520, 3], [3521, 3526, 1], [3530, 3535, 5], [3536, 3540, 1], [3542, 3544, 2], [3545, 3551, 1], [3558, 3567, 1], [3570, 3572, 1], [70113, 70132, 1]];
static Sogdian = [[69424, 69465, 1]];
static Sora_Sompeng = [[69840, 69864, 1], [69872, 69881, 1]];
static Soyombo = [[72272, 72354, 1]];
static Sundanese = [[7040, 7103, 1], [7360, 7367, 1]];
static Syloti_Nagri = [[43008, 43052, 1]];
static Syriac = [[1792, 1805, 1], [1807, 1866, 1], [1869, 1871, 1], [2144, 2154, 1]];
static Tagalog = [[5888, 5909, 1], [5919, 5919, 1]];
static Tagbanwa = [[5984, 5996, 1], [5998, 6000, 1], [6002, 6003, 1]];
static Tai_Le = [[6480, 6509, 1], [6512, 6516, 1]];
static Tai_Tham = [[6688, 6750, 1], [6752, 6780, 1], [6783, 6793, 1], [6800, 6809, 1], [6816, 6829, 1]];
static Tai_Viet = [[43648, 43714, 1], [43739, 43743, 1]];
static Takri = [[71296, 71353, 1], [71360, 71369, 1]];
static Tamil = [[2946, 2947, 1], [2949, 2954, 1], [2958, 2960, 1], [2962, 2965, 1], [2969, 2970, 1], [2972, 2974, 2], [2975, 2979, 4], [2980, 2984, 4], [2985, 2986, 1], [2990, 3001, 1], [3006, 3010, 1], [3014, 3016, 1], [3018, 3021, 1], [3024, 3031, 7], [3046, 3066, 1], [73664, 73713, 1], [73727, 73727, 1]];
static Tangsa = [[92784, 92862, 1], [92864, 92873, 1]];
static Tangut = [[94176, 94208, 32], [94209, 100343, 1], [100352, 101119, 1], [101632, 101640, 1]];
static Telugu = [[3072, 3084, 1], [3086, 3088, 1], [3090, 3112, 1], [3114, 3129, 1], [3132, 3140, 1], [3142, 3144, 1], [3146, 3149, 1], [3157, 3158, 1], [3160, 3162, 1], [3165, 3168, 3], [3169, 3171, 1], [3174, 3183, 1], [3191, 3199, 1]];
static Thaana = [[1920, 1969, 1]];
static Thai = [[3585, 3642, 1], [3648, 3675, 1]];
static Tibetan = [[3840, 3911, 1], [3913, 3948, 1], [3953, 3991, 1], [3993, 4028, 1], [4030, 4044, 1], [4046, 4052, 1], [4057, 4058, 1]];
static Tifinagh = [[11568, 11623, 1], [11631, 11632, 1], [11647, 11647, 1]];
static Tirhuta = [[70784, 70855, 1], [70864, 70873, 1]];
static Toto = [[123536, 123566, 1]];
static Ugaritic = [[66432, 66461, 1], [66463, 66463, 1]];
static Vai = [[42240, 42539, 1]];
static Vithkuqi = [[66928, 66938, 1], [66940, 66954, 1], [66956, 66962, 1], [66964, 66965, 1], [66967, 66977, 1], [66979, 66993, 1], [66995, 67001, 1], [67003, 67004, 1]];
static Wancho = [[123584, 123641, 1], [123647, 123647, 1]];
static Warang_Citi = [[71840, 71922, 1], [71935, 71935, 1]];
static Yezidi = [[69248, 69289, 1], [69291, 69293, 1], [69296, 69297, 1]];
static Yi = [[40960, 42124, 1], [42128, 42182, 1]];
static Zanabazar_Square = [[72192, 72263, 1]];
static CATEGORIES = (() => new Map([['C', UnicodeTables.C], ['Cc', UnicodeTables.Cc], ['Cf', UnicodeTables.Cf], ['Co', UnicodeTables.Co], ['Cs', UnicodeTables.Cs], ['L', UnicodeTables.L], ['Ll', UnicodeTables.Ll], ['Lm', UnicodeTables.Lm], ['Lo', UnicodeTables.Lo], ['Lt', UnicodeTables.Lt], ['Lu', UnicodeTables.Lu], ['M', UnicodeTables.M], ['Mc', UnicodeTables.Mc], ['Me', UnicodeTables.Me], ['Mn', UnicodeTables.Mn], ['N', UnicodeTables.N], ['Nd', UnicodeTables.Nd], ['Nl', UnicodeTables.Nl], ['No', UnicodeTables.No], ['P', UnicodeTables.P], ['Pc', UnicodeTables.Pc], ['Pd', UnicodeTables.Pd], ['Pe', UnicodeTables.Pe], ['Pf', UnicodeTables.Pf], ['Pi', UnicodeTables.Pi], ['Po', UnicodeTables.Po], ['Ps', UnicodeTables.Ps], ['S', UnicodeTables.S], ['Sc', UnicodeTables.Sc], ['Sk', UnicodeTables.Sk], ['Sm', UnicodeTables.Sm], ['So', UnicodeTables.So], ['Z', UnicodeTables.Z], ['Zl', UnicodeTables.Zl], ['Zp', UnicodeTables.Zp], ['Zs', UnicodeTables.Zs]]))();
static SCRIPTS = (() => new Map([['Adlam', UnicodeTables.Adlam], ['Ahom', UnicodeTables.Ahom], ['Anatolian_Hieroglyphs', UnicodeTables.Anatolian_Hieroglyphs], ['Arabic', UnicodeTables.Arabic], ['Armenian', UnicodeTables.Armenian], ['Avestan', UnicodeTables.Avestan], ['Balinese', UnicodeTables.Balinese], ['Bamum', UnicodeTables.Bamum], ['Bassa_Vah', UnicodeTables.Bassa_Vah], ['Batak', UnicodeTables.Batak], ['Bengali', UnicodeTables.Bengali], ['Bhaiksuki', UnicodeTables.Bhaiksuki], ['Bopomofo', UnicodeTables.Bopomofo], ['Brahmi', UnicodeTables.Brahmi], ['Braille', UnicodeTables.Braille], ['Buginese', UnicodeTables.Buginese], ['Buhid', UnicodeTables.Buhid], ['Canadian_Aboriginal', UnicodeTables.Canadian_Aboriginal], ['Carian', UnicodeTables.Carian], ['Caucasian_Albanian', UnicodeTables.Caucasian_Albanian], ['Chakma', UnicodeTables.Chakma], ['Cham', UnicodeTables.Cham], ['Cherokee', UnicodeTables.Cherokee], ['Chorasmian', UnicodeTables.Chorasmian], ['Common', UnicodeTables.Common], ['Coptic', UnicodeTables.Coptic], ['Cuneiform', UnicodeTables.Cuneiform], ['Cypriot', UnicodeTables.Cypriot], ['Cypro_Minoan', UnicodeTables.Cypro_Minoan], ['Cyrillic', UnicodeTables.Cyrillic], ['Deseret', UnicodeTables.Deseret], ['Devanagari', UnicodeTables.Devanagari], ['Dives_Akuru', UnicodeTables.Dives_Akuru], ['Dogra', UnicodeTables.Dogra], ['Duployan', UnicodeTables.Duployan], ['Egyptian_Hieroglyphs', UnicodeTables.Egyptian_Hieroglyphs], ['Elbasan', UnicodeTables.Elbasan], ['Elymaic', UnicodeTables.Elymaic], ['Ethiopic', UnicodeTables.Ethiopic], ['Georgian', UnicodeTables.Georgian], ['Glagolitic', UnicodeTables.Glagolitic], ['Gothic', UnicodeTables.Gothic], ['Grantha', UnicodeTables.Grantha], ['Greek', UnicodeTables.Greek], ['Gujarati', UnicodeTables.Gujarati], ['Gunjala_Gondi', UnicodeTables.Gunjala_Gondi], ['Gurmukhi', UnicodeTables.Gurmukhi], ['Han', UnicodeTables.Han], ['Hangul', UnicodeTables.Hangul], ['Hanifi_Rohingya', UnicodeTables.Hanifi_Rohingya], ['Hanunoo', UnicodeTables.Hanunoo], ['Hatran', UnicodeTables.Hatran], ['Hebrew', UnicodeTables.Hebrew], ['Hiragana', UnicodeTables.Hiragana], ['Imperial_Aramaic', UnicodeTables.Imperial_Aramaic], ['Inherited', UnicodeTables.Inherited], ['Inscriptional_Pahlavi', UnicodeTables.Inscriptional_Pahlavi], ['Inscriptional_Parthian', UnicodeTables.Inscriptional_Parthian], ['Javanese', UnicodeTables.Javanese], ['Kaithi', UnicodeTables.Kaithi], ['Kannada', UnicodeTables.Kannada], ['Katakana', UnicodeTables.Katakana], ['Kawi', UnicodeTables.Kawi], ['Kayah_Li', UnicodeTables.Kayah_Li], ['Kharoshthi', UnicodeTables.Kharoshthi], ['Khitan_Small_Script', UnicodeTables.Khitan_Small_Script], ['Khmer', UnicodeTables.Khmer], ['Khojki', UnicodeTables.Khojki], ['Khudawadi', UnicodeTables.Khudawadi], ['Lao', UnicodeTables.Lao], ['Latin', UnicodeTables.Latin], ['Lepcha', UnicodeTables.Lepcha], ['Limbu', UnicodeTables.Limbu], ['Linear_A', UnicodeTables.Linear_A], ['Linear_B', UnicodeTables.Linear_B], ['Lisu', UnicodeTables.Lisu], ['Lycian', UnicodeTables.Lycian], ['Lydian', UnicodeTables.Lydian], ['Mahajani', UnicodeTables.Mahajani], ['Makasar', UnicodeTables.Makasar], ['Malayalam', UnicodeTables.Malayalam], ['Mandaic', UnicodeTables.Mandaic], ['Manichaean', UnicodeTables.Manichaean], ['Marchen', UnicodeTables.Marchen], ['Masaram_Gondi', UnicodeTables.Masaram_Gondi], ['Medefaidrin', UnicodeTables.Medefaidrin], ['Meetei_Mayek', UnicodeTables.Meetei_Mayek], ['Mende_Kikakui', UnicodeTables.Mende_Kikakui], ['Meroitic_Cursive', UnicodeTables.Meroitic_Cursive], ['Meroitic_Hieroglyphs', UnicodeTables.Meroitic_Hieroglyphs], ['Miao', UnicodeTables.Miao], ['Modi', UnicodeTables.Modi], ['Mongolian', UnicodeTables.Mongolian], ['Mro', UnicodeTables.Mro], ['Multani', UnicodeTables.Multani], ['Myanmar', UnicodeTables.Myanmar], ['Nabataean', UnicodeTables.Nabataean], ['Nag_Mundari', UnicodeTables.Nag_Mundari], ['Nandinagari', UnicodeTables.Nandinagari], ['New_Tai_Lue', UnicodeTables.New_Tai_Lue], ['Newa', UnicodeTables.Newa], ['Nko', UnicodeTables.Nko], ['Nushu', UnicodeTables.Nushu], ['Nyiakeng_Puachue_Hmong', UnicodeTables.Nyiakeng_Puachue_Hmong], ['Ogham', UnicodeTables.Ogham], ['Ol_Chiki', UnicodeTables.Ol_Chiki], ['Old_Hungarian', UnicodeTables.Old_Hungarian], ['Old_Italic', UnicodeTables.Old_Italic], ['Old_North_Arabian', UnicodeTables.Old_North_Arabian], ['Old_Permic', UnicodeTables.Old_Permic], ['Old_Persian', UnicodeTables.Old_Persian], ['Old_Sogdian', UnicodeTables.Old_Sogdian], ['Old_South_Arabian', UnicodeTables.Old_South_Arabian], ['Old_Turkic', UnicodeTables.Old_Turkic], ['Old_Uyghur', UnicodeTables.Old_Uyghur], ['Oriya', UnicodeTables.Oriya], ['Osage', UnicodeTables.Osage], ['Osmanya', UnicodeTables.Osmanya], ['Pahawh_Hmong', UnicodeTables.Pahawh_Hmong], ['Palmyrene', UnicodeTables.Palmyrene], ['Pau_Cin_Hau', UnicodeTables.Pau_Cin_Hau], ['Phags_Pa', UnicodeTables.Phags_Pa], ['Phoenician', UnicodeTables.Phoenician], ['Psalter_Pahlavi', UnicodeTables.Psalter_Pahlavi], ['Rejang', UnicodeTables.Rejang], ['Runic', UnicodeTables.Runic], ['Samaritan', UnicodeTables.Samaritan], ['Saurashtra', UnicodeTables.Saurashtra], ['Sharada', UnicodeTables.Sharada], ['Shavian', UnicodeTables.Shavian], ['Siddham', UnicodeTables.Siddham], ['SignWriting', UnicodeTables.SignWriting], ['Sinhala', UnicodeTables.Sinhala], ['Sogdian', UnicodeTables.Sogdian], ['Sora_Sompeng', UnicodeTables.Sora_Sompeng], ['Soyombo', UnicodeTables.Soyombo], ['Sundanese', UnicodeTables.Sundanese], ['Syloti_Nagri', UnicodeTables.Syloti_Nagri], ['Syriac', UnicodeTables.Syriac], ['Tagalog', UnicodeTables.Tagalog], ['Tagbanwa', UnicodeTables.Tagbanwa], ['Tai_Le', UnicodeTables.Tai_Le], ['Tai_Tham', UnicodeTables.Tai_Tham], ['Tai_Viet', UnicodeTables.Tai_Viet], ['Takri', UnicodeTables.Takri], ['Tamil', UnicodeTables.Tamil], ['Tangsa', UnicodeTables.Tangsa], ['Tangut', UnicodeTables.Tangut], ['Telugu', UnicodeTables.Telugu], ['Thaana', UnicodeTables.Thaana], ['Thai', UnicodeTables.Thai], ['Tibetan', UnicodeTables.Tibetan], ['Tifinagh', UnicodeTables.Tifinagh], ['Tirhuta', UnicodeTables.Tirhuta], ['Toto', UnicodeTables.Toto], ['Ugaritic', UnicodeTables.Ugaritic], ['Vai', UnicodeTables.Vai], ['Vithkuqi', UnicodeTables.Vithkuqi], ['Wancho', UnicodeTables.Wancho], ['Warang_Citi', UnicodeTables.Warang_Citi], ['Yezidi', UnicodeTables.Yezidi], ['Yi', UnicodeTables.Yi], ['Zanabazar_Square', UnicodeTables.Zanabazar_Square]]))();
static FOLD_CATEGORIES = (() => new Map([['L', UnicodeTables.foldL], ['Ll', UnicodeTables.foldLl], ['Lt', UnicodeTables.foldLt], ['Lu', UnicodeTables.foldLu], ['M', UnicodeTables.foldM], ['Mn', UnicodeTables.foldMn]]))();
static FOLD_SCRIPT = (() => new Map([['Common', UnicodeTables.foldCommon], ['Greek', UnicodeTables.foldGreek], ['Inherited', UnicodeTables.foldInherited]]))();
}
/**
* Utilities for dealing with Unicode better than JS does.
*/
class Unicode {
// The highest legal rune value.
static MAX_RUNE = 0x10ffff;
// The highest legal ASCII value.
static MAX_ASCII = 0x7f;
// The highest legal Latin-1 value.
static MAX_LATIN1 = 0xff;
// The highest legal Basic Multilingual Plane (BMP) value.
static MAX_BMP = 0xffff;
// Minimum and maximum runes involved in folding.
// Checked during test.
static MIN_FOLD = 0x0041;
static MAX_FOLD = 0x1e943;
// is32 uses binary search to test whether rune is in the specified
// slice of 32-bit ranges.
static is32(ranges, r) {
// binary search over ranges
let lo = 0;
let hi = ranges.length;
while (lo < hi) {
let m = lo + Math.floor((hi - lo) / 2);
let range = ranges[m];
if (range[0] <= r && r <= range[1]) {
return (r - range[0]) % range[2] === 0;
}
if (r < range[0]) {
hi = m;
} else {
lo = m + 1;
}
}
return false;
}
// is tests whether rune is in the specified table of ranges.
static is(ranges, r) {
// common case: rune is ASCII or Latin-1, so use linear search.
if (r <= this.MAX_LATIN1) {
for (let range of ranges) {
// range = [lo, hi, stride]
if (r > range[1]) {
continue;
}
if (r < range[0]) {
return false;
}
return (r - range[0]) % range[2] === 0;
}
return false;
}
return ranges.length > 0 && r >= ranges[0][0] && this.is32(ranges, r);
}
// isUpper reports whether the rune is an upper case letter.
static isUpper(r) {
if (r <= this.MAX_LATIN1) {
const s = String.fromCodePoint(r);
return s.toUpperCase() === s && s.toLowerCase() !== s;
}
return this.is(UnicodeTables.Upper, r);
}
// isPrint reports whether the rune is printable (Unicode L/M/N/P/S or ' ').
static isPrint(r) {
if (r <= this.MAX_LATIN1) {
return r >= 0x20 && r < 0x7f || r >= 0xa1 && r !== 0xad;
}
return this.is(UnicodeTables.L, r) || this.is(UnicodeTables.M, r) || this.is(UnicodeTables.N, r) || this.is(UnicodeTables.P, r) || this.is(UnicodeTables.S, r);
}
// simpleFold iterates over Unicode code points equivalent under
// the Unicode-defined simple case folding. Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
// smallest r >= rune if one exists, or else the smallest r >= 0.
//
// For example:
// SimpleFold('A') = 'a'
// SimpleFold('a') = 'A'
//
// SimpleFold('K') = 'k'
// SimpleFold('k') = '\u212A' (Kelvin symbol, K)
// SimpleFold('\u212A') = 'K'
//
// SimpleFold('1') = '1'
//
// Derived from Go's unicode.SimpleFold.
//
static simpleFold(r) {
// Consult caseOrbit table for special cases.
if (UnicodeTables.CASE_ORBIT.has(r)) {
return UnicodeTables.CASE_ORBIT.get(r);
}
// No folding specified. This is a one- or two-element
// equivalence class containing rune and toLower(rune)
// and toUpper(rune) if they are different from rune.
const l = Codepoint.toLowerCase(r);
if (l !== r) {
return l;
}
return Codepoint.toUpperCase(r);
}
// equalsIgnoreCase performs case-insensitive equality comparison
// on the given runes |r1| and |r2|, with special consideration
// for the likely scenario where both runes are ASCII characters.
// If non-ASCII, Unicode case folding will be performed on |r1|
// to compare it to |r2|.
// -1 is interpreted as the end-of-file mark.
static equalsIgnoreCase(r1, r2) {
// Runes already match, or one of them is EOF
if (r1 < 0 || r2 < 0 || r1 === r2) {
return true;
}
// Fast path for the common case where both runes are ASCII characters.
// Coerces both runes to lowercase if applicable.
if (r1 <= this.MAX_ASCII && r2 <= this.MAX_ASCII) {
if (Codepoint.CODES.get('A') <= r1 && r1 <= Codepoint.CODES.get('Z')) {
r1 |= 0x20;
}
if (Codepoint.CODES.get('A') <= r2 && r2 <= Codepoint.CODES.get('Z')) {
r2 |= 0x20;
}
return r1 === r2;
}
// Fall back to full Unicode case folding otherwise.
// Invariant: r1 must be non-negative
for (let r = this.simpleFold(r1); r !== r1; r = this.simpleFold(r)) {
if (r === r2) {
return true;
}
}
return false;
}
}
/**
* Various constants and helper utilities.
*/
class Utils {
static METACHARACTERS = '\\.+*?()|[]{}^$';
//// EMPTY_* flags
static EMPTY_BEGIN_LINE = 0x01;
static EMPTY_END_LINE = 0x02;
static EMPTY_BEGIN_TEXT = 0x04;
static EMPTY_END_TEXT = 0x08;
static EMPTY_WORD_BOUNDARY = 0x10;
static EMPTY_NO_WORD_BOUNDARY = 0x20;
static EMPTY_ALL = (() => -1)();
static emptyInts() {
return [];
}
// Returns true iff |c| is an ASCII letter or decimal digit.
static isalnum(c) {
return Codepoint.CODES.get('0') <= c && c <= Codepoint.CODES.get('9') || Codepoint.CODES.get('a') <= c && c <= Codepoint.CODES.get('z') || Codepoint.CODES.get('A') <= c && c <= Codepoint.CODES.get('Z');
}
// If |c| is an ASCII hex digit, returns its value, otherwise -1.
static unhex(c) {
if (Codepoint.CODES.get('0') <= c && c <= Codepoint.CODES.get('9')) {
return c - Codepoint.CODES.get('0');
}
if (Codepoint.CODES.get('a') <= c && c <= Codepoint.CODES.get('f')) {
return c - Codepoint.CODES.get('a') + 10;
}
if (Codepoint.CODES.get('A') <= c && c <= Codepoint.CODES.get('F')) {
return c - Codepoint.CODES.get('A') + 10;
}
return -1;
}
// Appends a RE2 literal to |out| for rune |rune|,
// with regexp metacharacters escaped.
static escapeRune(rune) {
let out = '';
if (Unicode.isPrint(rune)) {
if (this.METACHARACTERS.indexOf(String.fromCodePoint(rune)) >= 0) {
out += '\\';
}
out += String.fromCodePoint(rune);
} else {
switch (rune) {
case Codepoint.CODES.get('"'):
// '"'
out += '\\"';
break;
case Codepoint.CODES.get('\\'):
// '\\'
out += '\\\\';
break;
case Codepoint.CODES.get('\t'):
// '\t'
out += '\\t';
break;
case Codepoint.CODES.get('\n'):
// '\n'
out += '\\n';
break;
case Codepoint.CODES.get('\r'):
// '\r'
out += '\\r';
break;
case Codepoint.CODES.get('\b'):
// '\b'
out += '\\b';
break;
case Codepoint.CODES.get('\f'):
// '\f'
out += '\\f';
break;
default:
{
let s = rune.toString(16);
if (rune < 0x100) {
out += '\\x';
if (s.length === 1) {
out += '0';
}
out += s;
} else {
out += `\\x{${s}}`;
}
break;
}
}
}
return out;
}
// Returns the array of runes in the specified Java UTF-16 string.
static stringToRunes(str) {
return String(str).split('').map(s => s.codePointAt(0));
}
// Returns the Java UTF-16 string containing the single rune |r|.
static runeToString(r) {
return String.fromCodePoint(r);
}
// isWordRune reports whether r is consider a ``word character''
// during the evaluation of the \b and \B zero-width assertions.
// These assertions are ASCII-only: the word characters are [A-Za-z0-9_].
static isWordRune(r) {
return Codepoint.CODES.get('a') <= r && r <= Codepoint.CODES.get('z') || Codepoint.CODES.get('A') <= r && r <= Codepoint.CODES.get('Z') || Codepoint.CODES.get('0') <= r && r <= Codepoint.CODES.get('9') || r === Codepoint.CODES.get('_');
}
// emptyOpContext returns the zero-width assertions satisfied at the position
// between the runes r1 and r2, a bitmask of EMPTY_* flags.
// Passing r1 == -1 indicates that the position is at the beginning of the
// text.
// Passing r2 == -1 indicates that the position is at the end of the text.
// eslint-disable-next-line no-warning-comments
// TODO(adonovan): move to Machine.
static emptyOpContext(r1, r2) {
let op = 0;
if (r1 < 0) {
op |= this.EMPTY_BEGIN_TEXT | this.EMPTY_BEGIN_LINE;
}
if (r1 === Codepoint.CODES.get('\n')) {
op |= this.EMPTY_BEGIN_LINE;
}
if (r2 < 0) {
op |= this.EMPTY_END_TEXT | this.EMPTY_END_LINE;
}
if (r2 === Codepoint.CODES.get('\n')) {
op |= this.EMPTY_END_LINE;
}
if (this.isWordRune(r1) !== this.isWordRune(r2)) {
op |= this.EMPTY_WORD_BOUNDARY;
} else {
op |= this.EMPTY_NO_WORD_BOUNDARY;
}
return op;
}
/**
* Returns a string that quotes all regular expression metacharacters inside the argument text;
* the returned string is a regular expression matching the literal text. For example,
* {@code quoteMeta("[foo]").equals("\\[foo\\]")}.
* @param {string} s
* @returns {string}
*/
static quoteMeta(str) {
return str.split('') // A char loop is correct because all metacharacters fit in one UTF-16 code.
.map(s => {
if (this.METACHARACTERS.indexOf(s) >= 0) {
return `\\${s}`;
}
return s;
}).join('');
}
static charCount(codePoint) {
return codePoint > Unicode.MAX_BMP ? 2 : 1;
}
static stringToUtf8ByteArray(str) {
if (globalThis.TextEncoder) {
return Array.from(new TextEncoder().encode(str));
} else {
// fallback, if no TextEncoder
let out = [],
p = 0;
for (let i = 0; i < str.length; i++) {
let c = str.charCodeAt(i);
if (c < 128) {
out[p++] = c;
} else if (c < 2048) {
out[p++] = c >> 6 | 192;
out[p++] = c & 63 | 128;
} else if ((c & 0xfc00) === 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) === 0xdc00) {
// Surrogate Pair
c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff);
out[p++] = c >> 18 | 240;
out[p++] = c >> 12 & 63 | 128;
out[p++] = c >> 6 & 63 | 128;
out[p++] = c & 63 | 128;
} else {
out[p++] = c >> 12 | 224;
out[p++] = c >> 6 & 63 | 128;
out[p++] = c & 63 | 128;
}
}
return out;
}
}
static utf8ByteArrayToString(bytes) {
if (globalThis.TextDecoder) {
return new TextDecoder('utf-8').decode(new Uint8Array(bytes));
} else {
// fallback, if no TextDecoder
let out = [],
pos = 0,
c = 0;
while (pos < bytes.length) {
let c1 = bytes[pos++];
if (c1 < 128) {
out[c++] = String.fromCharCode(c1);
} else if (c1 > 191 && c1 < 224) {
let c2 = bytes[pos++];
out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
} else if (c1 > 239 && c1 < 365) {
// Surrogate Pair
let c2 = bytes[pos++];
let c3 = bytes[pos++];
let c4 = bytes[pos++];
let u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) - 0x10000;
out[c++] = String.fromCharCode(0xd800 + (u >> 10));
out[c++] = String.fromCharCode(0xdc00 + (u & 1023));
} else {
let c2 = bytes[pos++];
let c3 = bytes[pos++];
out[c++] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
}
}
return out.join('');
}
}
}
// helper to create enums
// example
// Encoding[(Encoding['UTF_16'] = 0)] = 'UTF_16'
// Encoding[(Encoding['UTF_8'] = 1)] = 'UTF_8'
const createEnum = (values = [], initNum = 0) => {
const enumObject = {};
for (let i = 0; i < values.length; i++) {
const val = values[i];
const keyVal = initNum + i;
enumObject[val] = keyVal;
enumObject[keyVal] = val;
}
return Object.freeze(enumObject);
};
/**
* Abstract the representations of input text supplied to Matcher.
*/
class MatcherInputBase {
static Encoding = (() => createEnum(['UTF_16', 'UTF_8']))();
getEncoding() {
throw Error('not implemented');
}
/**
*
* @returns {boolean}
*/
isUTF8Encoding() {
return this.getEncoding() === MatcherInputBase.Encoding.UTF_8;
}
/**
*
* @returns {boolean}
*/
isUTF16Encoding() {
return this.getEncoding() === MatcherInputBase.Encoding.UTF_16;
}
}
class Utf8MatcherInput extends MatcherInputBase {
constructor(bytes = null) {
super();
this.bytes = bytes;
}
getEncoding() {
return MatcherInputBase.Encoding.UTF_8;
}
/**
*
* @returns {string}
*/
asCharSequence() {
return Utils.utf8ByteArrayToString(this.bytes);
}
/**
*
* @returns {number[]}
*/
asBytes() {
return this.bytes;
}
/**
*
* @returns {number}
*/
length() {
return this.bytes.length;
}
}
class Utf16MatcherInput extends MatcherInputBase {
constructor(charSequence = null) {
super();
this.charSequence = charSequence;
}
getEncoding() {
return MatcherInputBase.Encoding.UTF_16;
}
/**
*
* @returns {string}
*/
asCharSequence() {
return this.charSequence;
}
/**
*
* @returns {number[]}
*/
asBytes() {
return this.charSequence.toString().split('').map(s => s.codePointAt(0));
}
/**
*
* @returns {number}
*/
length() {
return this.charSequence.length;
}
}
class MatcherInput {
/**
* Return the MatcherInput for UTF_16 encoding.
* @returns {Utf16MatcherInput}
*/
static utf16(charSequence) {
return new Utf16MatcherInput(charSequence);
}
/**
* Return the MatcherInput for UTF_8 encoding.
* @returns {Utf8MatcherInput}
*/
static utf8(input) {
if (Array.isArray(input)) {
return new Utf8MatcherInput(input);
}
return new Utf8MatcherInput(Utils.stringToUtf8ByteArray(input));
}
}
class RE2JSException extends Error {
constructor(message) {
super(message);
this.name = 'RE2JSException';
}
}
/**
* An exception thrown by the parser if the pattern was invalid.
*/
class RE2JSSyntaxException extends RE2JSException {
constructor(error, input = null) {
let message = `error parsing regexp: ${error}`;
if (input) {
message += `: \`${input}\``;
}
super(message);
this.name = 'RE2JSSyntaxException';
this.message = message;
this.error = error;
this.input = input;
}
/**
* Retrieves the description of the error.
*/
getDescription() {
return this.error;
}
/**
* Retrieves the erroneous regular-expression pattern.
*/
getPattern() {
return this.input;
}
}
/**
* An exception thrown by the compiler
*/
class RE2JSCompileException extends RE2JSException {
constructor(message) {
super(message);
this.name = 'RE2JSCompileException';
}
}
/**
* An exception thrown by using groups
*/
class RE2JSGroupException extends RE2JSException {
constructor(message) {
super(message);
this.name = 'RE2JSGroupException';
}
}
/**
* An exception thrown by flags
*/
class RE2JSFlagsException extends RE2JSException {
constructor(message) {
super(message);
this.name = 'RE2JSFlagsException';
}
}
/**
* A stateful iterator that interprets a regex {@code RE2JS} on a specific input.
*
* Conceptually, a Matcher consists of four parts:
* <ol>
* <li>A compiled regular expression {@code RE2JS}, set at construction and fixed for the lifetime
* of the matcher.</li>
*
* <li>The remainder of the input string, set at construction or {@link #reset()} and advanced by
* each match operation such as {@link #find}, {@link #matches} or {@link #lookingAt}.</li>
*
* <li>The current match information, accessible via {@link #start}, {@link #end}, and
* {@link #group}, and updated by each match operation.</li>
*
* <li>The append position, used and advanced by {@link #appendReplacement} and {@link #appendTail}
* if performing a search and replace from the input to an external {@code StringBuffer}.
*
* </ol>
*
*
* @author rsc@google.com (Russ Cox)
*/
class Matcher {
/**
* Quotes '\' and '$' in {@code s}, so that the returned string could be used in
* {@link #appendReplacement} as a literal replacement of {@code s}.
*
* @param {string} str the string to be quoted
* @returns {string} the quoted string
*/
static quoteReplacement(str) {
if (str.indexOf('\\') < 0 && str.indexOf('$') < 0) {
return str;
}
return str.split('').map(s => {
const c = s.codePointAt(0);
if (c === Codepoint.CODES['\\'] || c === Codepoint.CODES['$']) {
return `\\${s}`;
}
return s;
}).join('');
}
/**
*
* @param {RE2JS} pattern
* @param {Utf8MatcherInput|Utf16MatcherInput|number[]|string} input
*/
constructor(pattern, input) {
if (pattern === null) {
throw new Error('pattern is null');
}
// The pattern being matched.
this.patternInput = pattern;
const re2 = this.patternInput.re2();
// The number of submatches (groups) in the pattern.
this.patternGroupCount = re2.numberOfCapturingGroups();
// The group indexes, in [start, end) pairs. Zeroth pair is overall match.
this.groups = [];
this.namedGroups = re2.namedGroups;
if (input instanceof MatcherInputBase) {
this.resetMatcherInput(input);
} else if (Array.isArray(input)) {
this.resetMatcherInput(MatcherInput.utf8(input));
} else {
this.resetMatcherInput(MatcherInput.utf16(input));
}
}
/**
* Returns the {@code RE2JS} associated with this {@code Matcher}.
* @returns {RE2JS}
*/
pattern() {
return this.patternInput;
}
/**
* Resets the {@code Matcher}, rewinding input and discarding any match information.
*
* @returns {Matcher} the {@code Matcher} itself, for chained method calls
*/
reset() {
// The input length in UTF16 codes.
this.matcherInputLength = this.matcherInput.length();
// The append position: where the next append should start.
this.appendPos = 0;
// Is there a current match?
this.hasMatch = false;
// Have we found the submatches (groups) of the current match?
// group[0], group[1] are set regardless.
this.hasGroups = false;
// The anchor flag to use when repeating the match to find subgroups.
this.anchorFlag = 0;
return this;
}
/**
* Resets the {@code Matcher} and changes the input.
* @returns {Matcher} the {@code Matcher} itself, for chained method calls
*/
resetMatcherInput(input) {
if (input === null) {
throw new Error('input is null');
}
this.matcherInput = input;
this.reset();
return this;
}
/**
* Returns the start of the named group of the most recent match, or -1 if the group was not
* matched.
* @param {string|number} [group=0]
* @returns {string}
*/
start(group = 0) {
if (typeof group === 'string') {
const groupInt = this.namedGroups[group];
if (!Number.isFinite(groupInt)) {
throw new RE2JSGroupException(`group '${group}' not found`);
}
group = groupInt;
}
this.loadGroup(group);
return this.groups[2 * group];
}
/**
* Returns the end of the named group of the most recent match, or -1 if the group was not
* matched.
* @param {string|number} [group=0]
* @returns {string}
*/
end(group = 0) {
if (typeof group === 'string') {
const groupInt = this.namedGroups[group];
if (!Number.isFinite(groupInt)) {
throw new RE2JSGroupException(`group '${group}' not found`);
}
group = groupInt;
}
this.loadGroup(group);
return this.groups[2 * group + 1];
}
/**
* Returns the named group of the most recent match, or {@code null} if the group was not matched.
* @param {string|number} [group=0]
* @returns {string}
*/
group(group = 0) {
if (typeof group === 'string') {
const groupInt = this.namedGroups[group];
if (!Number.isFinite(groupInt)) {
throw new RE2JSGroupException(`group '${group}' not found`);
}
group = groupInt;
}
const start = this.start(group);
const end = this.end(group);
if (start < 0 && end < 0) {
return null;
}
return this.substring(start, end);
}
/**
* Returns the number of subgroups in this pattern.
*
* @returns {number} the number of subgroups; the overall match (group 0) does not count
*/
groupCount() {
return this.patternGroupCount;
}
/**
* Helper: finds subgroup information if needed for group.
* @param {number} group
* @private
*/
loadGroup(group) {
if (group < 0 || group > this.patternGroupCount) {
throw new RE2JSGroupException(`Group index out of bounds: ${group}`);
}
if (!this.hasMatch) {
throw new RE2JSGroupException('perhaps no match attempted');
}
if (group === 0 || this.hasGroups) {
return;
}
let end = this.groups[1] + 1;
if (end > this.matcherInputLength) {
end = this.matcherInputLength;
}
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, this.groups[0], end, this.anchorFlag, 1 + this.patternGroupCount);
const ok = res[0];
if (!ok) {
throw new RE2JSGroupException('inconsistency in matching group data');
}
this.groups = res[1];
this.hasGroups = true;
}
/**
* Matches the entire input against the pattern (anchored start and end). If there is a match,
* {@code matches} sets the match state to describe it.
*
* @returns {boolean} true if the entire input matches the pattern
*/
matches() {
return this.genMatch(0, RE2Flags.ANCHOR_BOTH);
}
/**
* Matches the beginning of input against the pattern (anchored start). If there is a match,
* {@code lookingAt} sets the match state to describe it.
*
* @returns {boolean} true if the beginning of the input matches the pattern
*/
lookingAt() {
return this.genMatch(0, RE2Flags.ANCHOR_START);
}
/**
* Matches the input against the pattern (unanchored), starting at a specified position. If there
* is a match, {@code find} sets the match state to describe it.
*
* @param {string|number} [start=null] the input position where the search begins
* @returns {boolean} if it finds a match
* @throws IndexOutOfBoundsException if start is not a valid input position
*/
find(start = null) {
if (start !== null) {
if (start < 0 || start > this.matcherInputLength) {
throw new RE2JSGroupException(`start index out of bounds: ${start}`);
}
this.reset();
return this.genMatch(start, 0);
}
// no start
start = 0;
if (this.hasMatch) {
start = this.groups[1];
if (this.groups[0] === this.groups[1]) {
start++;
}
}
return this.genMatch(start, RE2Flags.UNANCHORED);
}
/**
* Helper: does match starting at start, with RE2 anchor flag.
* @param {number} startByte
* @param {number} anchor
* @returns {boolean}
* @private
*/
genMatch(startByte, anchor) {
const res = this.patternInput.re2().matchMachineInput(this.matcherInput, startByte, this.matcherInputLength, anchor, 1);
const ok = res[0];
if (!ok) {
return false;
}
this.groups = res[1];
this.hasMatch = true;
this.hasGroups = false;
this.anchorFlag = anchor;
return true;
}
/**
* Helper: return substring for [start, end).
* @param {number} start
* @param {number} end
* @returns {string}
*/
substring(start, end) {
if (this.matcherInput.isUTF8Encoding()) {
return Utils.utf8ByteArrayToString(this.matcherInput.asBytes().slice(start, end));
}
return this.matcherInput.asCharSequence().substring(start, end).toString();
}
/**
* Helper for Pattern: return input length.
* @returns {number}
*/
inputLength() {
return this.matcherInputLength;
}
/**
* Appends to result two strings: the text from the append position up to the beginning of the
* most recent match, and then the replacement with submatch groups substituted for references of
* the form {@code $n}, where {@code n} is the group number in decimal. It advances the append
* position to where the most recent match ended.
*
* To embed a literal {@code $}, use \$ (actually {@code "\\$"} with string escapes). The escape
* is only necessary when {@code $} is followed by a digit, but it is always allowed. Only
* {@code $} and {@code \} need escaping, but any character can be escaped.
*
* The group number {@code n} in {@code $n} is always at least one digit and expands to use more
* digits as long as the resulting number is a valid group number for this pattern. To cut it off
* earlier, escape the first digit that should not be used.
*
* @param {string} replacement the replacement string
* @param {boolean} [perlMode=false] activate perl/js mode (different behaviour for capture groups and special characters)
* @returns {string}
* @throws IllegalStateException if there was no most recent match
* @throws IndexOutOfBoundsException if replacement refers to an invalid group
* @private
*/
appendReplacement(replacement, perlMode = false) {
let res = '';
const s = this.start();
const e = this.end();
if (this.appendPos < s) {
res += this.substring(this.appendPos, s);
}
this.appendPos = e;
res += perlMode ? this.appendReplacementInternalPerl(replacement) : this.appendReplacementInternal(replacement);
return res;
}
/**
* @param {string} replacement - the replacement string
* @returns {string}
* @private
*/
appendReplacementInternal(replacement) {
let res = '';
let last = 0;
const m = replacement.length;
for (let i = 0; i < m - 1; i++) {
if (replacement.codePointAt(i) === Codepoint.CODES.get('\\')) {
if (last < i) {
res += replacement.substring(last, i);
}
i++;
last = i;
continue;
}
if (replacement.codePointAt(i) === Codepoint.CODES.get('$')) {
let c = replacement.codePointAt(i + 1);
if (Codepoint.CODES.get('0') <= c && c <= Codepoint.CODES.get('9')) {
let n = c - Codepoint.CODES.get('0');
if (last < i) {
res += replacement.substring(last, i);
}
for (i += 2; i < m; i++) {
c = replacement.codePointAt(i);
if (c < Codepoint.CODES.get('0') || c > Codepoint.CODES.get('9') || n * 10 + c - Codepoint.CODES.get('0') > this.patternGroupCount) {
break;
}
n = n * 10 + c - Codepoint.CODES.get('0');
}
if (n > this.patternGroupCount) {
throw new RE2JSGroupException(`n > number of groups: ${n}`);
}
const group = this.group(n);
if (group !== null) {
res += group;
}
last = i;
i--;
continue;
} else if (c === Codepoint.CODES.get('{')) {
if (last < i) {
res += replacement.substring(last, i);
}
i++;
let j = i + 1;
while (j < replacement.length && replacement.codePointAt(j) !== Codepoint.CODES.get('}') && replacement.codePointAt(j) !== Codepoint.CODES.get(' ')) {
j++;
}
if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get('}')) {
throw new RE2JSGroupException("named capture group is missing trailing '}'");
}
const groupName = replacement.substring(i + 1, j);
res += this.group(groupName);
last = j + 1;
}
}
}
if (last < m) {
res += replacement.substring(last, m);
}
return res;
}
/**
* @param {string} replacement - the replacement string
* @returns {string}
* @private
*/
appendReplacementInternalPerl(replacement) {
let res = '';
let last = 0;
const m = replacement.length;
for (let i = 0; i < m - 1; i++) {
if (replacement.codePointAt(i) === Codepoint.CODES.get('$')) {
let c = replacement.codePointAt(i + 1);
if (Codepoint.CODES.get('$') === c) {
if (last < i) {
res += replacement.substring(last, i);
}
res += '$';
i++;
last = i + 1;
continue;
} else if (Codepoint.CODES.get('&') === c) {
if (last < i) {
res += replacement.substring(last, i);
}
const group = this.group(0);
if (group !== null) {
res += group;
} else {
res += '$&';
}
i++;
last = i + 1;
continue;
} else if (Codepoint.CODES.get('1') <= c && c <= Codepoint.CODES.get('9')) {
let n = c - Codepoint.CODES.get('0');
if (last < i) {
res += replacement.substring(last, i);
}
for (i += 2; i < m; i++) {
c = replacement.codePointAt(i);
if (c < Codepoint.CODES.get('0') || c > Codepoint.CODES.get('9') || n * 10 + c - Codepoint.CODES.get('0') > this.patternGroupCount) {
break;
}
n = n * 10 + c - Codepoint.CODES.get('0');
}
if (n > this.patternGroupCount) {
res += `$${n}`;
last = i;
i--;
continue;
}
const group = this.group(n);
if (group !== null) {
res += group;
}
last = i;
i--;
continue;
} else if (c === Codepoint.CODES.get('<')) {
if (last < i) {
res += replacement.substring(last, i);
}
i++;
let j = i + 1;
while (j < replacement.length && replacement.codePointAt(j) !== Codepoint.CODES.get('>') && replacement.codePointAt(j) !== Codepoint.CODES.get(' ')) {
j++;
}
if (j === replacement.length || replacement.codePointAt(j) !== Codepoint.CODES.get('>')) {
res += replacement.substring(i - 1, j + 1);
last = j + 1;
continue;
}
const groupName = replacement.substring(i + 1, j);
if (Object.prototype.hasOwnProperty.call(this.namedGroups, groupName)) {
res += this.group(groupName);
} else {
res += `$<${groupName}>`;
}
last = j + 1;
}
}
}
if (last < m) {
res += replacement.substring(last, m);
}
return res;
}
/**
* Return the substring of the input from the append position to the end of the
* input.
* @returns {string}
*/
appendTail() {
return this.substring(this.appendPos, this.matcherInputLength);
}
/**
* Returns the input with all matches replaced by {@code replacement}, interpreted as for
* {@code appendReplacement}.
*
* @param {string} replacement - the replacement string
* @param {boolean} [perlMode=false] - activate perl/js mode (different behaviour for capture groups and special characters)
* @returns {string} the input string with the matches replaced
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and perlMode is false
*/
replaceAll(replacement, perlMode = false) {
return this.replace(replacement, true, perlMode);
}
/**
* Returns the input with the first match replaced by {@code replacement}, interpreted as for
* {@code appendReplacement}.
*
* @param {string} replacement - the replacement string
* @param {boolean} [perlMode=false] - activate perl/js mode (different behaviour for capture groups and special characters)
* @returns {string} the input string with the first match replaced
* @throws IndexOutOfBoundsException if replacement refers to an invalid group and perlMode is false
*/
replaceFirst(replacement, perlMode = false) {
return this.replace(replacement, false, perlMode);
}
/**
* Helper: replaceAll/replaceFirst hybrid.
* @param {string} replacement - the replacement string
* @param {boolean} [all=true] - replace all matches
* @param {boolean} [perlMode=false] - activate perl/js mode (different behaviour for capture groups and special characters)
* @returns {string}
* @private
*/
replace(replacement, all = true, perlMode = false) {
let res = '';
this.reset();
while (this.find()) {
res += this.appendReplacement(replacement, perlMode);
if (!all) {
break;
}
}
res += this.appendTail();
return res;
}
}
/**
* MachineInput abstracts different representations of the input text supplied to the Machine. It
* provides one-character lookahead.
*/
class MachineInputBase {
static EOF() {
return -1 << 3;
}
// can we look ahead without losing info?
canCheckPrefix() {
return true;
}
// Returns the end position in the same units as step().
endPos() {
return this.end;
}
}
// An implementation of MachineInput for UTF-8 byte arrays.
// |pos| and |width| are byte indices.
class MachineUTF8Input extends MachineInputBase {
constructor(bytes, start = 0, end = bytes.length) {
super();
this.bytes = bytes;
this.start = start;
this.end = end;
}
// Returns the rune at the specified index; the units are
// unspecified, but could be UTF-8 byte, UTF-16 char, or rune
// indices. Returns the width (in the same units) of the rune in
// the lower 3 bits, and the rune (Unicode code point) in the high
// bits. Never negative, except for EOF which is represented as -1
// << 3 | 0.
step(i) {
i += this.start;
if (i >= this.end) {
return MachineInputBase.EOF();
}
let x = this.bytes[i++] & 255;
if ((x & 128) === 0) {
return x << 3 | 1;
} else if ((x & 224) === 192) {
x = x & 31;
if (i >= this.end) {
return MachineInputBase.EOF();
}
x = x << 6 | this.bytes[i++] & 63;
return x << 3 | 2;
} else if ((x & 240) === 224) {
x = x & 15;
if (i + 1 >= this.end) {
return MachineInputBase.EOF();
}
x = x << 6 | this.bytes[i++] & 63;
x = x << 6 | this.bytes[i++] & 63;
return x << 3 | 3;
} else {
x = x & 7;
if (i + 2 >= this.end) {
return MachineInputBase.EOF();
}
x = x << 6 | this.bytes[i++] & 63;
x = x << 6 | this.bytes[i++] & 63;
x = x << 6 | this.bytes[i++] & 63;
return x << 3 | 4;
}
}
// Returns the index relative to |pos| at which |re2.prefix| is found
// in this input stream, or a negative value if not found.
index(re2, pos) {
pos += this.start;
const i = this.indexOf(this.bytes, re2.prefixUTF8, pos);
return i < 0 ? i : i - pos;
}
// Returns a bitmask of EMPTY_* flags.
context(pos) {
pos += this.start;
let r1 = -1;
if (pos > this.start && pos <= this.end) {
let start = pos - 1;
r1 = this.bytes[start--];
if (r1 >= 128) {
let lim = pos - 4;
if (lim < this.start) {
lim = this.start;
}
while (start >= lim && (this.bytes[start] & 192) === 128) {
start--;
}
if (start < this.start) {
start = this.start;
}
r1 = this.step(start) >> 3;
}
}
const r2 = pos < this.end ? this.step(pos) >> 3 : -1;
return Utils.emptyOpContext(r1, r2);
}
// Returns the index of the first occurrence of array |target| within
// array |source| after |fromIndex|, or -1 if not found.
indexOf(source, target, fromIndex = 0) {
let targetLength = target.length;
if (targetLength === 0) {
return -1;
}
let sourceLength = source.length;
for (let i = fromIndex; i <= sourceLength - targetLength; i++) {
for (let j = 0; j < targetLength; j++) {
if (source[i + j] !== target[j]) {
break;
} else if (j === targetLength - 1) {
return i;
}
}
}
return -1;
}
}
// |pos| and |width| are in JS "char" units.
class MachineUTF16Input extends MachineInputBase {
constructor(charSequence, start = 0, end = charSequence.length) {
super();
this.charSequence = charSequence;
this.start = start;
this.end = end;
}
// Returns the rune at the specified index; the units are
// unspecified, but could be UTF-8 byte, UTF-16 char, or rune
// indices. Returns the width (in the same units) of the rune in
// the lower 3 bits, and the rune (Unicode code point) in the high
// bits. Never negative, except for EOF which is represented as -1
// << 3 | 0.
step(pos) {
pos += this.start;
if (pos < this.end) {
const rune = this.charSequence.codePointAt(pos);
return rune << 3 | Utils.charCount(rune);
} else {
return MachineInputBase.EOF();
}
}
// Returns the index relative to |pos| at which |re2.prefix| is found
// in this input stream, or a negative value if not found.
index(re2, pos) {
pos += this.start;
const i = this.charSequence.indexOf(re2.prefix, pos);
return i < 0 ? i : i - pos;
}
// Returns a bitmask of EMPTY_* flags.
context(pos) {
pos += this.start;
const r1 = pos > 0 && pos <= this.charSequence.length ? this.charSequence.codePointAt(pos - 1) : -1;
const r2 = pos < this.charSequence.length ? this.charSequence.codePointAt(pos) : -1;
return Utils.emptyOpContext(r1, r2);
}
}
class MachineInput {
static fromUTF8(bytes, start = 0, end = bytes.length) {
return new MachineUTF8Input(bytes, start, end);
}
static fromUTF16(charSequence, start = 0, end = charSequence.length) {
return new MachineUTF16Input(charSequence, start, end);
}
}
/**
* Regular expression abstract syntax tree. Produced by parser, used by compiler. NB, this
* corresponds to {@code syntax.regexp} in the Go implementation; Go's {@code regexp} is called
* {@code RE2} in Java.
*/
class Regexp {
static Op = (() => createEnum(['NO_MATCH',
// Matches no strings.
'EMPTY_MATCH',
// Matches empty string.
'LITERAL',
// Matches runes[] sequence
'CHAR_CLASS',
// Matches Runes interpreted as range pair list
'ANY_CHAR_NOT_NL',
// Matches any character except '\n'
'ANY_CHAR',
// Matches any character
'BEGIN_LINE',
// Matches empty string at end of line
'END_LINE',
// Matches empty string at end of line
'BEGIN_TEXT',
// Matches empty string at beginning of text
'END_TEXT',
// Matches empty string at end of text
'WORD_BOUNDARY',
// Matches word boundary `\b`
'NO_WORD_BOUNDARY',
// Matches word non-boundary `\B`
'CAPTURE',
// Capturing subexpr with index cap, optional name name
'STAR',
// Matches subs[0] zero or more times.
'PLUS',
// Matches subs[0] one or more times.
'QUEST',
// Matches subs[0] zero or one times.
'REPEAT',
// Matches subs[0] [min, max] times; max=-1 => no limit.
'CONCAT',
// Matches concatenation of subs[]
'ALTERNATE',
// Matches union of subs[]
// Pseudo ops, used internally by Parser for parsing stack:
'LEFT_PAREN', 'VERTICAL_BAR']))();
static isPseudoOp(op) {
return op >= Regexp.Op.LEFT_PAREN;
}
static emptySubs() {
return [];
}
static quoteIfHyphen(rune) {
if (rune === Codepoint.CODES.get('-')) {
return '\\';
}
return '';
}
static fromRegexp(re) {
const regex = new Regexp(re.op);
regex.flags = re.flags;
regex.subs = re.subs;
regex.runes = re.runes;
regex.cap = re.cap;
regex.min = re.min;
regex.max = re.max;
regex.name = re.name;
regex.namedGroups = re.namedGroups;
return regex;
}
constructor(op) {
this.op = op; // operator
this.flags = 0; // bitmap of parse flags
// subexpressions, if any. Never null.
// subs[0] is used as the freelist.
this.subs = Regexp.emptySubs();
this.runes = null; // matched runes, for LITERAL, CHAR_CLASS
this.min = 0; // min for REPEAT
this.max = 0; // max for REPEAT
this.cap = 0; // capturing index, for CAPTURE
this.name = null; // capturing name, for CAPTURE
this.namedGroups = {}; // map of group name -> capturing index
}
reinit() {
this.flags = 0;
this.subs = Regexp.emptySubs();
this.runes = null;
this.cap = 0;
this.min = 0;
this.max = 0;
this.name = null;
this.namedGroups = {};
}
toString() {
return this.appendTo();
}
// appendTo() appends the Perl syntax for |this| regular expression to out
appendTo() {
let out = '';
switch (this.op) {
case Regexp.Op.NO_MATCH:
out += '[^\\x00-\\x{10FFFF}]';
break;
case Regexp.Op.EMPTY_MATCH:
out += '(?:)';
break;
case Regexp.Op.STAR:
case Regexp.Op.PLUS:
case Regexp.Op.QUEST:
case Regexp.Op.REPEAT:
{
const sub = this.subs[0];
if (sub.op > Regexp.Op.CAPTURE || sub.op === Regexp.Op.LITERAL && sub.runes.length > 1) {
out += `(?:${sub.appendTo()})`;
} else {
out += sub.appendTo();
}
switch (this.op) {
case Regexp.Op.STAR:
out += '*';
break;
case Regexp.Op.PLUS:
out += '+';
break;
case Regexp.Op.QUEST:
out += '?';
break;
case Regexp.Op.REPEAT:
out += `{${this.min}`;
if (this.min !== this.max) {
out += ',';
if (this.max >= 0) {
out += this.max;
}
}
out += '}';
break;
}
if ((this.flags & RE2Flags.NON_GREEDY) !== 0) {
out += '?';
}
break;
}
case Regexp.Op.CONCAT:
{
for (let sub of this.subs) {
if (sub.op === Regexp.Op.ALTERNATE) {
out += `(?:${sub.appendTo()})`;
} else {
out += sub.appendTo();
}
}
break;
}
case Regexp.Op.ALTERNATE:
{
let sep = '';
for (let sub of this.subs) {
out += sep;
sep = '|';
out += sub.appendTo();
}
break;
}
case Regexp.Op.LITERAL:
if ((this.flags & RE2Flags.FOLD_CASE) !== 0) {
out += '(?i:';
}
for (let rune of this.runes) {
out += Utils.escapeRune(rune);
}
if ((this.flags & RE2Flags.FOLD_CASE) !== 0) {
out += ')';
}
break;
case Regexp.Op.ANY_CHAR_NOT_NL:
out += '(?-s:.)';
break;
case Regexp.Op.ANY_CHAR:
out += '(?s:.)';
break;
case Regexp.Op.CAPTURE:
if (this.name === null || this.name.length === 0) {
out += '(';
} else {
out += `(?P<${this.name}>`;
}
if (this.subs[0].op !== Regexp.Op.EMPTY_MATCH) {
out += this.subs[0].appendTo();
}
out += ')';
break;
case Regexp.Op.BEGIN_TEXT:
out += '\\A';
break;
case Regexp.Op.END_TEXT:
if ((this.flags & RE2Flags.WAS_DOLLAR) !== 0) {
out += '(?-m:$)';
} else {
out += '\\z';
}
break;
case Regexp.Op.BEGIN_LINE:
out += '^';
break;
case Regexp.Op.END_LINE:
out += '$';
break;
case Regexp.Op.WORD_BOUNDARY:
out += '\\b';
break;
case Regexp.Op.NO_WORD_BOUNDARY:
out += '\\B';
break;
case Regexp.Op.CHAR_CLASS:
if (this.runes.length % 2 !== 0) {
out += '[invalid char class]';
break;
}
out += '[';
if (this.runes.length === 0) {
out += '^\\x00-\\x{10FFFF}';
} else if (this.runes[0] === 0 && this.runes[this.runes.length - 1] === Unicode.MAX_RUNE) {
out += '^';
for (let i = 1; i < this.runes.length - 1; i += 2) {
const lo = this.runes[i] + 1;
const hi = this.runes[i + 1] - 1;
out += Regexp.quoteIfHyphen(lo);
out += Utils.escapeRune(lo);
if (lo !== hi) {
out += '-';
out += Regexp.quoteIfHyphen(hi);
out += Utils.escapeRune(hi);
}
}
} else {
for (let i = 0; i < this.runes.length; i += 2) {
const lo = this.runes[i];
const hi = this.runes[i + 1];
out += Regexp.quoteIfHyphen(lo);
out += Utils.escapeRune(lo);
if (lo !== hi) {
out += '-';
out += Regexp.quoteIfHyphen(hi);
out += Utils.escapeRune(hi);
}
}
}
out += ']';
break;
default:
out += this.op;
break;
}
return out;
}
// maxCap() walks the regexp to find the maximum capture index.
maxCap() {
let m = 0;
if (this.op === Regexp.Op.CAPTURE) {
m = this.cap;
}
if (this.subs !== null) {
for (let sub of this.subs) {
const n = sub.maxCap();
if (m < n) {
m = n;
}
}
}
return m;
}
// equals() returns true if this and that have identical structure.
equals(that) {
if (!(that !== null && that instanceof Regexp)) {
return false;
}
if (this.op !== that.op) {
return false;
}
switch (this.op) {
case Regexp.Op.END_TEXT:
{
if ((this.flags & RE2Flags.WAS_DOLLAR) !== (that.flags & RE2Flags.WAS_DOLLAR)) {
return false;
}
break;
}
case Regexp.Op.LITERAL:
case Regexp.Op.CHAR_CLASS:
{
if (this.runes === null && that.runes === null) {
break;
}
if (this.runes === null || that.runes === null) {
return false;
}
if (this.runes.length !== that.runes.length) {
return false;
}
for (let i = 0; i < this.runes.length; i++) {
if (this.runes[i] !== that.runes[i]) {
return false;
}
}
break;
}
case Regexp.Op.ALTERNATE:
case Regexp.Op.CONCAT:
{
if (this.subs.length !== that.subs.length) {
return false;
}
for (let i = 0; i < this.subs.length; ++i) {
if (!this.subs[i].equals(that.subs[i])) {
return false;
}
}
break;
}
case Regexp.Op.STAR:
case Regexp.Op.PLUS:
case Regexp.Op.QUEST:
{
if ((this.flags & RE2Flags.NON_GREEDY) !== (that.flags & RE2Flags.NON_GREEDY) || !this.subs[0].equals(that.subs[0])) {
return false;
}
break;
}
case Regexp.Op.REPEAT:
{
if ((this.flags & RE2Flags.NON_GREEDY) !== (that.flags & RE2Flags.NON_GREEDY) || this.min !== that.min || this.max !== that.max || !this.subs[0].equals(that.subs[0])) {
return false;
}
break;
}
case Regexp.Op.CAPTURE:
{
if (this.cap !== that.cap || (this.name === null ? that.name !== null : this.name !== that.name) || !this.subs[0].equals(that.subs[0])) {
return false;
}
break;
}
}
return true;
}
}
/**
* A single instruction in the regular expression virtual machine.
*
* @see http://swtch.com/~rsc/regexp/regexp2.html
*/
class Inst {
static ALT = 1;
static ALT_MATCH = 2;
static CAPTURE = 3;
static EMPTY_WIDTH = 4;
static FAIL = 5;
static MATCH = 6;
static NOP = 7;
static RUNE = 8;
static RUNE1 = 9;
static RUNE_ANY = 10;
static RUNE_ANY_NOT_NL = 11;
static isRuneOp(op) {
return Inst.RUNE <= op && op <= Inst.RUNE_ANY_NOT_NL;
}
// Returns an RE2 expression matching exactly |runes|.
static escapeRunes(runes) {
let out = '"';
for (let rune of runes) {
out += Utils.escapeRune(rune);
}
out += '"';
return out;
}
constructor(op) {
this.op = op;
this.out = 0; // all but MATCH, FAIL
this.arg = 0; // ALT, ALT_MATCH, CAPTURE, EMPTY_WIDTH
// length==1 => exact match
// otherwise a list of [lo,hi] pairs. hi is *inclusive*.
this.runes = null;
}
// MatchRune returns true if the instruction matches (and consumes) r.
// It should only be called when op == InstRune.
matchRune(r) {
// Special case: single-rune slice is from literal string, not char
// class.
if (this.runes.length === 1) {
const r0 = this.runes[0];
// If this pattern is case-insensitive, apply Unicode case folding to compare the two runes.
// Note that this may result in a case-folding loop when executed,
// so attempt to reduce the chance of that occurring
// by performing case folding on |r0| from the pattern rather than |r| from the input.
if ((this.arg & RE2Flags.FOLD_CASE) !== 0) {
return Unicode.equalsIgnoreCase(r0, r);
}
return r === r0;
}
// Peek at the first few pairs.
// Should handle ASCII well.
for (let j = 0; j < this.runes.length && j <= 8; j += 2) {
if (r < this.runes[j]) {
return false;
}
if (r <= this.runes[j + 1]) {
return true;
}
}
// Otherwise binary search.
let lo = 0;
let hi = this.runes.length / 2 | 0;
while (lo < hi) {
const m = lo + ((hi - lo) / 2 | 0);
const c = this.runes[2 * m];
if (c <= r) {
if (r <= this.runes[2 * m + 1]) {
return true;
}
lo = m + 1;
} else {
hi = m;
}
}
return false;
}
/**
*
* @returns {string}
*/
toString() {
switch (this.op) {
case Inst.ALT:
return `alt -> ${this.out}, ${this.arg}`;
case Inst.ALT_MATCH:
return `altmatch -> ${this.out}, ${this.arg}`;
case Inst.CAPTURE:
return `cap ${this.arg} -> ${this.out}`;
case Inst.EMPTY_WIDTH:
return `empty ${this.arg} -> ${this.out}`;
case Inst.MATCH:
return 'match';
case Inst.FAIL:
return 'fail';
case Inst.NOP:
return `nop -> ${this.out}`;
case Inst.RUNE:
if (this.runes === null) {
return 'rune <null>';
}
return ['rune ', Inst.escapeRunes(this.runes), (this.arg & RE2Flags.FOLD_CASE) !== 0 ? '/i' : '', ' -> ', this.out].join('');
case Inst.RUNE1:
return `rune1 ${Inst.escapeRunes(this.runes)} -> ${this.out}`;
case Inst.RUNE_ANY:
return `any -> ${this.out}`;
case Inst.RUNE_ANY_NOT_NL:
return `anynotnl -> ${this.out}`;
default:
throw new Error('unhandled case in Inst.toString');
}
}
}
/**
* A Prog is a compiled regular expression program.
*/
class Prog {
constructor() {
this.inst = [];
this.start = 0; // index of start instruction
// number of CAPTURE insts in re
// 2 => implicit ( and ) for whole match $0
this.numCap = 2;
}
// Returns the instruction at the specified pc.
// Precondition: pc > 0 && pc < numInst().
getInst(pc) {
return this.inst[pc];
}
// Returns the number of instructions in this program.
numInst() {
return this.inst.length;
}
// Adds a new instruction to this program, with operator |op| and |pc| equal
// to |numInst()|.
addInst(op) {
this.inst.push(new Inst(op));
}
// skipNop() follows any no-op or capturing instructions and returns the
// resulting instruction.
skipNop(pc) {
let i = this.inst[pc];
while (i.op === Inst.NOP || i.op === Inst.CAPTURE) {
i = this.inst[pc];
pc = i.out;
}
return i;
}
// prefix() returns a pair of a literal string that all matches for the
// regexp must start with, and a boolean which is true if the prefix is the
// entire match. The string is returned by appending to |prefix|.
prefix() {
let prefix = '';
let i = this.skipNop(this.start);
if (!Inst.isRuneOp(i.op) || i.runes.length !== 1) {
return [i.op === Inst.MATCH, prefix];
}
while (Inst.isRuneOp(i.op) && i.runes.length === 1 && (i.arg & RE2Flags.FOLD_CASE) === 0) {
prefix += String.fromCodePoint(i.runes[0]);
i = this.skipNop(i.out);
}
return [i.op === Inst.MATCH, prefix];
}
// startCond() returns the leading empty-width conditions that must be true
// in any match. It returns -1 (all bits set) if no matches are possible.
startCond() {
let flag = 0;
let pc = this.start;
loop: for (;;) {
const i = this.inst[pc];
switch (i.op) {
case Inst.EMPTY_WIDTH:
flag |= i.arg;
break;
case Inst.FAIL:
return -1;
case Inst.CAPTURE:
case Inst.NOP:
break;
default:
break loop;
}
pc = i.out;
}
return flag;
}
// --- Patch list ---
// A patchlist is a list of instruction pointers that need to be filled in
// (patched). Because the pointers haven't been filled in yet, we can reuse
// their storage to hold the list. It's kind of sleazy, but works well in
// practice. See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
// These aren't really pointers: they're integers, so we can reinterpret them
// this way without using package unsafe. A value l denotes p.inst[l>>1].out
// (l&1==0) or .arg (l&1==1). l == 0 denotes the empty list, okay because we
// start every program with a fail instruction, so we'll never want to point
// at its output link.
next(l) {
const i = this.inst[l >> 1];
if ((l & 1) === 0) {
return i.out;
}
return i.arg;
}
patch(l, val) {
while (l !== 0) {
const i = this.inst[l >> 1];
if ((l & 1) === 0) {
l = i.out;
i.out = val;
} else {
l = i.arg;
i.arg = val;
}
}
}
append(l1, l2) {
if (l1 === 0) {
return l2;
}
if (l2 === 0) {
return l1;
}
let last = l1;
for (;;) {
const next = this.next(last);
if (next === 0) {
break;
}
last = next;
}
const i = this.inst[last >> 1];
if ((last & 1) === 0) {
i.out = l2;
} else {
i.arg = l2;
}
return l1;
}
/**
*
* @returns {string}
*/
toString() {
let out = '';
for (let pc = 0; pc < this.inst.length; pc++) {
const len = out.length;
out += pc;
if (pc === this.start) {
out += '*';
}
out += ' '.substring(out.length - len);
out += this.inst[pc];
out += '\n';
}
return out;
}
}
/**
* A fragment of a compiled regular expression program.
*
* @see http://swtch.com/~rsc/regexp/regexp1.html
* @class
*/
class Frag {
constructor(i = 0, out = 0, nullable = false) {
this.i = i; // an instruction address (pc).
this.out = out; // a patch list; see explanation in Prog.js
this.nullable = nullable; // whether the fragment can match the empty string
}
}
/**
* Compiler from {@code Regexp} (RE2 abstract syntax) to {@code RE2} (compiled regular expression).
*
* The only entry point is {@link #compileRegexp}.
*/
class Compiler {
static ANY_RUNE_NOT_NL() {
return [0, Codepoint.CODES.get('\n') - 1, Codepoint.CODES.get('\n') + 1, Unicode.MAX_RUNE];
}
static ANY_RUNE() {
return [0, Unicode.MAX_RUNE];
}
static compileRegexp(re) {
const c = new Compiler();
const f = c.compile(re);
c.prog.patch(f.out, c.newInst(Inst.MATCH).i);
c.prog.start = f.i;
return c.prog;
}
constructor() {
this.prog = new Prog();
this.newInst(Inst.FAIL);
}
newInst(op) {
this.prog.addInst(op);
return new Frag(this.prog.numInst() - 1, 0, true);
}
// Returns a no-op fragment. Sometimes unavoidable.
nop() {
const f = this.newInst(Inst.NOP);
f.out = f.i << 1;
return f;
}
fail() {
return new Frag();
}
// Given fragment a, returns (a) capturing as \n.
// Given a fragment a, returns a fragment with capturing parens around a.
cap(arg) {
const f = this.newInst(Inst.CAPTURE);
f.out = f.i << 1;
this.prog.getInst(f.i).arg = arg;
if (this.prog.numCap < arg + 1) {
this.prog.numCap = arg + 1;
}
return f;
}
// Given fragments a and b, returns ab; a|b
cat(f1, f2) {
// concat of failure is failure
if (f1.i === 0 || f2.i === 0) {
return this.fail();
}
// eslint-disable-next-line no-warning-comments
// TODO(rsc): elide nop
this.prog.patch(f1.out, f2.i);
return new Frag(f1.i, f2.out, f1.nullable && f2.nullable);
}
// Given fragments for a and b, returns fragment for a|b.
alt(f1, f2) {
// alt of failure is other
if (f1.i === 0) {
return f2;
}
if (f2.i === 0) {
return f1;
}
const f = this.newInst(Inst.ALT);
const i = this.prog.getInst(f.i);
i.out = f1.i;
i.arg = f2.i;
f.out = this.prog.append(f1.out, f2.out);
f.nullable = f1.nullable || f2.nullable;
return f;
}
// loop returns the fragment for the main loop of a plus or star.
// For plus, it can be used directly. with f1.i as the entry.
// For star, it can be used directly when f1 can't match an empty string.
// (When f1 can match an empty string, f1* must be implemented as (f1+)?
// to get the priority match order correct.)
loop(f1, nongreedy) {
const f = this.newInst(Inst.ALT);
const i = this.prog.getInst(f.i);
if (nongreedy) {
i.arg = f1.i;
f.out = f.i << 1;
} else {
i.out = f1.i;
f.out = f.i << 1 | 1;
}
this.prog.patch(f1.out, f.i);
return f;
}
// Given a fragment for a, returns a fragment for a? or a?? (if nongreedy)
quest(f1, nongreedy) {
const f = this.newInst(Inst.ALT);
const i = this.prog.getInst(f.i);
if (nongreedy) {
i.arg = f1.i;
f.out = f.i << 1;
} else {
i.out = f1.i;
f.out = f.i << 1 | 1;
}
f.out = this.prog.append(f.out, f1.out);
return f;
}
// Given a fragment a, returns a fragment for a* or a*? (if nongreedy)
star(f1, nongreedy) {
if (f1.nullable) {
return this.quest(this.plus(f1, nongreedy), nongreedy);
}
return this.loop(f1, nongreedy);
}
// Given a fragment for a, returns a fragment for a+ or a+? (if nongreedy)
plus(f1, nongreedy) {
return new Frag(f1.i, this.loop(f1, nongreedy).out, f1.nullable);
}
// op is a bitmask of EMPTY_* flags.
empty(op) {
const f = this.newInst(Inst.EMPTY_WIDTH);
this.prog.getInst(f.i).arg = op;
f.out = f.i << 1;
return f;
}
// flags : parser flags
rune(runes, flags) {
const f = this.newInst(Inst.RUNE);
f.nullable = false;
const i = this.prog.getInst(f.i);
i.runes = runes;
flags &= RE2Flags.FOLD_CASE;
if (runes.length !== 1 || Unicode.simpleFold(runes[0]) === runes[0]) {
flags &= ~RE2Flags.FOLD_CASE;
}
i.arg = flags;
f.out = f.i << 1;
if ((flags & RE2Flags.FOLD_CASE) === 0 && runes.length === 1 || runes.length === 2 && runes[0] === runes[1]) {
i.op = Inst.RUNE1;
} else if (runes.length === 2 && runes[0] === 0 && runes[1] === Unicode.MAX_RUNE) {
i.op = Inst.RUNE_ANY;
} else if (runes.length === 4 && runes[0] === 0 && runes[1] === Codepoint.CODES.get('\n') - 1 && runes[2] === Codepoint.CODES.get('\n') + 1 && runes[3] === Unicode.MAX_RUNE) {
i.op = Inst.RUNE_ANY_NOT_NL;
}
return f;
}
compile(re) {
switch (re.op) {
case Regexp.Op.NO_MATCH:
return this.fail();
case Regexp.Op.EMPTY_MATCH:
return this.nop();
case Regexp.Op.LITERAL:
if (re.runes.length === 0) {
return this.nop();
} else {
let f = null;
for (let r of re.runes) {
const f1 = this.rune([r], re.flags);
f = f === null ? f1 : this.cat(f, f1);
}
return f;
}
case Regexp.Op.CHAR_CLASS:
return this.rune(re.runes, re.flags);
case Regexp.Op.ANY_CHAR_NOT_NL:
return this.rune(Compiler.ANY_RUNE_NOT_NL(), 0);
case Regexp.Op.ANY_CHAR:
return this.rune(Compiler.ANY_RUNE(), 0);
case Regexp.Op.BEGIN_LINE:
return this.empty(Utils.EMPTY_BEGIN_LINE);
case Regexp.Op.END_LINE:
return this.empty(Utils.EMPTY_END_LINE);
case Regexp.Op.BEGIN_TEXT:
return this.empty(Utils.EMPTY_BEGIN_TEXT);
case Regexp.Op.END_TEXT:
return this.empty(Utils.EMPTY_END_TEXT);
case Regexp.Op.WORD_BOUNDARY:
return this.empty(Utils.EMPTY_WORD_BOUNDARY);
case Regexp.Op.NO_WORD_BOUNDARY:
return this.empty(Utils.EMPTY_NO_WORD_BOUNDARY);
case Regexp.Op.CAPTURE:
{
const bra = this.cap(re.cap << 1);
const sub = this.compile(re.subs[0]);
const ket = this.cap(re.cap << 1 | 1);
return this.cat(this.cat(bra, sub), ket);
}
case Regexp.Op.STAR:
return this.star(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
case Regexp.Op.PLUS:
return this.plus(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
case Regexp.Op.QUEST:
return this.quest(this.compile(re.subs[0]), (re.flags & RE2Flags.NON_GREEDY) !== 0);
case Regexp.Op.CONCAT:
{
if (re.subs.length === 0) {
return this.nop();
} else {
let f = null;
for (let sub of re.subs) {
const f1 = this.compile(sub);
f = f === null ? f1 : this.cat(f, f1);
}
return f;
}
}
case Regexp.Op.ALTERNATE:
{
if (re.subs.length === 0) {
return this.nop();
} else {
let f = null;
for (let sub of re.subs) {
const f1 = this.compile(sub);
f = f === null ? f1 : this.alt(f, f1);
}
return f;
}
}
default:
throw new RE2JSCompileException('regexp: unhandled case in compile');
}
}
}
class Simplify {
// Simplify returns a regexp equivalent to re but without counted
// repetitions and with various other simplifications, such as
// rewriting /(?:a+)+/ to /a+/. The resulting regexp will execute
// correctly but its string representation will not produce the same
// parse tree, because capturing parentheses may have been duplicated
// or removed. For example, the simplified form for /(x){1,2}/ is
// /(x)(x)?/ but both parentheses capture as $1. The returned regexp
// may share structure with or be the original.
static simplify(re) {
if (re === null) {
return null;
}
switch (re.op) {
case Regexp.Op.CAPTURE:
case Regexp.Op.CONCAT:
case Regexp.Op.ALTERNATE:
{
let nre = re;
for (let i = 0; i < re.subs.length; i++) {
const sub = re.subs[i];
const nsub = Simplify.simplify(sub);
if (nre === re && nsub !== sub) {
nre = Regexp.fromRegexp(re);
nre.runes = null;
nre.subs = re.subs.slice(0, re.subs.length);
}
if (nre !== re) {
nre.subs[i] = nsub;
}
}
return nre;
}
case Regexp.Op.STAR:
case Regexp.Op.PLUS:
case Regexp.Op.QUEST:
{
const sub = Simplify.simplify(re.subs[0]);
return Simplify.simplify1(re.op, re.flags, sub, re);
}
case Regexp.Op.REPEAT:
{
// Special special case: x{0} matches the empty string
// and doesn't even need to consider x.
if (re.min === 0 && re.max === 0) {
return new Regexp(Regexp.Op.EMPTY_MATCH);
}
// The fun begins.
const sub = Simplify.simplify(re.subs[0]);
// x{n,} means at least n matches of x.
if (re.max === -1) {
// Special case: x{0,} is x*.
if (re.min === 0) {
return Simplify.simplify1(Regexp.Op.STAR, re.flags, sub, null);
}
// Special case: x{1,} is x+.
if (re.min === 1) {
return Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null);
}
// General case: x{4,} is xxxx+.
const nre = new Regexp(Regexp.Op.CONCAT);
const subs = [];
for (let i = 0; i < re.min - 1; i++) {
subs.push(sub);
}
subs.push(Simplify.simplify1(Regexp.Op.PLUS, re.flags, sub, null));
nre.subs = subs.slice(0);
return nre;
}
// Special case x{0} handled above.
// Special case: x{1} is just x.
if (re.min === 1 && re.max === 1) {
return sub;
}
// General case: x{n,m} means n copies of x and m copies of x?
// The machine will do less work if we nest the final m copies,
// so that x{2,5} = xx(x(x(x)?)?)?
// Build leading prefix: xx.
let prefixSubs = null;
if (re.min > 0) {
prefixSubs = [];
for (let i = 0; i < re.min; i++) {
prefixSubs.push(sub);
}
}
// Build and attach suffix: (x(x(x)?)?)?
if (re.max > re.min) {
let suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, sub, null);
for (let i = re.min + 1; i < re.max; i++) {
const nre2 = new Regexp(Regexp.Op.CONCAT);
nre2.subs = [sub, suffix];
suffix = Simplify.simplify1(Regexp.Op.QUEST, re.flags, nre2, null);
}
if (prefixSubs === null) {
return suffix;
}
prefixSubs.push(suffix);
}
if (prefixSubs !== null) {
const prefix = new Regexp(Regexp.Op.CONCAT);
prefix.subs = prefixSubs.slice(0);
return prefix;
}
// Some degenerate case like min > max or min < max < 0.
// Handle as impossible match.
return new Regexp(Regexp.Op.NO_MATCH);
}
}
return re;
}
// simplify1 implements Simplify for the unary OpStar,
// OpPlus, and OpQuest operators. It returns the simple regexp
// equivalent to
//
// Regexp{Op: op, Flags: flags, Sub: {sub}}
//
// under the assumption that sub is already simple, and
// without first allocating that structure. If the regexp
// to be returned turns out to be equivalent to re, simplify1
// returns re instead.
//
// simplify1 is factored out of Simplify because the implementation
// for other operators generates these unary expressions.
// Letting them call simplify1 makes sure the expressions they
// generate are simple.
static simplify1(op, flags, sub, re) {
// Special case: repeat the empty string as much as
// you want, but it's still the empty string.
if (sub.op === Regexp.Op.EMPTY_MATCH) {
return sub;
}
// The operators are idempotent if the flags match.
if (op === sub.op && (flags & RE2Flags.NON_GREEDY) === (sub.flags & RE2Flags.NON_GREEDY)) {
return sub;
}
if (re !== null && re.op === op && (re.flags & RE2Flags.NON_GREEDY) === (flags & RE2Flags.NON_GREEDY) && sub === re.subs[0]) {
return re;
}
re = new Regexp(op);
re.flags = flags;
re.subs = [sub];
return re;
}
}
// GENERATED BY tools/scripts/make_perl_groups.pl; DO NOT EDIT.
// ./tools/scripts/make_perl_groups.pl > src/CharGroup.js
class CharGroup {
constructor(sign, cls) {
this.sign = sign;
this.cls = cls;
}
}
const code1 = [0x30, 0x39];
const code2 = [0x9, 0xa, 0xc, 0xd, 0x20, 0x20];
const code3 = [0x30, 0x39, 0x41, 0x5a, 0x5f, 0x5f, 0x61, 0x7a];
const PERL_GROUPS = new Map([['\\d', new CharGroup(+1, code1)], ['\\D', new CharGroup(-1, code1)], ['\\s', new CharGroup(+1, code2)], ['\\S', new CharGroup(-1, code2)], ['\\w', new CharGroup(+1, code3)], ['\\W', new CharGroup(-1, code3)]]);
const code4 = [0x30, 0x39, 0x41, 0x5a, 0x61, 0x7a];
const code5 = [0x41, 0x5a, 0x61, 0x7a];
const code6 = [0x0, 0x7f];
const code7 = [0x9, 0x9, 0x20, 0x20];
const code8 = [0x0, 0x1f, 0x7f, 0x7f];
const code9 = [0x30, 0x39];
const code10 = [0x21, 0x7e];
const code11 = [0x61, 0x7a];
const code12 = [0x20, 0x7e];
const code13 = [0x21, 0x2f, 0x3a, 0x40, 0x5b, 0x60, 0x7b, 0x7e];
const code14 = [0x9, 0xd, 0x20, 0x20];
const code15 = [0x41, 0x5a];
const code16 = [0x30, 0x39, 0x41, 0x5a, 0x5f, 0x5f, 0x61, 0x7a];
const code17 = [0x30, 0x39, 0x41, 0x46, 0x61, 0x66];
const POSIX_GROUPS = new Map([['[:alnum:]', new CharGroup(+1, code4)], ['[:^alnum:]', new CharGroup(-1, code4)], ['[:alpha:]', new CharGroup(+1, code5)], ['[:^alpha:]', new CharGroup(-1, code5)], ['[:ascii:]', new CharGroup(+1, code6)], ['[:^ascii:]', new CharGroup(-1, code6)], ['[:blank:]', new CharGroup(+1, code7)], ['[:^blank:]', new CharGroup(-1, code7)], ['[:cntrl:]', new CharGroup(+1, code8)], ['[:^cntrl:]', new CharGroup(-1, code8)], ['[:digit:]', new CharGroup(+1, code9)], ['[:^digit:]', new CharGroup(-1, code9)], ['[:graph:]', new CharGroup(+1, code10)], ['[:^graph:]', new CharGroup(-1, code10)], ['[:lower:]', new CharGroup(+1, code11)], ['[:^lower:]', new CharGroup(-1, code11)], ['[:print:]', new CharGroup(+1, code12)], ['[:^print:]', new CharGroup(-1, code12)], ['[:punct:]', new CharGroup(+1, code13)], ['[:^punct:]', new CharGroup(-1, code13)], ['[:space:]', new CharGroup(+1, code14)], ['[:^space:]', new CharGroup(-1, code14)], ['[:upper:]', new CharGroup(+1, code15)], ['[:^upper:]', new CharGroup(-1, code15)], ['[:word:]', new CharGroup(+1, code16)], ['[:^word:]', new CharGroup(-1, code16)], ['[:xdigit:]', new CharGroup(+1, code17)], ['[:^xdigit:]', new CharGroup(-1, code17)]]);
/**
* A "builder"-style helper class for manipulating character classes represented as an array of
* pairs of runes [lo, hi], each denoting an inclusive interval.
*
* All methods mutate the internal state and return {@code this}, allowing operations to be chained.
*/
class CharClass {
// Exposed, since useful for debugging CharGroups too.
static charClassToString(r, len) {
let result = '[';
for (let i = 0; i < len; i += 2) {
if (i > 0) {
result += ' ';
}
const lo = r[i];
const hi = r[i + 1];
if (lo === hi) {
result += `0x${lo.toString(16)}`;
} else {
result += `0x${lo.toString(16)}-0x${hi.toString(16)}`;
}
}
result += ']';
return result;
}
// cmp() returns the ordering of the pair (a[i], a[i+1]) relative to
// (pivotFrom, pivotTo), where the first component of the pair (lo) is
// ordered naturally and the second component (hi) is in reverse order.
static cmp(array, i, pivotFrom, pivotTo) {
const cmp = array[i] - pivotFrom;
return cmp !== 0 ? cmp : pivotTo - array[i + 1];
}
// qsortIntPair() quicksorts pairs of ints in |array| according to lt().
// Precondition: |left|, |right|, |this.len| must all be even; |this.len > 1|.
static qsortIntPair(array, left, right) {
const pivotIndex = ((left + right) / 2 | 0) & ~1;
const pivotFrom = array[pivotIndex];
const pivotTo = array[pivotIndex + 1];
let i = left;
let j = right;
while (i <= j) {
while (i < right && CharClass.cmp(array, i, pivotFrom, pivotTo) < 0) {
i += 2;
}
while (j > left && CharClass.cmp(array, j, pivotFrom, pivotTo) > 0) {
j -= 2;
}
if (i <= j) {
if (i !== j) {
let temp = array[i];
array[i] = array[j];
array[j] = temp;
temp = array[i + 1];
array[i + 1] = array[j + 1];
array[j + 1] = temp;
}
i += 2;
j -= 2;
}
}
if (left < j) {
CharClass.qsortIntPair(array, left, j);
}
if (i < right) {
CharClass.qsortIntPair(array, i, right);
}
}
constructor(r = Utils.emptyInts()) {
this.r = r; // inclusive ranges, pairs of [lo,hi]. r.length is even.
this.len = r.length; // prefix of |r| that is defined. Even.
}
// Returns the character class as an int array. Subsequent CharClass
// operations may mutate this array, so typically this is the last operation
// performed on a given CharClass instance.
toArray() {
if (this.len === this.r.length) {
return this.r;
} else {
return this.r.slice(0, this.len);
}
}
// cleanClass() sorts the ranges (pairs of elements) of this CharClass,
// merges them, and eliminates duplicates.
cleanClass() {
if (this.len < 4) {
return this;
}
// Sort by lo increasing, hi decreasing to break ties.
CharClass.qsortIntPair(this.r, 0, this.len - 2);
// Merge abutting, overlapping.
let w = 2; // write index
for (let i = 2; i < this.len; i += 2) {
{
const lo = this.r[i];
const hi = this.r[i + 1];
if (lo <= this.r[w - 1] + 1) {
// merge with previous range
if (hi > this.r[w - 1]) {
this.r[w - 1] = hi;
}
continue;
}
// new disjoint range
this.r[w] = lo;
this.r[w + 1] = hi;
w += 2;
}
}
this.len = w;
return this;
}
// appendLiteral() appends the literal |x| to this CharClass.
appendLiteral(x, flags) {
return (flags & RE2Flags.FOLD_CASE) !== 0 ? this.appendFoldedRange(x, x) : this.appendRange(x, x);
}
// appendRange() appends the range [lo-hi] (inclusive) to this CharClass.
appendRange(lo, hi) {
// Expand last range or next to last range if it overlaps or abuts.
// Checking two ranges helps when appending case-folded
// alphabets, so that one range can be expanding A-Z and the
// other expanding a-z.
if (this.len > 0) {
for (let i = 2; i <= 4; i += 2) {
// twice, using i=2, i=4
if (this.len >= i) {
const rlo = this.r[this.len - i];
const rhi = this.r[this.len - i + 1];
if (lo <= rhi + 1 && rlo <= hi + 1) {
if (lo < rlo) {
this.r[this.len - i] = lo;
}
if (hi > rhi) {
this.r[this.len - i + 1] = hi;
}
return this;
}
}
}
}
this.r[this.len++] = lo;
this.r[this.len++] = hi;
return this;
}
// appendFoldedRange() appends the range [lo-hi] and its case
// folding-equivalent runes to this CharClass.
appendFoldedRange(lo, hi) {
// Optimizations.
if (lo <= Unicode.MIN_FOLD && hi >= Unicode.MAX_FOLD) {
// Range is full: folding can't add more.
return this.appendRange(lo, hi);
}
if (hi < Unicode.MIN_FOLD || lo > Unicode.MAX_FOLD) {
// Range is outside folding possibilities.
return this.appendRange(lo, hi);
}
if (lo < Unicode.MIN_FOLD) {
// [lo, minFold-1] needs no folding.
this.appendRange(lo, Unicode.MIN_FOLD - 1);
lo = Unicode.MIN_FOLD;
}
if (hi > Unicode.MAX_FOLD) {
// [maxFold+1, hi] needs no folding.
this.appendRange(Unicode.MAX_FOLD + 1, hi);
hi = Unicode.MAX_FOLD;
}
// Brute force. Depend on appendRange to coalesce ranges on the fly.
for (let c = lo; c <= hi; c++) {
this.appendRange(c, c);
for (let f = Unicode.simpleFold(c); f !== c; f = Unicode.simpleFold(f)) {
this.appendRange(f, f);
}
}
return this;
}
// appendClass() appends the class |x| to this CharClass.
// It assumes |x| is clean. Does not mutate |x|.
appendClass(x) {
for (let i = 0; i < x.length; i += 2) {
this.appendRange(x[i], x[i + 1]);
}
return this;
}
// appendFoldedClass() appends the case folding of the class |x| to this
// CharClass. Does not mutate |x|.
appendFoldedClass(x) {
for (let i = 0; i < x.length; i += 2) {
this.appendFoldedRange(x[i], x[i + 1]);
}
return this;
}
// appendNegatedClass() append the negation of the class |x| to this
// CharClass. It assumes |x| is clean. Does not mutate |x|.
appendNegatedClass(x) {
let nextLo = 0;
for (let i = 0; i < x.length; i += 2) {
const lo = x[i];
const hi = x[i + 1];
if (nextLo <= lo - 1) {
this.appendRange(nextLo, lo - 1);
}
nextLo = hi + 1;
}
if (nextLo <= Unicode.MAX_RUNE) {
this.appendRange(nextLo, Unicode.MAX_RUNE);
}
return this;
}
// appendTable() appends the Unicode range table |table| to this CharClass.
// Does not mutate |table|.
appendTable(table) {
for (let triple of table) {
const lo = triple[0];
const hi = triple[1];
const stride = triple[2];
if (stride === 1) {
this.appendRange(lo, hi);
continue;
}
for (let c = lo; c <= hi; c += stride) {
this.appendRange(c, c);
}
}
return this;
}
// appendNegatedTable() returns the result of appending the negation of range
// table |table| to this CharClass. Does not mutate |table|.
appendNegatedTable(table) {
let nextLo = 0;
for (let triple of table) {
const lo = triple[0];
const hi = triple[1];
const stride = triple[2];
if (stride === 1) {
if (nextLo <= lo - 1) {
this.appendRange(nextLo, lo - 1);
}
nextLo = hi + 1;
continue;
}
for (let c = lo; c <= hi; c += stride) {
if (nextLo <= c - 1) {
this.appendRange(nextLo, c - 1);
}
nextLo = c + 1;
}
}
if (nextLo <= Unicode.MAX_RUNE) {
this.appendRange(nextLo, Unicode.MAX_RUNE);
}
return this;
}
// appendTableWithSign() calls append{,Negated}Table depending on sign.
// Does not mutate |table|.
appendTableWithSign(table, sign) {
return sign < 0 ? this.appendNegatedTable(table) : this.appendTable(table);
}
// negateClass() negates this CharClass, which must already be clean.
negateClass() {
let nextLo = 0; // lo end of next class to add
let w = 0; // write index
for (let i = 0; i < this.len; i += 2) {
const lo = this.r[i];
const hi = this.r[i + 1];
if (nextLo <= lo - 1) {
this.r[w] = nextLo;
this.r[w + 1] = lo - 1;
w += 2;
}
nextLo = hi + 1;
}
this.len = w;
if (nextLo <= Unicode.MAX_RUNE) {
this.r[this.len++] = nextLo;
this.r[this.len++] = Unicode.MAX_RUNE;
}
return this;
}
// appendClassWithSign() calls appendClass() if sign is +1 or
// appendNegatedClass if sign is -1. Does not mutate |x|.
appendClassWithSign(x, sign) {
return sign < 0 ? this.appendNegatedClass(x) : this.appendClass(x);
}
// appendGroup() appends CharGroup |g| to this CharClass, folding iff
// |foldCase|. Does not mutate |g|.
appendGroup(g, foldCase) {
let cls = g.cls;
if (foldCase) {
cls = new CharClass().appendFoldedClass(cls).cleanClass().toArray();
}
return this.appendClassWithSign(cls, g.sign);
}
toString() {
return CharClass.charClassToString(this.r, this.len);
}
}
class Pair {
static of(first, second) {
return new Pair(first, second);
}
constructor(first, second) {
this.first = first;
this.second = second;
}
}
// StringIterator: a stream of runes with an opaque cursor, permitting
// rewinding. The units of the cursor are not specified beyond the
// fact that ASCII characters are single width. (Cursor positions
// could be UTF-8 byte indices, UTF-16 code indices or rune indices.)
//
// In particular, be careful with:
// - skip: only use this to advance over ASCII characters
// since these always have a width of 1.
// - skipString: only use this to advance over strings which are
// known to be at the current position, e.g. due to prior call to
// lookingAt().
// Only use pop() to advance over possibly non-ASCII runes.
class StringIterator {
constructor(str) {
this.str = str;
this.position = 0;
}
// Returns the cursor position. Do not interpret the result!
pos() {
return this.position;
}
// Resets the cursor position to a previous value returned by pos().
rewindTo(pos) {
this.position = pos;
}
// Returns true unless the stream is exhausted.
more() {
return this.position < this.str.length;
}
// Returns the rune at the cursor position.
// Precondition: |more()|.
peek() {
return this.str.codePointAt(this.position);
}
// Advances the cursor by |n| positions, which must be ASCII runes.
//
// (In practise, this is only ever used to skip over regexp
// metacharacters that are ASCII, so there is no numeric difference
// between indices into UTF-8 bytes, UTF-16 codes and runes.)
skip(n) {
this.position += n;
}
// Advances the cursor by the number of cursor positions in |s|.
skipString(s) {
this.position += s.length;
}
// Returns the rune at the cursor position, and advances the cursor
// past it. Precondition: |more()|.
pop() {
const r = this.str.codePointAt(this.position);
this.position += Utils.charCount(r);
return r;
}
lookingAt(s) {
return this.rest().startsWith(s);
}
// Returns the rest of the pattern as a Java UTF-16 string.
rest() {
return this.str.substring(this.position);
}
// Returns the substring from |beforePos| to the current position.
// |beforePos| must have been previously returned by |pos()|.
from(beforePos) {
return this.str.substring(beforePos, this.position);
}
toString() {
return this.rest();
}
}
/**
* A parser of regular expression patterns.
*
* The only public entry point is {@link #parse(String pattern, int flags)}.
*/
class Parser {
// Unexpected error
static ERR_INTERNAL_ERROR = 'regexp/syntax: internal error';
// Parse errors
static ERR_INVALID_CHAR_RANGE = 'invalid character class range';
static ERR_INVALID_ESCAPE = 'invalid escape sequence';
static ERR_INVALID_NAMED_CAPTURE = 'invalid named capture';
static ERR_INVALID_PERL_OP = 'invalid or unsupported Perl syntax';
static ERR_INVALID_REPEAT_OP = 'invalid nested repetition operator';
static ERR_INVALID_REPEAT_SIZE = 'invalid repeat count';
static ERR_MISSING_BRACKET = 'missing closing ]';
static ERR_MISSING_PAREN = 'missing closing )';
static ERR_MISSING_REPEAT_ARGUMENT = 'missing argument to repetition operator';
static ERR_TRAILING_BACKSLASH = 'trailing backslash at end of expression';
static ERR_DUPLICATE_NAMED_CAPTURE = 'duplicate capture group name';
// RangeTables are represented as int[][], a list of triples (start, end,
// stride).
static ANY_TABLE() {
return [[0, Unicode.MAX_RUNE, 1]];
}
// unicodeTable() returns the Unicode RangeTable identified by name
// and the table of additional fold-equivalent code points.
// Returns null if |name| does not identify a Unicode character range.
static unicodeTable(name) {
if (name === 'Any') {
return Pair.of(Parser.ANY_TABLE(), Parser.ANY_TABLE());
}
if (UnicodeTables.CATEGORIES.has(name)) {
return Pair.of(UnicodeTables.CATEGORIES.get(name), UnicodeTables.FOLD_CATEGORIES.get(name));
}
if (UnicodeTables.SCRIPTS.has(name)) {
return Pair.of(UnicodeTables.SCRIPTS.get(name), UnicodeTables.FOLD_SCRIPT.get(name));
}
return null;
}
// minFoldRune returns the minimum rune fold-equivalent to r.
static minFoldRune(r) {
if (r < Unicode.MIN_FOLD || r > Unicode.MAX_FOLD) {
return r;
}
let min = r;
const r0 = r;
for (r = Unicode.simpleFold(r); r !== r0; r = Unicode.simpleFold(r)) {
if (min > r) {
min = r;
}
}
return min;
}
// leadingRegexp returns the leading regexp that re begins with.
// The regexp refers to storage in re or its children.
static leadingRegexp(re) {
if (re.op === Regexp.Op.EMPTY_MATCH) {
return null;
}
if (re.op === Regexp.Op.CONCAT && re.subs.length > 0) {
const sub = re.subs[0];
if (sub.op === Regexp.Op.EMPTY_MATCH) {
return null;
}
return sub;
}
return re;
}
static literalRegexp(s, flags) {
const re = new Regexp(Regexp.Op.LITERAL);
re.flags = flags;
re.runes = Utils.stringToRunes(s);
return re;
}
/**
* Parse regular expression pattern {@code pattern} with mode flags {@code flags}.
* @param {string} pattern
* @param {number} flags
*/
static parse(pattern, flags) {
return new Parser(pattern, flags).parseInternal();
}
// parseRepeat parses {min} (max=min) or {min,} (max=-1) or {min,max}.
// If |t| is not of that form, it returns -1.
// If |t| has the right form but the values are negative or too big,
// it returns -2.
// On success, returns a nonnegative number encoding min/max in the
// high/low signed halfwords of the result. (Note: min >= 0; max may
// be -1.)
//
// On success, advances |t| beyond the repeat; otherwise |t.pos()| is
// undefined.
static parseRepeat(t) {
const start = t.pos();
if (!t.more() || !t.lookingAt('{')) {
return -1;
}
t.skip(1);
const min = Parser.parseInt(t);
if (min === -1) {
return -1;
}
if (!t.more()) {
return -1;
}
let max;
if (!t.lookingAt(',')) {
max = min;
} else {
t.skip(1);
if (!t.more()) {
return -1;
}
if (t.lookingAt('}')) {
max = -1;
} else if ((max = Parser.parseInt(t)) === -1) {
return -1;
}
}
if (!t.more() || !t.lookingAt('}')) {
return -1;
}
t.skip(1);
if (min < 0 || min > 1000 || max === -2 || max > 1000 || max >= 0 && min > max) {
throw new RE2JSSyntaxException(Parser.ERR_INVALID_REPEAT_SIZE, t.from(start));
}
return min << 16 | max & Unicode.MAX_BMP;
}
// isValidCaptureName reports whether name
// is a valid capture name: [A-Za-z0-9_]+.
// PCRE limits names to 32 bytes.
// Python rejects names starting with digits.
// We don't enforce either of those.
static isValidCaptureName(name) {
if (name.length === 0) {
return false;
}
for (let i = 0; i < name.length; i++) {
const c = name.codePointAt(i);
if (c !== Codepoint.CODES.get('_') && !Utils.isalnum(c)) {
return false;
}
}
return true;
}
// parseInt parses a nonnegative decimal integer.
// -1 => bad format. -2 => format ok, but integer overflow.
static parseInt(t) {
const start = t.pos();
while (t.more() && t.peek() >= Codepoint.CODES.get('0') && t.peek() <= Codepoint.CODES.get('9')) {
t.skip(1);
}
const n = t.from(start);
if (n.length === 0 || n.length > 1 && n.codePointAt(0) === Codepoint.CODES.get('0')) {
return -1;
}
if (n.length > 8) {
return -2;
}
return parseFloat(n, 10);
}
// can this be represented as a character class?
// single-rune literal string, char class, ., and .|\n.
static isCharClass(re) {
return re.op === Regexp.Op.LITERAL && re.runes.length === 1 || re.op === Regexp.Op.CHAR_CLASS || re.op === Regexp.Op.ANY_CHAR_NOT_NL || re.op === Regexp.Op.ANY_CHAR;
}
// does re match r?
static matchRune(re, r) {
switch (re.op) {
case Regexp.Op.LITERAL:
return re.runes.length === 1 && re.runes[0] === r;
case Regexp.Op.CHAR_CLASS:
for (let i = 0; i < re.runes.length; i += 2) {
if (re.runes[i] <= r && r <= re.runes[i + 1]) {
return true;
}
}
return false;
case Regexp.Op.ANY_CHAR_NOT_NL:
return r !== Codepoint.CODES.get('\n');
case Regexp.Op.ANY_CHAR:
return true;
}
return false;
}
// mergeCharClass makes dst = dst|src.
// The caller must ensure that dst.Op >= src.Op,
// to reduce the amount of copying.
static mergeCharClass(dst, src) {
switch (dst.op) {
case Regexp.Op.ANY_CHAR:
break;
case Regexp.Op.ANY_CHAR_NOT_NL:
if (Parser.matchRune(src, Codepoint.CODES.get('\n'))) {
dst.op = Regexp.Op.ANY_CHAR;
}
break;
case Regexp.Op.CHAR_CLASS:
if (src.op === Regexp.Op.LITERAL) {
dst.runes = new CharClass(dst.runes).appendLiteral(src.runes[0], src.flags).toArray();
} else {
dst.runes = new CharClass(dst.runes).appendClass(src.runes).toArray();
}
break;
case Regexp.Op.LITERAL:
if (src.runes[0] === dst.runes[0] && src.flags === dst.flags) {
break;
}
dst.op = Regexp.Op.CHAR_CLASS;
dst.runes = new CharClass().appendLiteral(dst.runes[0], dst.flags).appendLiteral(src.runes[0], src.flags).toArray();
break;
}
}
// parseEscape parses an escape sequence at the beginning of s
// and returns the rune.
// Pre: t at '\\'. Post: after escape.
static parseEscape(t) {
const startPos = t.pos();
t.skip(1); // '\\'
if (!t.more()) {
throw new RE2JSSyntaxException(Parser.ERR_TRAILING_BACKSLASH);
}
let c = t.pop();
bigswitch: switch (c) {
case Codepoint.CODES.get('1'):
case Codepoint.CODES.get('2'):
case Codepoint.CODES.get('3'):
case Codepoint.CODES.get('4'):
case Codepoint.CODES.get('5'):
case Codepoint.CODES.get('6'):
case Codepoint.CODES.get('7'):
{
if (!t.more() || t.peek() < Codepoint.CODES.get('0') || t.peek() > Codepoint.CODES.get('7')) {
break;
}
}
// eslint-disable-next-line no-fallthrough
case Codepoint.CODES.get('0'):
{
let r = c - Codepoint.CODES.get('0');
for (let i = 1; i < 3; i++) {
if (!t.more() || t.peek() < Codepoint.CODES.get('0') || t.peek() > Codepoint.CODES.get('7')) {
break;
}
r = r * 8 + t.peek() - Codepoint.CODES.get('0');
t.skip(1);
}
return r;
}
case Codepoint.CODES.get('x'):
{
if (!t.more()) {
break;
}
c = t.pop();
if (c === Codepoint.CODES.get('{')) {
let nhex = 0;
let r = 0;
// eslint-disable-next-line no-constant-condition
while (true) {
if (!t.more()) {
break bigswitch;
}
c = t.pop();
if (c === Codepoint.CODES.get('}')) {
break;
}
const v = Utils.unhex(c);
if (v < 0) {
break bigswitch;
}
r = r * 16 + v;
if (r > Unicode.MAX_RUNE) {
break bigswitch;
}
nhex++;
}
if (nhex === 0) {
break bigswitch;
}
return r;
}
const x = Utils.unhex(c);
if (!t.more()) {
break;
}
c = t.pop();
const y = Utils.unhex(c);
if (x < 0 || y < 0) {
break;
}
return x * 16 + y;
}
case Codepoint.CODES.get('a'):
return Codepoint.CODES.get('\x07');
case Codepoint.CODES.get('f'):
return Codepoint.CODES.get('\f');
case Codepoint.CODES.get('n'):
return Codepoint.CODES.get('\n');
case Codepoint.CODES.get('r'):
return Codepoint.CODES.get('\r');
case Codepoint.CODES.get('t'):
return Codepoint.CODES.get('\t');
case Codepoint.CODES.get('v'):
return Codepoint.CODES.get('\v');
default:
if (!Utils.isalnum(c)) {
return c;
}
break;
}
throw new RE2JSSyntaxException(Parser.ERR_INVALID_ESCAPE, t.from(startPos));
}
// parseClassChar parses a character class character and returns it.
// wholeClassPos is the position of the start of the entire class "[...".
// Pre: t at class char; Post: t after it.
static parseClassChar(t, wholeClassPos) {
if (!t.more()) {
throw new RE2JSSyntaxException(Parser.ERR_MISSING_BRACKET, t.from(wholeClassPos));
}
if (t.lookingAt('\\')) {
return Parser.parseEscape(t);
}
return t.pop();
}
static concatRunes(x, y) {
return [...x, ...y];
}
constructor(wholeRegexp, flags = 0) {
this.wholeRegexp = wholeRegexp;
// Flags control the behavior of the parser and record information about
// regexp context.
this.flags = flags;
// number of capturing groups seen
this.numCap = 0;
this.namedGroups = {};
// Stack of parsed expressions.
this.stack = [];
this.free = null;
}
// Allocate a Regexp, from the free list if possible.
newRegexp(op) {
let re = this.free;
if (re !== null && re.subs !== null && re.subs.length > 0) {
this.free = re.subs[0];
re.reinit();
re.op = op;
} else {
re = new Regexp(op);
}
return re;
}
reuse(re) {
if (re.subs !== null && re.subs.length > 0) {
re.subs[0] = this.free;
}
this.free = re;
}
// Parse stack manipulation.
pop() {
return this.stack.pop();
}
popToPseudo() {
const n = this.stack.length;
let i = n;
while (i > 0 && !Regexp.isPseudoOp(this.stack[i - 1].op)) {
i--;
}
const r = this.stack.slice(i, n);
this.stack = this.stack.slice(0, i);
return r;
}
// push pushes the regexp re onto the parse stack and returns the regexp.
// Returns null for a CHAR_CLASS that can be merged with the top-of-stack.
push(re) {
if (re.op === Regexp.Op.CHAR_CLASS && re.runes.length === 2 && re.runes[0] === re.runes[1]) {
if (this.maybeConcat(re.runes[0], this.flags & ~RE2Flags.FOLD_CASE)) {
return null;
}
re.op = Regexp.Op.LITERAL;
re.runes = [re.runes[0]];
re.flags = this.flags & ~RE2Flags.FOLD_CASE;
} else if (re.op === Regexp.Op.CHAR_CLASS && re.runes.length === 4 && re.runes[0] === re.runes[1] && re.runes[2] === re.runes[3] && Unicode.simpleFold(re.runes[0]) === re.runes[2] && Unicode.simpleFold(re.runes[2]) === re.runes[0] || re.op === Regexp.Op.CHAR_CLASS && re.runes.length === 2 && re.runes[0] + 1 === re.runes[1] && Unicode.simpleFold(re.runes[0]) === re.runes[1] && Unicode.simpleFold(re.runes[1]) === re.runes[0]) {
// Case-insensitive rune like [Aa] or [Δδ].
if (this.maybeConcat(re.runes[0], this.flags | RE2Flags.FOLD_CASE)) {
return null;
}
// Rewrite as (case-insensitive) literal.
re.op = Regexp.Op.LITERAL;
re.runes = [re.runes[0]];
re.flags = this.flags | RE2Flags.FOLD_CASE;
} else {
// Incremental concatenation.
this.maybeConcat(-1, 0);
}
this.stack.push(re);
return re;
}
// maybeConcat implements incremental concatenation
// of literal runes into string nodes. The parser calls this
// before each push, so only the top fragment of the stack
// might need processing. Since this is called before a push,
// the topmost literal is no longer subject to operators like *
// (Otherwise ab* would turn into (ab)*.)
// If (r >= 0 and there's a node left over, maybeConcat uses it
// to push r with the given flags.
// maybeConcat reports whether r was pushed.
maybeConcat(r, flags) {
const n = this.stack.length;
if (n < 2) {
return false;
}
const re1 = this.stack[n - 1];
const re2 = this.stack[n - 2];
if (re1.op !== Regexp.Op.LITERAL || re2.op !== Regexp.Op.LITERAL || (re1.flags & RE2Flags.FOLD_CASE) !== (re2.flags & RE2Flags.FOLD_CASE)) {
return false;
}
// Push re1 into re2.
re2.runes = Parser.concatRunes(re2.runes, re1.runes);
// Reuse re1 if possible.
if (r >= 0) {
re1.runes = [r];
re1.flags = flags;
return true;
}
this.pop();
this.reuse(re1);
return false; // did not push r
}
// newLiteral returns a new LITERAL Regexp with the given flags
newLiteral(r, flags) {
const re = this.newRegexp(Regexp.Op.LITERAL);
re.flags = flags;
if ((flags & RE2Flags.FOLD_CASE) !== 0) {
r = Parser.minFoldRune(r);
}
re.runes = [r];
return re;
}
// literal pushes a literal regexp for the rune r on the stack
// and returns that regexp.
literal(r) {
this.push(this.newLiteral(r, this.flags));
}
// op pushes a regexp with the given op onto the stack
// and returns that regexp.
op(op) {
const re = this.newRegexp(op);
re.flags = this.flags;
return this.push(re);
}
// repeat replaces the top stack element with itself repeated according to
// op, min, max. beforePos is the start position of the repetition operator.
// Pre: t is positioned after the initial repetition operator.
// Post: t advances past an optional perl-mode '?', or stays put.
// Or, it fails with RE2JSSyntaxException.
repeat(op, min, max, beforePos, t, lastRepeatPos) {
let flags = this.flags;
if ((flags & RE2Flags.PERL_X) !== 0) {
if (t.more() && t.lookingAt('?')) {
t.skip(1);
flags ^= RE2Flags.NON_GREEDY;
}
if (lastRepeatPos !== -1) {
// In Perl it is not allowed to stack repetition operators:
// a** is a syntax error, not a doubled star, and a++ means
// something else entirely, which we don't support!
throw new RE2JSSyntaxException(Parser.ERR_INVALID_REPEAT_OP, t.from(lastRepeatPos));
}
}
const n = this.stack.length;
if (n === 0) {
throw new RE2JSSyntaxException(Parser.ERR_MISSING_REPEAT_ARGUMENT, t.from(beforePos));
}
const sub = this.stack[n - 1];
if (Regexp.isPseudoOp(sub.op)) {
throw new RE2JSSyntaxException(Parser.ERR_MISSING_REPEAT_ARGUMENT, t.from(beforePos));
}
const re = this.newRegexp(op);
re.min = min;
re.max = max;
re.flags = flags;
re.subs = [sub];
this.stack[n - 1] = re;
}
// concat replaces the top of the stack (above the topmost '|' or '(') with
// its concatenation.
concat() {
this.maybeConcat(-1, 0);
const subs = this.popToPseudo();
if (subs.length === 0) {
return this.push(this.newRegexp(Regexp.Op.EMPTY_MATCH));
}
return this.push(this.collapse(subs, Regexp.Op.CONCAT));
}
// alternate replaces the top of the stack (above the topmost '(') with its
// alternation.
alternate() {
// Scan down to find pseudo-operator (.
// There are no | above (.
const subs = this.popToPseudo();
// Make sure top class is clean.
// All the others already are (see swapVerticalBar).
if (subs.length > 0) {
this.cleanAlt(subs[subs.length - 1]);
}
// Empty alternate is special case
// (shouldn't happen but easy to handle).
if (subs.length === 0) {
return this.push(this.newRegexp(Regexp.Op.NO_MATCH));
}
return this.push(this.collapse(subs, Regexp.Op.ALTERNATE));
}
// cleanAlt cleans re for eventual inclusion in an alternation.
cleanAlt(re) {
if (re.op === Regexp.Op.CHAR_CLASS) {
re.runes = new CharClass(re.runes).cleanClass().toArray();
if (re.runes.length === 2 && re.runes[0] === 0 && re.runes[1] === Unicode.MAX_RUNE) {
re.runes = null;
re.op = Regexp.Op.ANY_CHAR;
} else if (re.runes.length === 4 && re.runes[0] === 0 && re.runes[1] === Codepoint.CODES.get('\n') - 1 && re.runes[2] === Codepoint.CODES.get('\n') + 1 && re.runes[3] === Unicode.MAX_RUNE) {
re.runes = null;
re.op = Regexp.Op.ANY_CHAR_NOT_NL;
}
}
}
// collapse returns the result of applying op to subs[start:end].
// If (sub contains op nodes, they all get hoisted up
// so that there is never a concat of a concat or an
// alternate of an alternate.
collapse(subs, op) {
if (subs.length === 1) {
return subs[0];
}
// Concatenate subs iff op is same.
// Compute length in first pass.
let len = 0;
for (let sub of subs) {
len += sub.op === op ? sub.subs.length : 1;
}
let newsubs = new Array(len).fill(null);
let i = 0;
for (let sub of subs) {
if (sub.op === op) {
newsubs.splice(i, sub.subs.length, ...sub.subs);
i += sub.subs.length;
this.reuse(sub);
} else {
newsubs[i++] = sub;
}
}
let re = this.newRegexp(op);
re.subs = newsubs;
if (op === Regexp.Op.ALTERNATE) {
// re.subs = this.factor(re.subs, re.flags)
re.subs = this.factor(re.subs);
if (re.subs.length === 1) {
const old = re;
re = re.subs[0];
this.reuse(old);
}
}
return re;
}
// factor factors common prefixes from the alternation list sub. It
// returns a replacement list that reuses the same storage and frees
// (passes to p.reuse) any removed *Regexps.
//
// For example,
// ABC|ABD|AEF|BCX|BCY
// simplifies by literal prefix extraction to
// A(B(C|D)|EF)|BC(X|Y)
// which simplifies by character class introduction to
// A(B[CD]|EF)|BC[XY]
//
factor(array) {
if (array.length < 2) {
return array;
}
// The following code is subtle, because it's a literal JS
// translation of code that makes clever use of Go "slices".
// A slice is a triple (array, offset, length), and the Go
// implementation uses two slices, |sub| and |out| backed by the
// same array. In JS, we have to be explicit about all of these
// variables, so:
//
// Go JS
// sub (array, s, lensub)
// out (array, 0, lenout) // (always a prefix of |array|)
//
// In the comments we'll use the logical notation of go slices, e.g. sub[i]
// even though the JS code will read array[s + i].
let s = 0; // offset of first |sub| within array.
let lensub = array.length; // = len(sub)
let lenout = 0; // = len(out)
// Round 1: Factor out common literal prefixes.
// Note: (str, strlen) and (istr, istrlen) are like Go slices
// onto a prefix of some Regexp's runes array (hence offset=0).
let str = null;
let strlen = 0;
let strflags = 0;
let start = 0;
for (let i = 0; i <= lensub; i++) {
// Invariant: the Regexps that were in sub[0:start] have been
// used or marked for reuse, and the slice space has been reused
// for out (len <= start).
//
// Invariant: sub[start:i] consists of regexps that all begin
// with str as modified by strflags.
let istr = null;
let istrlen = 0;
let iflags = 0;
if (i < lensub) {
// NB, we inlined Go's leadingString() since Java has no pair return.
let re = array[s + i];
if (re.op === Regexp.Op.CONCAT && re.subs.length > 0) {
re = re.subs[0];
}
if (re.op === Regexp.Op.LITERAL) {
istr = re.runes;
istrlen = re.runes.length;
iflags = re.flags & RE2Flags.FOLD_CASE;
}
// istr is the leading literal string that re begins with.
// The string refers to storage in re or its children.
if (iflags === strflags) {
let same = 0;
while (same < strlen && same < istrlen && str[same] === istr[same]) {
same++;
}
if (same > 0) {
// Matches at least one rune in current range.
// Keep going around.
strlen = same;
continue;
}
}
}
// Found end of a run with common leading literal string:
// sub[start:i] all begin with str[0:strlen], but sub[i]
// does not even begin with str[0].
//
// Factor out common string and append factored expression to out.
if (i === start) ; else if (i === start + 1) {
// Just one: don't bother factoring.
array[lenout++] = array[s + start];
} else {
// Construct factored form: prefix(suffix1|suffix2|...)
const prefix = this.newRegexp(Regexp.Op.LITERAL);
prefix.flags = strflags;
prefix.runes = str.slice(0, strlen);
for (let j = start; j < i; j++) {
array[s + j] = this.removeLeadingString(array[s + j], strlen);
}
// Recurse.
const suffix = this.collapse(array.slice(s + start, s + i), Regexp.Op.ALTERNATE);
const re = this.newRegexp(Regexp.Op.CONCAT);
re.subs = [prefix, suffix];
array[lenout++] = re;
}
// Prepare for next iteration.
start = i;
str = istr;
strlen = istrlen;
strflags = iflags;
}
// In Go: sub = out
lensub = lenout;
s = 0;
// Round 2: Factor out common complex prefixes,
// just the first piece of each concatenation,
// whatever it is. This is good enough a lot of the time.
start = 0;
lenout = 0;
let first = null;
for (let i = 0; i <= lensub; i++) {
// Invariant: the Regexps that were in sub[0:start] have been
// used or marked for reuse, and the slice space has been reused
// for out (lenout <= start).
//
// Invariant: sub[start:i] consists of regexps that all begin with
// ifirst.
let ifirst = null;
if (i < lensub) {
ifirst = Parser.leadingRegexp(array[s + i]);
if (first !== null && first.equals(ifirst) && (Parser.isCharClass(first) || first.op === Regexp.Op.REPEAT && first.min === first.max && Parser.isCharClass(first.subs[0]))) {
continue;
}
}
// Found end of a run with common leading regexp:
// sub[start:i] all begin with first but sub[i] does not.
//
// Factor out common regexp and append factored expression to out.
if (i === start) ; else if (i === start + 1) {
// Just one: don't bother factoring.
array[lenout++] = array[s + start];
} else {
// Construct factored form: prefix(suffix1|suffix2|...)
const prefix = first;
for (let j = start; j < i; j++) {
const reuse = j !== start; // prefix came from sub[start]
array[s + j] = this.removeLeadingRegexp(array[s + j], reuse);
}
// recurse
const suffix = this.collapse(array.slice(s + start, s + i), Regexp.Op.ALTERNATE);
const re = this.newRegexp(Regexp.Op.CONCAT);
re.subs = [prefix, suffix];
array[lenout++] = re;
}
// Prepare for next iteration.
start = i;
first = ifirst;
}
// In Go: sub = out
lensub = lenout;
s = 0;
// Round 3: Collapse runs of single literals into character classes.
start = 0;
lenout = 0;
for (let i = 0; i <= lensub; i++) {
// Invariant: the Regexps that were in sub[0:start] have been
// used or marked for reuse, and the slice space has been reused
// for out (lenout <= start).
//
// Invariant: sub[start:i] consists of regexps that are either
// literal runes or character classes.
if (i < lensub && Parser.isCharClass(array[s + i])) {
continue;
}
// sub[i] is not a char or char class;
// emit char class for sub[start:i]...
if (i === start) ; else if (i === start + 1) {
// Just one: don't bother factoring.
array[lenout++] = array[s + start];
} else {
// Make new char class.
// Start with most complex regexp in sub[start].
let max = start;
for (let j = start + 1; j < i; j++) {
const subMax = array[s + max];
const subJ = array[s + j];
if (subMax.op < subJ.op || subMax.op === subJ.op && (subMax.runes !== null ? subMax.runes.length : 0) < (subJ.runes !== null ? subJ.runes.length : 0)) {
max = j;
}
}
// swap sub[start], sub[max].
const tmp = array[s + start];
array[s + start] = array[s + max];
array[s + max] = tmp;
for (let j = start + 1; j < i; j++) {
Parser.mergeCharClass(array[s + start], array[s + j]);
this.reuse(array[s + j]);
}
this.cleanAlt(array[s + start]);
array[lenout++] = array[s + start];
}
// ... and then emit sub[i].
if (i < lensub) {
array[lenout++] = array[s + i];
}
start = i + 1;
}
// In Go: sub = out
lensub = lenout;
s = 0;
// Round 4: Collapse runs of empty matches into a single empty match.
start = 0;
lenout = 0;
for (let i = 0; i < lensub; ++i) {
if (i + 1 < lensub && array[s + i].op === Regexp.Op.EMPTY_MATCH && array[s + i + 1].op === Regexp.Op.EMPTY_MATCH) {
continue;
}
array[lenout++] = array[s + i];
}
// In Go: sub = out
lensub = lenout;
s = 0;
return array.slice(s, lensub);
}
// removeLeadingString removes the first n leading runes
// from the beginning of re. It returns the replacement for re.
removeLeadingString(re, n) {
if (re.op === Regexp.Op.CONCAT && re.subs.length > 0) {
// Removing a leading string in a concatenation
// might simplify the concatenation.
const sub = this.removeLeadingString(re.subs[0], n);
re.subs[0] = sub;
if (sub.op === Regexp.Op.EMPTY_MATCH) {
this.reuse(sub);
switch (re.subs.length) {
case 0:
case 1:
// Impossible but handle.
re.op = Regexp.Op.EMPTY_MATCH;
re.subs = null;
break;
case 2:
{
const old = re;
re = re.subs[1];
this.reuse(old);
break;
}
default:
re.subs = re.subs.slice(1, re.subs.length);
break;
}
}
return re;
}
if (re.op === Regexp.Op.LITERAL) {
re.runes = re.runes.slice(n, re.runes.length);
if (re.runes.length === 0) {
re.op = Regexp.Op.EMPTY_MATCH;
}
}
return re;
}
// removeLeadingRegexp removes the leading regexp in re.
// It returns the replacement for re.
// If reuse is true, it passes the removed regexp (if no longer needed) to
// reuse.
removeLeadingRegexp(re, reuse) {
if (re.op === Regexp.Op.CONCAT && re.subs.length > 0) {
if (reuse) {
this.reuse(re.subs[0]);
}
re.subs = re.subs.slice(1, re.subs.length);
switch (re.subs.length) {
case 0:
{
re.op = Regexp.Op.EMPTY_MATCH;
re.subs = Regexp.emptySubs();
break;
}
case 1:
{
const old = re;
re = re.subs[0];
this.reuse(old);
break;
}
}
return re;
}
if (reuse) {
this.reuse(re);
}
return this.newRegexp(Regexp.Op.EMPTY_MATCH);
}
parseInternal() {
if ((this.flags & RE2Flags.LITERAL) !== 0) {
// Trivial parser for literal string.
return Parser.literalRegexp(this.wholeRegexp, this.flags);
}
// Otherwise, must do real work.
let lastRepeatPos = -1;
let min = -1;
let max = -1;
const t = new StringIterator(this.wholeRegexp);
while (t.more()) {
{
let repeatPos = -1;
bigswitch: switch (t.peek()) {
case Codepoint.CODES.get('('):
if ((this.flags & RE2Flags.PERL_X) !== 0 && t.lookingAt('(?')) {
// Flag changes and non-capturing groups.
this.parsePerlFlags(t);
break;
}
this.op(Regexp.Op.LEFT_PAREN).cap = ++this.numCap;
t.skip(1); // '('
break;
case Codepoint.CODES.get('|'):
this.parseVerticalBar(); // '|'
t.skip(1); // '|'
break;
case Codepoint.CODES.get(')'):
this.parseRightParen();
t.skip(1); // ')'
break;
case Codepoint.CODES.get('^'):
if ((this.flags & RE2Flags.ONE_LINE) !== 0) {
this.op(Regexp.Op.BEGIN_TEXT);
} else {
this.op(Regexp.Op.BEGIN_LINE);
}
t.skip(1); // '^'
break;
case Codepoint.CODES.get('$'):
if ((this.flags & RE2Flags.ONE_LINE) !== 0) {
this.op(Regexp.Op.END_TEXT).flags |= RE2Flags.WAS_DOLLAR;
} else {
this.op(Regexp.Op.END_LINE);
}
t.skip(1); // '$'
break;
case Codepoint.CODES.get('.'):
if ((this.flags & RE2Flags.DOT_NL) !== 0) {
this.op(Regexp.Op.ANY_CHAR);
} else {
this.op(Regexp.Op.ANY_CHAR_NOT_NL);
}
t.skip(1); // '.'
break;
case Codepoint.CODES.get('['):
this.parseClass(t);
break;
case Codepoint.CODES.get('*'):
case Codepoint.CODES.get('+'):
case Codepoint.CODES.get('?'):
{
repeatPos = t.pos();
let op = null;
switch (t.pop()) {
case Codepoint.CODES.get('*'):
op = Regexp.Op.STAR;
break;
case Codepoint.CODES.get('+'):
op = Regexp.Op.PLUS;
break;
case Codepoint.CODES.get('?'):
op = Regexp.Op.QUEST;
break;
}
this.repeat(op, min, max, repeatPos, t, lastRepeatPos);
// (min and max are now dead.)
break;
}
case Codepoint.CODES.get('{'):
{
repeatPos = t.pos();
const minMax = Parser.parseRepeat(t);
if (minMax < 0) {
// If the repeat cannot be parsed, { is a literal.
t.rewindTo(repeatPos);
this.literal(t.pop()); // '{'
break;
}
min = minMax >> 16;
max = (minMax & Unicode.MAX_BMP) << 16 >> 16;
this.repeat(Regexp.Op.REPEAT, min, max, repeatPos, t, lastRepeatPos);
break;
}
case Codepoint.CODES.get('\\'):
{
const savedPos = t.pos();
t.skip(1); // '\\'
if ((this.flags & RE2Flags.PERL_X) !== 0 && t.more()) {
const c = t.pop();
switch (c) {
case Codepoint.CODES.get('A'):
this.op(Regexp.Op.BEGIN_TEXT);
break bigswitch;
case Codepoint.CODES.get('b'):
this.op(Regexp.Op.WORD_BOUNDARY);
break bigswitch;
case Codepoint.CODES.get('B'):
this.op(Regexp.Op.NO_WORD_BOUNDARY);
break bigswitch;
case Codepoint.CODES.get('C'):
// any byte; not supported
throw new RE2JSSyntaxException(Parser.ERR_INVALID_ESCAPE, '\\C');
case Codepoint.CODES.get('Q'):
{
// \Q ... \E: the ... is always literals
let lit = t.rest();
const i = lit.indexOf('\\E');
if (i >= 0) {
lit = lit.substring(0, i);
}
t.skipString(lit);
t.skipString('\\E');
let j = 0;
while (j < lit.length) {
const codepoint = lit.codePointAt(j);
this.literal(codepoint);
j += Utils.charCount(codepoint);
}
break bigswitch;
}
case Codepoint.CODES.get('z'):
this.op(Regexp.Op.END_TEXT);
break bigswitch;
default:
t.rewindTo(savedPos);
break;
}
}
const re = this.newRegexp(Regexp.Op.CHAR_CLASS);
re.flags = this.flags;
// Look for Unicode character group like \p{Han}
if (t.lookingAt('\\p') || t.lookingAt('\\P')) {
const cc = new CharClass();
if (this.parseUnicodeClass(t, cc)) {
re.runes = cc.toArray();
this.push(re);
break bigswitch;
}
}
// Perl character class escape.
const cc = new CharClass();
if (this.parsePerlClassEscape(t, cc)) {
re.runes = cc.toArray();
this.push(re);
break bigswitch;
}
t.rewindTo(savedPos);
this.reuse(re);
// Ordinary single-character escape.
this.literal(Parser.parseEscape(t));
break;
}
default:
this.literal(t.pop());
break;
}
lastRepeatPos = repeatPos;
}
}
this.concat();
if (this.swapVerticalBar()) {
this.pop(); // pop vertical bar
}
this.alternate();
const n = this.stack.length;
if (n !== 1) {
throw new RE2JSSyntaxException(Parser.ERR_MISSING_PAREN, this.wholeRegexp);
}
this.stack[0].namedGroups = this.namedGroups;
return this.stack[0];
}
// parsePerlFlags parses a Perl flag setting or non-capturing group or both,
// like (?i) or (?: or (?i:.
// Pre: t at "(?". Post: t after ")".
// Sets numCap.
parsePerlFlags(t) {
const startPos = t.pos();
// Check for named captures, first introduced in Python's regexp library.
// As usual, there are three slightly different syntaxes:
//
// (?P<name>expr) the original, introduced by Python
// (?<name>expr) the .NET alteration, adopted by Perl 5.10
// (?'name'expr) another .NET alteration, adopted by Perl 5.10
//
// Perl 5.10 gave in and implemented the Python version too,
// but they claim that the last two are the preferred forms.
// PCRE and languages based on it (specifically, PHP and Ruby)
// support all three as well. EcmaScript 4 uses only the Python form.
//
// In both the open source world (via Code Search) and the
// Google source tree, (?P<name>expr) and (?<name>expr) are the
// dominant forms of named captures and both are supported.
const s = t.rest();
if (s.startsWith('(?P<') || s.startsWith('(?<')) {
// Pull out name.
const begin = s.charAt(2) === 'P' ? 4 : 3;
const end = s.indexOf('>');
if (end < 0) {
throw new RE2JSSyntaxException(Parser.ERR_INVALID_NAMED_CAPTURE, s);
}
const name = s.substring(begin, end); // "name"
t.skipString(name);
t.skip(begin + 1); // "(?P<>" or "(?<>"
if (!Parser.isValidCaptureName(name)) {
// "(?P<name>"
throw new RE2JSSyntaxException(Parser.ERR_INVALID_NAMED_CAPTURE, s.substring(0, end + 1)); // "(?P<name>" or "(?<name>"
}
// Like ordinary capture, but named.
const re = this.op(Regexp.Op.LEFT_PAREN);
re.cap = ++this.numCap;
if (this.namedGroups[name]) {
throw new RE2JSSyntaxException(Parser.ERR_DUPLICATE_NAMED_CAPTURE, name);
}
this.namedGroups[name] = this.numCap;
re.name = name;
return;
}
// Non-capturing group. Might also twiddle Perl flags.
t.skip(2); // "(?"
let flags = this.flags;
let sign = +1;
let sawFlag = false;
loop: while (t.more()) {
{
const c = t.pop();
switch (c) {
case Codepoint.CODES.get('i'):
flags |= RE2Flags.FOLD_CASE;
sawFlag = true;
break;
case Codepoint.CODES.get('m'):
flags &= ~RE2Flags.ONE_LINE;
sawFlag = true;
break;
case Codepoint.CODES.get('s'):
flags |= RE2Flags.DOT_NL;
sawFlag = true;
break;
case Codepoint.CODES.get('U'):
flags |= RE2Flags.NON_GREEDY;
sawFlag = true;
break;
// Switch to negation.
case Codepoint.CODES.get('-'):
if (sign < 0) {
break loop;
}
sign = -1;
// Invert flags so that | above turn into &~ and vice versa.
// We'll invert flags again before using it below.
flags = ~flags;
sawFlag = false;
break;
// End of flags, starting group or not.
case Codepoint.CODES.get(':'):
case Codepoint.CODES.get(')'):
if (sign < 0) {
if (!sawFlag) {
break loop;
}
flags = ~flags;
}
if (c === Codepoint.CODES.get(':')) {
// Open new group
this.op(Regexp.Op.LEFT_PAREN);
}
this.flags = flags;
return;
default:
// Flags.
break loop;
}
}
}
throw new RE2JSSyntaxException(Parser.ERR_INVALID_PERL_OP, t.from(startPos));
}
// parseVerticalBar handles a | in the input.
parseVerticalBar() {
this.concat();
// The concatenation we just parsed is on top of the stack.
// If it sits above an opVerticalBar, swap it below
// (things below an opVerticalBar become an alternation).
// Otherwise, push a new vertical bar.
if (!this.swapVerticalBar()) {
this.op(Regexp.Op.VERTICAL_BAR);
}
}
// If the top of the stack is an element followed by an opVerticalBar
// swapVerticalBar swaps the two and returns true.
// Otherwise it returns false.
swapVerticalBar() {
const n = this.stack.length;
// If above and below vertical bar are literal or char class,
// can merge into a single char class.
if (n >= 3 && this.stack[n - 2].op === Regexp.Op.VERTICAL_BAR && Parser.isCharClass(this.stack[n - 1]) && Parser.isCharClass(this.stack[n - 3])) {
let re1 = this.stack[n - 1];
let re3 = this.stack[n - 3];
// Make re3 the more complex of the two.
if (re1.op > re3.op) {
const tmp = re3;
re3 = re1;
re1 = tmp;
this.stack[n - 3] = re3;
}
Parser.mergeCharClass(re3, re1);
this.reuse(re1);
this.pop();
return true;
}
if (n >= 2) {
const re1 = this.stack[n - 1];
const re2 = this.stack[n - 2];
if (re2.op === Regexp.Op.VERTICAL_BAR) {
if (n >= 3) {
// Now out of reach.
// Clean opportunistically.
this.cleanAlt(this.stack[n - 3]);
}
this.stack[n - 2] = re1;
this.stack[n - 1] = re2;
return true;
}
}
return false;
}
// parseRightParen handles a ')' in the input.
parseRightParen() {
this.concat();
if (this.swapVerticalBar()) {
this.pop(); // pop vertical bar
}
this.alternate();
const n = this.stack.length;
if (n < 2) {
throw new RE2JSSyntaxException(Parser.ERR_INTERNAL_ERROR, 'stack underflow');
}
const re1 = this.pop();
const re2 = this.pop();
if (re2.op !== Regexp.Op.LEFT_PAREN) {
throw new RE2JSSyntaxException(Parser.ERR_MISSING_PAREN, this.wholeRegexp);
}
// Restore flags at time of paren.
this.flags = re2.flags;
if (re2.cap === 0) {
// Just for grouping.
this.push(re1);
} else {
re2.op = Regexp.Op.CAPTURE;
re2.subs = [re1];
this.push(re2);
}
}
// parsePerlClassEscape parses a leading Perl character class escape like \d
// from the beginning of |t|. If one is present, it appends the characters
// to cc and returns true. The iterator is advanced past the escape
// on success, undefined on failure, in which case false is returned.
parsePerlClassEscape(t, cc) {
const beforePos = t.pos();
if ((this.flags & RE2Flags.PERL_X) === 0 || !t.more() || t.pop() !== Codepoint.CODES.get('\\') || !t.more()) {
return false;
}
t.pop(); // e.g. advance past 'd' in "\\d"
const p = t.from(beforePos);
const g = PERL_GROUPS.has(p) ? PERL_GROUPS.get(p) : null;
if (g === null) {
return false;
}
cc.appendGroup(g, (this.flags & RE2Flags.FOLD_CASE) !== 0);
return true;
}
// parseNamedClass parses a leading POSIX named character class like
// [:alnum:] from the beginning of t. If one is present, it appends the
// characters to cc, advances the iterator, and returns true.
// Pre: t at "[:". Post: t after ":]".
// On failure (no class of than name), throws RE2JSSyntaxException.
// On misparse, returns false; t.pos() is undefined.
parseNamedClass(t, cc) {
// (Go precondition check deleted.)
const cls = t.rest();
const i = cls.indexOf(':]');
if (i < 0) {
return false;
}
const name = cls.substring(0, i + 2); // "[:alnum:]"
t.skipString(name);
const g = POSIX_GROUPS.has(name) ? POSIX_GROUPS.get(name) : null;
if (g === null) {
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, name);
}
cc.appendGroup(g, (this.flags & RE2Flags.FOLD_CASE) !== 0);
return true;
}
// parseUnicodeClass() parses a leading Unicode character class like \p{Han}
// from the beginning of t. If one is present, it appends the characters to
// to |cc|, advances |t| and returns true.
//
// Returns false if such a pattern is not present or UNICODE_GROUPS
// flag is not enabled; |t.pos()| is not advanced in this case.
// Indicates error by throwing RE2JSSyntaxException.
parseUnicodeClass(t, cc) {
const startPos = t.pos();
if ((this.flags & RE2Flags.UNICODE_GROUPS) === 0 || !t.lookingAt('\\p') && !t.lookingAt('\\P')) {
return false;
}
t.skip(1); // '\\'
// Committed to parse or throw exception.
let sign = +1;
let c = t.pop(); // 'p' or 'P'
if (c === Codepoint.CODES.get('P')) {
sign = -1;
}
if (!t.more()) {
t.rewindTo(startPos);
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, t.rest());
}
c = t.pop();
let name;
if (c !== Codepoint.CODES.get('{')) {
// Single-letter name.
name = Utils.runeToString(c);
} else {
// Name is in braces.
const rest = t.rest();
const end = rest.indexOf('}');
if (end < 0) {
t.rewindTo(startPos);
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, t.rest());
}
name = rest.substring(0, end); // e.g. "Han"
t.skipString(name);
t.skip(1);
// Don't use skip(end) because it assumes UTF-16 coding, and
// StringIterator doesn't guarantee that.
}
// Group can have leading negation too.
// \p{^Han} == \P{Han}, \P{^Han} == \p{Han}.
if (!(name.length === 0) && name.codePointAt(0) === Codepoint.CODES.get('^')) {
sign = 0 - sign; // -sign
name = name.substring(1);
}
const pair = Parser.unicodeTable(name);
if (pair === null) {
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, t.from(startPos));
}
const tab = pair.first;
const fold = pair.second; // fold-equivalent table
// Variation of CharClass.appendGroup() for tables.
if ((this.flags & RE2Flags.FOLD_CASE) === 0 || fold === null) {
cc.appendTableWithSign(tab, sign);
} else {
// Merge and clean tab and fold in a temporary buffer.
// This is necessary for the negative case and just tidy
// for the positive case.
const tmp = new CharClass().appendTable(tab).appendTable(fold).cleanClass().toArray();
cc.appendClassWithSign(tmp, sign);
}
return true;
}
// parseClass parses a character class and pushes it onto the parse stack.
//
// NOTES:
// Pre: at '['; Post: after ']'.
// Mutates stack. Advances iterator. May throw.
parseClass(t) {
const startPos = t.pos();
t.skip(1); // '['
const re = this.newRegexp(Regexp.Op.CHAR_CLASS);
re.flags = this.flags;
const cc = new CharClass();
let sign = +1;
if (t.more() && t.lookingAt('^')) {
sign = -1;
t.skip(1); // '^'
// If character class does not match \n, add it here,
// so that negation later will do the right thing.
if ((this.flags & RE2Flags.CLASS_NL) === 0) {
cc.appendRange(Codepoint.CODES.get('\n'), Codepoint.CODES.get('\n'));
}
}
let first = true; // ']' and '-' are okay as first char in class
while (!t.more() || t.peek() !== Codepoint.CODES.get(']') || first) {
// POSIX: - is only okay unescaped as first or last in class.
// Perl: - is okay anywhere.
if (t.more() && t.lookingAt('-') && (this.flags & RE2Flags.PERL_X) === 0 && !first) {
const s = t.rest();
if (s === '-' || !s.startsWith('-]')) {
t.rewindTo(startPos);
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, t.rest());
}
}
first = false;
const beforePos = t.pos();
// Look for POSIX [:alnum:] etc.
if (t.lookingAt('[:')) {
if (this.parseNamedClass(t, cc)) {
continue;
}
t.rewindTo(beforePos);
}
// Look for Unicode character group like \p{Han}.
if (this.parseUnicodeClass(t, cc)) {
continue;
}
// Look for Perl character class symbols (extension).
if (this.parsePerlClassEscape(t, cc)) {
continue;
}
t.rewindTo(beforePos);
// Single character or simple range.
const lo = Parser.parseClassChar(t, startPos);
let hi = lo;
if (t.more() && t.lookingAt('-')) {
t.skip(1);
if (t.more() && t.lookingAt(']')) {
// [a-] means (a|-) so check for final ].
t.skip(-1);
} else {
hi = Parser.parseClassChar(t, startPos);
if (hi < lo) {
throw new RE2JSSyntaxException(Parser.ERR_INVALID_CHAR_RANGE, t.from(beforePos));
}
}
}
if ((this.flags & RE2Flags.FOLD_CASE) === 0) {
cc.appendRange(lo, hi);
} else {
cc.appendFoldedRange(lo, hi);
}
}
t.skip(1); // ']'
cc.cleanClass();
if (sign < 0) {
cc.negateClass();
}
re.runes = cc.toArray();
this.push(re);
}
}
// A logical thread in the NFA.
class Thread {
constructor() {
this.inst = null;
this.cap = [];
}
}
// A queue is a 'sparse array' holding pending threads of execution. See:
// research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html
class Queue {
constructor() {
this.sparse = []; // may contain stale but in-bounds values.
this.densePcs = []; // may contain stale pc in slots >= size
this.denseThreads = []; // may contain stale Thread in slots >= size
this.size = 0;
}
contains(pc) {
const j = this.sparse[pc];
return j < this.size && this.densePcs[j] === pc;
}
isEmpty() {
return this.size === 0;
}
add(pc) {
const j = this.size++;
this.sparse[pc] = j;
this.denseThreads[j] = null;
this.densePcs[j] = pc;
return j;
}
clear() {
this.sparse = [];
this.densePcs = [];
this.denseThreads = [];
this.size = 0;
}
toString() {
let out = '{';
for (let i = 0; i < this.size; i++) {
if (i !== 0) {
out += ', ';
}
out += this.densePcs[i];
}
out += '}';
return out;
}
}
// A Machine matches an input string of Unicode characters against an
// RE2 instance using a simple NFA.
//
// Called by RE2.doExecute.
class Machine {
static fromRE2(re2) {
const m = new Machine();
m.prog = re2.prog;
m.re2 = re2;
m.q0 = new Queue(m.prog.numInst());
m.q1 = new Queue(m.prog.numInst());
m.pool = [];
m.poolSize = 0;
m.matched = false;
m.matchcap = Array(m.prog.numCap < 2 ? 2 : m.prog.numCap).fill(0);
m.ncap = 0;
return m;
}
static fromMachine(machine) {
const m = new Machine();
m.re2 = machine.re2;
m.prog = machine.prog;
m.q0 = machine.q0;
m.q1 = machine.q1;
m.pool = machine.pool;
m.poolSize = machine.poolSize;
m.matched = machine.matched;
m.matchcap = machine.matchcap;
m.ncap = machine.ncap;
return m;
}
// init() reinitializes an existing Machine for re-use on a new input.
init(ncap) {
this.ncap = ncap;
if (ncap > this.matchcap.length) {
this.initNewCap(ncap);
} else {
this.resetCap(ncap);
}
}
resetCap(ncap) {
for (let i = 0; i < this.poolSize; i++) {
const t = this.pool[i];
t.cap = Array(ncap).fill(0);
}
}
initNewCap(ncap) {
for (let i = 0; i < this.poolSize; i++) {
const t = this.pool[i];
t.cap = Array(ncap).fill(0);
}
this.matchcap = Array(ncap).fill(0);
}
submatches() {
if (this.ncap === 0) {
return Utils.emptyInts();
}
return this.matchcap.slice(0, this.ncap);
}
// alloc() allocates a new thread with the given instruction.
// It uses the free pool if possible.
alloc(inst) {
let t;
if (this.poolSize > 0) {
this.poolSize--;
t = this.pool[this.poolSize];
} else {
t = new Thread();
}
t.inst = inst;
return t;
}
// Frees all threads on the thread queue, returning them to the free pool.
freeQueue(queue, from = 0) {
const numberOfThread = queue.size - from;
const requiredPoolLength = this.poolSize + numberOfThread;
if (this.pool.length < requiredPoolLength) {
this.pool = this.pool.slice(0, Math.max(this.pool.length * 2, requiredPoolLength));
}
for (let i = from; i < queue.size; i++) {
const t = queue.denseThreads[i];
if (t !== null) {
this.pool[this.poolSize] = t;
this.poolSize++;
}
}
queue.clear();
}
// freeThread() returns t to the free pool.
freeThread(t) {
if (this.pool.length <= this.poolSize) {
this.pool = this.pool.slice(0, this.pool.length * 2);
}
this.pool[this.poolSize] = t;
this.poolSize++;
}
match(input, pos, anchor) {
const startCond = this.re2.cond;
if (startCond === Utils.EMPTY_ALL) {
return false;
}
if ((anchor === RE2Flags.ANCHOR_START || anchor === RE2Flags.ANCHOR_BOTH) && pos !== 0) {
return false;
}
this.matched = false;
this.matchcap = Array(this.prog.numCap).fill(-1);
let runq = this.q0;
let nextq = this.q1;
let r = input.step(pos);
let rune = r >> 3;
let width = r & 7;
let rune1 = -1;
let width1 = 0;
if (r !== MachineInputBase.EOF()) {
r = input.step(pos + width);
rune1 = r >> 3;
width1 = r & 7;
}
let flag;
if (pos === 0) {
flag = Utils.emptyOpContext(-1, rune);
} else {
flag = input.context(pos);
}
// eslint-disable-next-line no-constant-condition
while (true) {
if (runq.isEmpty()) {
if ((startCond & Utils.EMPTY_BEGIN_TEXT) !== 0 && pos !== 0) {
break;
}
if (this.matched) {
break;
}
if (!(this.re2.prefix.length === 0) && rune1 !== this.re2.prefixRune && input.canCheckPrefix()) {
const advance = input.index(this.re2, pos);
if (advance < 0) {
break;
}
pos += advance;
r = input.step(pos);
rune = r >> 3;
width = r & 7;
r = input.step(pos + width);
rune1 = r >> 3;
width1 = r & 7;
}
}
if (!this.matched && (pos === 0 || anchor === RE2Flags.UNANCHORED)) {
if (this.ncap > 0) {
this.matchcap[0] = pos;
}
this.add(runq, this.prog.start, pos, this.matchcap, flag, null);
}
const nextPos = pos + width;
flag = input.context(nextPos);
this.step(runq, nextq, pos, nextPos, rune, flag, anchor, pos === input.endPos());
if (width === 0) {
break;
}
if (this.ncap === 0 && this.matched) {
break;
}
pos += width;
rune = rune1;
width = width1;
if (rune !== -1) {
r = input.step(pos + width);
rune1 = r >> 3;
width1 = r & 7;
}
const tmpq = runq;
runq = nextq;
nextq = tmpq;
}
this.freeQueue(nextq);
return this.matched;
}
step(runq, nextq, pos, nextPos, c, nextCond, anchor, atEnd) {
const longest = this.re2.longest;
for (let j = 0; j < runq.size; j++) {
let t = runq.denseThreads[j];
if (t === null) {
continue;
}
if (longest && this.matched && this.ncap > 0 && this.matchcap[0] < t.cap[0]) {
this.freeThread(t);
continue;
}
const i = t.inst;
let add = false;
switch (i.op) {
case Inst.MATCH:
if (anchor === RE2Flags.ANCHOR_BOTH && !atEnd) {
break;
}
if (this.ncap > 0 && (!longest || !this.matched || this.matchcap[1] < pos)) {
t.cap[1] = pos;
this.matchcap = t.cap.slice(0, this.ncap);
}
if (!longest) {
this.freeQueue(runq, j + 1);
}
this.matched = true;
break;
case Inst.RUNE:
add = i.matchRune(c);
break;
case Inst.RUNE1:
add = c === i.runes[0];
break;
case Inst.RUNE_ANY:
add = true;
break;
case Inst.RUNE_ANY_NOT_NL:
add = c !== Codepoint.CODES.get('\n');
break;
default:
throw new Error('bad inst');
}
if (add) {
t = this.add(nextq, i.out, nextPos, t.cap, nextCond, t);
}
if (t !== null) {
this.freeThread(t);
runq.denseThreads[j] = null;
}
}
runq.clear();
}
add(q, pc, pos, cap, cond, t) {
if (pc === 0) {
return t;
}
if (q.contains(pc)) {
return t;
}
const d = q.add(pc);
const inst = this.prog.inst[pc];
switch (inst.op) {
case Inst.FAIL:
break;
case Inst.ALT:
case Inst.ALT_MATCH:
t = this.add(q, inst.out, pos, cap, cond, t);
t = this.add(q, inst.arg, pos, cap, cond, t);
break;
case Inst.EMPTY_WIDTH:
if ((inst.arg & ~cond) === 0) {
t = this.add(q, inst.out, pos, cap, cond, t);
}
break;
case Inst.NOP:
t = this.add(q, inst.out, pos, cap, cond, t);
break;
case Inst.CAPTURE:
if (inst.arg < this.ncap) {
const opos = cap[inst.arg];
cap[inst.arg] = pos;
this.add(q, inst.out, pos, cap, cond, null);
cap[inst.arg] = opos;
} else {
t = this.add(q, inst.out, pos, cap, cond, t);
}
break;
case Inst.MATCH:
case Inst.RUNE:
case Inst.RUNE1:
case Inst.RUNE_ANY:
case Inst.RUNE_ANY_NOT_NL:
if (t === null) {
t = this.alloc(inst);
} else {
t.inst = inst;
}
if (this.ncap > 0 && t.cap !== cap) {
t.cap = cap.slice(0, this.ncap);
}
q.denseThreads[d] = t;
t = null;
break;
default:
throw new Error('unhandled');
}
return t;
}
}
class AtomicReference {
constructor(initialValue) {
this.value = initialValue;
}
// Returns the current value
get() {
return this.value;
}
// Sets to the given value
set(newValue) {
this.value = newValue;
}
// Atomically sets to the given value and returns true if the current value == the expected value
compareAndSet(expect, update) {
if (this.value === expect) {
this.value = update;
return true;
}
return false;
}
}
/**
* An RE2 class instance is a compiled representation of an RE2 regular expression, independent of
* the public Java-like Pattern/Matcher API.
*
* This class also contains various implementation helpers for RE2 regular expressions.
*
* Use the {@link #quoteMeta(String)} utility function to quote all regular expression
* metacharacters in an arbitrary string.
*
*/
class RE2 {
// This is visible for testing.
static initTest(expr) {
const re2 = RE2.compile(expr);
const res = new RE2(re2.expr, re2.prog, re2.numSubexp, re2.longest);
res.cond = re2.cond;
res.prefix = re2.prefix;
res.prefixUTF8 = re2.prefixUTF8;
res.prefixComplete = re2.prefixComplete;
res.prefixRune = re2.prefixRune;
return res;
}
/**
* Parses a regular expression and returns, if successful, an {@code RE2} instance that can be
* used to match against text.
*
* When matching against text, the regexp returns a match that begins as early as possible in the
* input (leftmost), and among those it chooses the one that a backtracking search would have
* found first. This so-called leftmost-first matching is the same semantics that Perl, Python,
* and other implementations use, although this package implements it without the expense of
* backtracking. For POSIX leftmost-longest matching, see {@link #compilePOSIX}.
*/
static compile(expr) {
return RE2.compileImpl(expr, RE2Flags.PERL, false);
}
/**
* {@code compilePOSIX} is like {@link #compile} but restricts the regular expression to POSIX ERE
* (egrep) syntax and changes the match semantics to leftmost-longest.
*
* That is, when matching against text, the regexp returns a match that begins as early as
* possible in the input (leftmost), and among those it chooses a match that is as long as
* possible. This so-called leftmost-longest matching is the same semantics that early regular
* expression implementations used and that POSIX specifies.
*
* However, there can be multiple leftmost-longest matches, with different submatch choices, and
* here this package diverges from POSIX. Among the possible leftmost-longest matches, this
* package chooses the one that a backtracking search would have found first, while POSIX
* specifies that the match be chosen to maximize the length of the first subexpression, then the
* second, and so on from left to right. The POSIX rule is computationally prohibitive and not
* even well-defined. See http://swtch.com/~rsc/regexp/regexp2.html#posix
*/
static compilePOSIX(expr) {
return RE2.compileImpl(expr, RE2Flags.POSIX, true);
}
// Exposed to ExecTests.
static compileImpl(expr, mode, longest) {
let re = Parser.parse(expr, mode);
const maxCap = re.maxCap();
re = Simplify.simplify(re);
const prog = Compiler.compileRegexp(re);
const re2 = new RE2(expr, prog, maxCap, longest);
const [prefixCompl, prefixStr] = prog.prefix();
re2.prefixComplete = prefixCompl;
re2.prefix = prefixStr;
re2.prefixUTF8 = Utils.stringToUtf8ByteArray(re2.prefix);
if (re2.prefix.length > 0) {
re2.prefixRune = re2.prefix.codePointAt(0);
}
re2.namedGroups = re.namedGroups;
return re2;
}
/**
* Returns true iff textual regular expression {@code pattern} matches string {@code s}.
*
* More complicated queries need to use {@link #compile} and the full {@code RE2} interface.
*/
// This is visible for testing.
static match(pattern, s) {
return RE2.compile(pattern).match(s);
}
constructor(expr, prog, numSubexp = 0, longest = 0) {
this.expr = expr; // as passed to Compile
this.prog = prog; // compiled program
this.numSubexp = numSubexp;
this.longest = longest;
this.cond = prog.startCond(); // EMPTY_* bitmask: empty-width conditions
this.prefix = null; // required UTF-16 prefix in unanchored matches
this.prefixUTF8 = null; // required UTF-8 prefix in unanchored matches
this.prefixComplete = false; // true if prefix is the entire regexp
this.prefixRune = 0; // first rune in prefix
this.pooled = new AtomicReference(); // Cache of machines for running regexp. Forms a Treiber stack.
}
/**
* Returns the number of parenthesized subexpressions in this regular expression.
*/
numberOfCapturingGroups() {
return this.numSubexp;
}
// get() returns a machine to use for matching |this|. It uses |this|'s
// machine cache if possible, to avoid unnecessary allocation.
get() {
// Pop a machine off the stack if available.
let head;
do {
head = this.pooled.get();
} while (head && !this.pooled.compareAndSet(head, head.next));
return head;
}
// Clears the memory associated with this machine.
reset() {
this.pooled.set(null);
}
// put() returns a machine to |this|'s machine cache. There is no attempt to
// limit the size of the cache, so it will grow to the maximum number of
// simultaneous matches run using |this|. (The cache empties when |this|
// gets garbage collected or reset is called.)
put(m, isNew) {
// To avoid allocation in the single-thread or uncontended case, reuse a node only if
// it was the only element in the stack when it was popped, and it's the only element
// in the stack when it's pushed back after use.
let head = this.pooled.get();
do {
head = this.pooled.get();
if (!isNew && head) {
// If an element had a null next pointer and it was previously in the stack, another thread
// might be trying to pop it out right now, and if it sees the same node now in the
// stack the pop will succeed, but the new top of the stack will be the stale (null) value
// of next. Allocate a new Machine so that the CAS will not succeed if this node has been
// popped and re-pushed.
m = Machine.fromMachine(m);
isNew = true;
}
// Without this comparison, TSAN will complain about a race condition:
// Thread A, B, and C all attempt to do a match on the same pattern.
//
// A: Allocates Machine 1; executes match; put machine 1. State is now:
//
// pooled -> machine 1 -> null
//
// B reads pooled, sees machine 1
//
// C reads pooled, sees machine 1
//
// B successfully CASes pooled to null
//
// B executes match; put machine 1, which involves setting machine1.next to
// null (even though it's already null); preempted before CAS
//
// C resumes, and reads machine1.next in order to execute cas(head, head.next)
//
// There is no happens-before relationship between B's redundant null write
// and C's read, thus triggering TSAN.
//
// Not needed for JS code
if (m.next !== head) {
m.next = head;
}
} while (!this.pooled.compareAndSet(head, m));
}
toString() {
return this.expr;
}
// doExecute() finds the leftmost match in the input and returns
// the position of its subexpressions.
// Derived from exec.go.
doExecute(input, pos, anchor, ncap) {
let m = this.get();
// The Treiber stack cannot reuse nodes, unless the node to be reused has only ever been at
// the bottom of the stack (i.e., next == null).
let isNew = false;
if (!m) {
m = Machine.fromRE2(this);
isNew = true;
} else if (m.next !== null) {
m = Machine.fromMachine(m);
isNew = true;
}
m.init(ncap);
const cap = m.match(input, pos, anchor) ? m.submatches() : null;
this.put(m, isNew);
return cap;
}
match(s) {
return this.doExecute(MachineInput.fromUTF16(s), 0, RE2Flags.UNANCHORED, 0) !== null;
}
/**
* Matches the regular expression against input starting at position start and ending at position
* end, with the given anchoring. Records the submatch boundaries in group, which is [start, end)
* pairs of byte offsets. The number of boundaries needed is inferred from the size of the group
* array. It is most efficient not to ask for submatch boundaries.
*
* @param input the input byte array
* @param start the beginning position in the input
* @param end the end position in the input
* @param anchor the anchoring flag (UNANCHORED, ANCHOR_START, ANCHOR_BOTH)
* @param group the array to fill with submatch positions
* @param ngroup the number of array pairs to fill in
* @returns true if a match was found
*/
matchWithGroup(input, start, end, anchor, ngroup) {
if (!(input instanceof MatcherInputBase)) {
input = MatcherInput.utf16(input);
}
return this.matchMachineInput(input, start, end, anchor, ngroup);
}
matchMachineInput(input, start, end, anchor, ngroup) {
if (start > end) {
return [false, null];
}
const machineInput = input.isUTF16Encoding() ? MachineInput.fromUTF16(input.asCharSequence(), 0, end) : MachineInput.fromUTF8(input.asBytes(), 0, end);
const groupMatch = this.doExecute(machineInput, start, anchor, 2 * ngroup);
if (groupMatch === null) {
return [false, null];
}
return [true, groupMatch];
}
/**
* Returns true iff this regexp matches the UTF-8 byte array {@code b}.
*/
// This is visible for testing.
matchUTF8(b) {
return this.doExecute(MachineInput.fromUTF8(b), 0, RE2Flags.UNANCHORED, 0) !== null;
}
/**
* Returns a copy of {@code src} in which all matches for this regexp have been replaced by
* {@code repl}. No support is provided for expressions (e.g. {@code \1} or {@code $1}) in the
* replacement string.
*/
// This is visible for testing.
replaceAll(src, repl) {
return this.replaceAllFunc(src, () => repl, 2 * src.length + 1);
}
/**
* Returns a copy of {@code src} in which only the first match for this regexp has been replaced
* by {@code repl}. No support is provided for expressions (e.g. {@code \1} or {@code $1}) in the
* replacement string.
*/
// This is visible for testing.
replaceFirst(src, repl) {
return this.replaceAllFunc(src, () => repl, 1);
}
/**
* Returns a copy of {@code src} in which at most {@code maxReplaces} matches for this regexp have
* been replaced by the return value of of function {@code repl} (whose first argument is the
* matched string). No support is provided for expressions (e.g. {@code \1} or {@code $1}) in the
* replacement string.
*/
// This is visible for testing.
replaceAllFunc(src, replFunc, maxReplaces) {
let lastMatchEnd = 0;
let searchPos = 0;
let out = '';
const input = MachineInput.fromUTF16(src);
let numReplaces = 0;
while (searchPos <= src.length) {
const a = this.doExecute(input, searchPos, RE2Flags.UNANCHORED, 2);
if (a === null || a.length === 0) {
break;
}
out += src.substring(lastMatchEnd, a[0]);
if (a[1] > lastMatchEnd || a[0] === 0) {
out += replFunc(src.substring(a[0], a[1]));
numReplaces++;
}
lastMatchEnd = a[1];
const width = input.step(searchPos) & 7;
if (searchPos + width > a[1]) {
searchPos += width;
} else if (searchPos + 1 > a[1]) {
searchPos++;
} else {
searchPos = a[1];
}
if (numReplaces >= maxReplaces) {
break;
}
}
out += src.substring(lastMatchEnd);
return out;
}
// The number of capture values in the program may correspond
// to fewer capturing expressions than are in the regexp.
// For example, "(a){0}" turns into an empty program, so the
// maximum capture in the program is 0 but we need to return
// an expression for \1. Pad returns a with -1s appended as needed;
// the result may alias a.
pad(a) {
if (a === null) {
return null;
}
let n = (1 + this.numSubexp) * 2;
if (a.length < n) {
let a2 = new Array(n).fill(-1);
for (let i = 0; i < a.length; i++) {
a2[i] = a[i];
}
a = a2;
}
return a;
}
// Find matches in input.
allMatches(input, n, deliverFun = v => v) {
let result = [];
const end = input.endPos();
if (n < 0) {
n = end + 1;
}
let pos = 0;
let i = 0;
let prevMatchEnd = -1;
while (i < n && pos <= end) {
const matches = this.doExecute(input, pos, RE2Flags.UNANCHORED, this.prog.numCap);
if (matches === null || matches.length === 0) {
break;
}
let accept = true;
if (matches[1] === pos) {
if (matches[0] === prevMatchEnd) {
accept = false;
}
const r = input.step(pos);
if (r < 0) {
pos = end + 1;
} else {
pos += r & 7;
}
} else {
pos = matches[1];
}
prevMatchEnd = matches[1];
if (accept) {
result.push(deliverFun(this.pad(matches)));
i++;
}
}
return result;
}
// Legacy Go-style interface; preserved (package-private) for better
// test coverage.
//
// There are 16 methods of RE2 that match a regular expression and
// identify the matched text. Their names are matched by this regular
// expression:
//
// find(All)?(UTF8)?(Submatch)?(Index)?
//
// If 'All' is present, the routine matches successive non-overlapping
// matches of the entire expression. Empty matches abutting a
// preceding match are ignored. The return value is an array
// containing the successive return values of the corresponding
// non-All routine. These routines take an extra integer argument, n;
// if n >= 0, the function returns at most n matches/submatches.
//
// If 'UTF8' is present, the argument is a UTF-8 encoded byte[] array;
// otherwise it is a UTF-16 encoded js string; return values
// are adjusted as appropriate.
//
// If 'Submatch' is present, the return value is an list identifying
// the successive submatches of the expression. Submatches are
// matches of parenthesized subexpressions within the regular
// expression, numbered from left to right in order of opening
// parenthesis. Submatch 0 is the match of the entire expression,
// submatch 1 the match of the first parenthesized subexpression, and
// so on.
//
// If 'Index' is present, matches and submatches are identified by
// byte index pairs within the input string: result[2*n:2*n+1]
// identifies the indexes of the nth submatch. The pair for n==0
// identifies the match of the entire expression. If 'Index' is not
// present, the match is identified by the text of the match/submatch.
// If an index is negative, it means that subexpression did not match
// any string in the input.
/**
* Returns an array holding the text of the leftmost match in {@code b} of this regular
* expression.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findUTF8(b) {
const a = this.doExecute(MachineInput.fromUTF8(b), 0, RE2Flags.UNANCHORED, 2);
if (a === null) {
return null;
}
return b.slice(a[0], a[1]);
}
/**
* Returns a two-element array of integers defining the location of the leftmost match in
* {@code b} of this regular expression. The match itself is at {@code b[loc[0]...loc[1]]}.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findUTF8Index(b) {
const a = this.doExecute(MachineInput.fromUTF8(b), 0, RE2Flags.UNANCHORED, 2);
if (a === null) {
return null;
}
return a.slice(0, 2);
}
/**
* Returns a string holding the text of the leftmost match in {@code s} of this regular
* expression.
*
* If there is no match, the return value is an empty string, but it will also be empty if the
* regular expression successfully matches an empty string. Use {@link #findIndex} or
* {@link #findSubmatch} if it is necessary to distinguish these cases.
*/
// This is visible for testing.
find(s) {
const a = this.doExecute(MachineInput.fromUTF16(s), 0, RE2Flags.UNANCHORED, 2);
if (a === null) {
return '';
}
return s.substring(a[0], a[1]);
}
/**
* Returns a two-element array of integers defining the location of the leftmost match in
* {@code s} of this regular expression. The match itself is at
* {@code s.substring(loc[0], loc[1])}.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findIndex(s) {
return this.doExecute(MachineInput.fromUTF16(s), 0, RE2Flags.UNANCHORED, 2);
}
/**
* Returns an array of arrays the text of the leftmost match of the regular expression in
* {@code b} and the matches, if any, of its subexpressions, as defined by the <a
* href='#submatch'>Submatch</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findUTF8Submatch(b) {
const a = this.doExecute(MachineInput.fromUTF8(b), 0, RE2Flags.UNANCHORED, this.prog.numCap);
if (a === null) {
return null;
}
const ret = new Array(1 + this.numSubexp).fill(null);
for (let i = 0; i < ret.length; i++) {
if (2 * i < a.length && a[2 * i] >= 0) {
ret[i] = b.slice(a[2 * i], a[2 * i + 1]);
}
}
return ret;
}
/**
* Returns an array holding the index pairs identifying the leftmost match of this regular
* expression in {@code b} and the matches, if any, of its subexpressions, as defined by the the
* <a href='#submatch'>Submatch</a> and <a href='#index'>Index</a> descriptions above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findUTF8SubmatchIndex(b) {
return this.pad(this.doExecute(MachineInput.fromUTF8(b), 0, RE2Flags.UNANCHORED, this.prog.numCap));
}
/**
* Returns an array of strings holding the text of the leftmost match of the regular expression in
* {@code s} and the matches, if any, of its subexpressions, as defined by the <a
* href='#submatch'>Submatch</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findSubmatch(s) {
const a = this.doExecute(MachineInput.fromUTF16(s), 0, RE2Flags.UNANCHORED, this.prog.numCap);
if (a === null) {
return null;
}
const ret = new Array(1 + this.numSubexp).fill(null);
for (let i = 0; i < ret.length; i++) {
if (2 * i < a.length && a[2 * i] >= 0) {
ret[i] = s.substring(a[2 * i], a[2 * i + 1]);
}
}
return ret;
}
/**
* Returns an array holding the index pairs identifying the leftmost match of this regular
* expression in {@code s} and the matches, if any, of its subexpressions, as defined by the <a
* href='#submatch'>Submatch</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findSubmatchIndex(s) {
return this.pad(this.doExecute(MachineInput.fromUTF16(s), 0, RE2Flags.UNANCHORED, this.prog.numCap));
}
/**
* {@code findAllUTF8()} is the <a href='#all'>All</a> version of {@link #findUTF8}; it returns a
* list of up to {@code n} successive matches of the expression, as defined by the <a
* href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*
* TODO(adonovan): think about defining a byte slice view class, like a read-only Go slice backed
* by |b|.
*/
// This is visible for testing.
findAllUTF8(b, n) {
const result = this.allMatches(MachineInput.fromUTF8(b), n, match => b.slice(match[0], match[1]));
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllUTF8Index} is the <a href='#all'>All</a> version of {@link #findUTF8Index}; it
* returns a list of up to {@code n} successive matches of the expression, as defined by the <a
* href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllUTF8Index(b, n) {
const result = this.allMatches(MachineInput.fromUTF8(b), n, match => match.slice(0, 2));
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAll} is the <a href='#all'>All</a> version of {@link #find}; it returns a list of up
* to {@code n} successive matches of the expression, as defined by the <a href='#all'>All</a>
* description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAll(s, n) {
const result = this.allMatches(MachineInput.fromUTF16(s), n, match => s.substring(match[0], match[1]));
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllIndex} is the <a href='#all'>All</a> version of {@link #findIndex}; it returns a
* list of up to {@code n} successive matches of the expression, as defined by the <a
* href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllIndex(s, n) {
const result = this.allMatches(MachineInput.fromUTF16(s), n, match => match.slice(0, 2));
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllUTF8Submatch} is the <a href='#all'>All</a> version of {@link #findUTF8Submatch};
* it returns a list of up to {@code n} successive matches of the expression, as defined by the <a
* href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllUTF8Submatch(b, n) {
const result = this.allMatches(MachineInput.fromUTF8(b), n, match => {
let slice = new Array(match.length / 2 | 0).fill(null);
for (let j = 0; j < slice.length; j++) {
if (match[2 * j] >= 0) {
slice[j] = b.slice(match[2 * j], match[2 * j + 1]);
}
}
return slice;
});
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllUTF8SubmatchIndex} is the <a href='#all'>All</a> version of
* {@link #findUTF8SubmatchIndex}; it returns a list of up to {@code n} successive matches of the
* expression, as defined by the <a href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllUTF8SubmatchIndex(b, n) {
const result = this.allMatches(MachineInput.fromUTF8(b), n);
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllSubmatch} is the <a href='#all'>All</a> version of {@link #findSubmatch}; it
* returns a list of up to {@code n} successive matches of the expression, as defined by the <a
* href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllSubmatch(s, n) {
const result = this.allMatches(MachineInput.fromUTF16(s), n, match => {
let slice = new Array(match.length / 2 | 0).fill(null);
for (let j = 0; j < slice.length; j++) {
if (match[2 * j] >= 0) {
slice[j] = s.substring(match[2 * j], match[2 * j + 1]);
}
}
return slice;
});
if (result.length === 0) {
return null;
}
return result;
}
/**
* {@code findAllSubmatchIndex} is the <a href='#all'>All</a> version of
* {@link #findSubmatchIndex}; it returns a list of up to {@code n} successive matches of the
* expression, as defined by the <a href='#all'>All</a> description above.
*
* A return value of null indicates no match.
*/
// This is visible for testing.
findAllSubmatchIndex(s, n) {
const result = this.allMatches(MachineInput.fromUTF16(s), n);
if (result.length === 0) {
return null;
}
return result;
}
}
/**
* A compiled representation of an RE2 regular expression
*
* The matching functions take {@code String} arguments instead of the more general Java
* {@code CharSequence} since the latter doesn't provide UTF-16 decoding.
*
*
* @author rsc@google.com (Russ Cox)
* @class
*/
class RE2JS {
/**
* Flag: case insensitive matching.
*/
static CASE_INSENSITIVE = 1;
/**
* Flag: dot ({@code .}) matches all characters, including newline.
*/
static DOTALL = 2;
/**
* Flag: multiline matching: {@code ^} and {@code $} match at beginning and end of line, not just
* beginning and end of input.
*/
static MULTILINE = 4;
/**
* Flag: Unicode groups (e.g. {@code \p\ Greek\} ) will be syntax errors.
*/
static DISABLE_UNICODE_GROUPS = 8;
/**
* Flag: matches longest possible string.
*/
static LONGEST_MATCH = 16;
/**
* Returns a literal pattern string for the specified string.
*
* This method produces a string that can be used to create a <code>RE2JS</code> that would
* match the string <code>s</code> as if it were a literal pattern.
*
* Metacharacters or escape sequences in the input sequence will be given no special meaning.
*
* @param {string} str The string to be literalized
* @returns {string} A literal string replacement
*/
static quote(str) {
return Utils.quoteMeta(str);
}
/**
* Helper: create new RE2JS with given regex and flags. Flregex is the regex with flags applied.
* @param {string} regex
* @param {number} [flags=0]
* @returns {RE2JS}
*/
static compile(regex, flags = 0) {
let fregex = regex;
if ((flags & RE2JS.CASE_INSENSITIVE) !== 0) {
fregex = `(?i)${fregex}`;
}
if ((flags & RE2JS.DOTALL) !== 0) {
fregex = `(?s)${fregex}`;
}
if ((flags & RE2JS.MULTILINE) !== 0) {
fregex = `(?m)${fregex}`;
}
if ((flags & ~(RE2JS.MULTILINE | RE2JS.DOTALL | RE2JS.CASE_INSENSITIVE | RE2JS.DISABLE_UNICODE_GROUPS | RE2JS.LONGEST_MATCH)) !== 0) {
throw new RE2JSFlagsException('Flags should only be a combination of MULTILINE, DOTALL, CASE_INSENSITIVE, DISABLE_UNICODE_GROUPS, LONGEST_MATCH');
}
let re2Flags = RE2Flags.PERL;
if ((flags & RE2JS.DISABLE_UNICODE_GROUPS) !== 0) {
re2Flags &= ~RE2Flags.UNICODE_GROUPS;
}
const p = new RE2JS(regex, flags);
// The compiled RE2 regexp.
p.re2Input = RE2.compileImpl(fregex, re2Flags, (flags & RE2JS.LONGEST_MATCH) !== 0);
return p;
}
/**
* Matches a string against a regular expression.
*
* @param {string} regex the regular expression
* @param {string|number[]} input the input
* @returns {boolean} true if the regular expression matches the entire input
* @throws RE2JSSyntaxException if the regular expression is malformed
*/
static matches(regex, input) {
return RE2JS.compile(regex).matcher(input).matches();
}
/**
* This is visible for testing.
* @private
*/
static initTest(pattern, flags, re2) {
if (pattern == null) {
throw new Error('pattern is null');
}
if (re2 == null) {
throw new Error('re2 is null');
}
const p = new RE2JS(pattern, flags);
// The compiled RE2 regexp.
p.re2Input = re2;
return p;
}
/**
*
* @param {string} pattern
* @param {number} flags
*/
constructor(pattern, flags) {
// The pattern string at construction time.
this.patternInput = pattern;
// The flags at construction time.
this.flagsInput = flags;
}
/**
* Releases memory used by internal caches associated with this pattern. Does not change the
* observable behaviour. Useful for tests that detect memory leaks via allocation tracking.
*/
reset() {
this.re2Input.reset();
}
/**
* Returns the flags used in the constructor.
* @returns {number}
*/
flags() {
return this.flagsInput;
}
/**
* Returns the pattern used in the constructor.
* @returns {string}
*/
pattern() {
return this.patternInput;
}
re2() {
return this.re2Input;
}
/**
* Matches a string against a regular expression.
*
* @param {string|number[]} input the input
* @returns {boolean} true if the regular expression matches the entire input
*/
matches(input) {
return this.matcher(input).matches();
}
/**
* Creates a new {@code Matcher} matching the pattern against the input.
*
* @param {string|number[]} input the input string
* @returns {Matcher}
*/
matcher(input) {
if (Array.isArray(input)) {
input = MatcherInput.utf8(input);
}
return new Matcher(this, input);
}
/**
* Splits input around instances of the regular expression. It returns an array giving the strings
* that occur before, between, and after instances of the regular expression.
*
* If {@code limit <= 0}, there is no limit on the size of the returned array. If
* {@code limit == 0}, empty strings that would occur at the end of the array are omitted. If
* {@code limit > 0}, at most limit strings are returned. The final string contains the remainder
* of the input, possibly including additional matches of the pattern.
*
* @param {string} input the input string to be split
* @param {number} [limit=0] the limit
* @returns {string[]} the split strings
*/
split(input, limit = 0) {
const m = this.matcher(input);
const result = [];
let emptiesSkipped = 0;
let last = 0;
while (m.find()) {
if (last === 0 && m.end() === 0) {
// Zero-width match at the beginning, skip
last = m.end();
continue;
}
if (limit > 0 && result.length === limit - 1) {
// no more room for matches
break;
}
if (last === m.start()) {
// Empty match, may or may not be trailing.
if (limit === 0) {
emptiesSkipped += 1;
last = m.end();
continue;
}
} else {
// If emptiesSkipped > 0 then limit == 0 and we have non-trailing empty matches to add before
// this non-empty match.
while (emptiesSkipped > 0) {
result.push('');
emptiesSkipped -= 1;
}
}
result.push(m.substring(last, m.start()));
last = m.end();
}
if (limit === 0 && last !== m.inputLength()) {
// Unlimited match, no more delimiters but we have a non-empty input at the end. Catch up any skipped empty
// matches, then emit the final match.
while (emptiesSkipped > 0) {
result.push('');
emptiesSkipped -= 1;
}
result.push(m.substring(last, m.inputLength()));
}
if (limit !== 0 || result.length === 0) {
result.push(m.substring(last, m.inputLength()));
}
return result;
}
/**
*
* @returns {string}
*/
toString() {
return this.patternInput;
}
/**
* Returns the number of capturing groups in this matcher's pattern. Group zero denotes the entire
* pattern and is excluded from this count.
*
* @returns {number} the number of capturing groups in this pattern
*/
groupCount() {
return this.re2Input.numberOfCapturingGroups();
}
/**
* Return a map of the capturing groups in this matcher's pattern, where key is the name and value
* is the index of the group in the pattern.
* @returns {*}
*/
namedGroups() {
return this.re2Input.namedGroups;
}
/**
*
* @param {*} other
* @returns {boolean}
*/
equals(other) {
if (this === other) {
return true;
}
if (other === null || this.constructor !== other.constructor) {
return false;
}
return this.flagsInput === other.flagsInput && this.patternInput === other.patternInput;
}
}
exports.RE2JS = RE2JS;
exports.RE2JSCompileException = RE2JSCompileException;
exports.RE2JSException = RE2JSException;
exports.RE2JSFlagsException = RE2JSFlagsException;
exports.RE2JSGroupException = RE2JSGroupException;
exports.RE2JSSyntaxException = RE2JSSyntaxException;
//# sourceMappingURL=index.cjs.cjs.map