teptris 0.3.23.0 → 0.3.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/teptris_ext/engine/README.md +1 -1
- data/ext/teptris_ext/engine/src/include/teptris/version.h +2 -2
- data/ext/teptris_ext/engine/src/teptris/schema/regex.c +143 -7
- data/ext/teptris_ext/engine/src/teptris/schema/unicode_props.c +5508 -0
- data/ext/teptris_ext/engine/src/teptris/schema/unicode_props.h +20 -0
- data/ext/teptris_ext/engine/src/teptris/schema/validate.c +112 -4
- data/lib/teptris/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4063376572c74e54b603e2c960d0c37a6f7322fcb60fc13c851ba537a5ecc3f4
|
|
4
|
+
data.tar.gz: 2c9216707cc91cb020909c0606ee1db5c6303de629eae1db1b9f81e003d4e512
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 634870c546775f3b2405803b9a0a34b80e8aeda5be6c7da5b488e481b216bafa1cfa4b04391c959633937c0bc4ba20e0379a3e3dc393a43311298e59eac2c0b3
|
|
7
|
+
data.tar.gz: 242e90ad01de5cf198eaf34bf0ac212fba289b9dd2ee70dc10846fbbf84c8eeca88e91851d9334ead183b8f2c7c697bd9e2f53f4903c51b1d425111cc33bf8b8
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
#include <string.h>
|
|
21
21
|
|
|
22
22
|
#include "regex.h"
|
|
23
|
+
#include "unicode_props.h"
|
|
23
24
|
|
|
24
25
|
/* ---------------------------------------------------------------- AST -- */
|
|
25
26
|
|
|
@@ -199,6 +200,94 @@ static void cls_add_cp(pctx *c, ra *cl, uint32_t cp) {
|
|
|
199
200
|
cl->n_ranges++;
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
/* ------------------------------------------------- \p{...} properties -- */
|
|
204
|
+
|
|
205
|
+
static void cls_reserve(pctx *c, ra *cl, size_t cap);
|
|
206
|
+
|
|
207
|
+
/* the property named by s[0..n) (decoded code points): binary search
|
|
208
|
+
* over the sorted table */
|
|
209
|
+
static const teptris_uc_prop *uc_find(const uint32_t *s, size_t n) {
|
|
210
|
+
int lo = 0, hi = teptris_n_unicode_props - 1;
|
|
211
|
+
while (lo <= hi) {
|
|
212
|
+
int mid = (lo + hi) / 2;
|
|
213
|
+
const char *name = teptris_unicode_props[mid].name;
|
|
214
|
+
int cmp = 0;
|
|
215
|
+
for (size_t i = 0; i < n; i++) {
|
|
216
|
+
unsigned char c = (unsigned char)name[i];
|
|
217
|
+
if (c == '\0' || (uint32_t)c != s[i]) {
|
|
218
|
+
cmp = (uint32_t)c < s[i] ? -1 : 1;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (cmp == 0 && name[n] == '\0') return &teptris_unicode_props[mid];
|
|
223
|
+
if (cmp == 0) cmp = 1; /* longer table name: s sorts first */
|
|
224
|
+
if (cmp < 0) lo = mid + 1;
|
|
225
|
+
else hi = mid - 1;
|
|
226
|
+
}
|
|
227
|
+
return NULL;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* the complement of sorted ranges over the whole codepoint space (the
|
|
231
|
+
* caller reserved headroom) */
|
|
232
|
+
static void cls_append_complement(pctx *c, ra *cl,
|
|
233
|
+
const teptris_uc_range *rs, int n) {
|
|
234
|
+
(void)c;
|
|
235
|
+
uint32_t expect = 0;
|
|
236
|
+
for (int i = 0; i <= n; i++) {
|
|
237
|
+
uint32_t lo = i < n ? rs[i].lo : 0x110000;
|
|
238
|
+
uint32_t hi = i < n ? rs[i].hi : 0x110000;
|
|
239
|
+
if (lo > expect) {
|
|
240
|
+
cl->ranges[cl->n_ranges].lo = expect;
|
|
241
|
+
cl->ranges[cl->n_ranges].hi = lo - 1;
|
|
242
|
+
cl->n_ranges++;
|
|
243
|
+
}
|
|
244
|
+
if (hi + 1 > expect) expect = hi + 1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* parse \p{...} / \P{...} / \p{^...} with c->pos after the letter;
|
|
249
|
+
* the ranges (or their complement) append into cl */
|
|
250
|
+
static void prop_escape(pctx *c, ra *cl, bool negate_letter) {
|
|
251
|
+
bool inner_neg = false;
|
|
252
|
+
if (c->pos >= c->n || c->s[c->pos] != '{') {
|
|
253
|
+
pfail(c, "\\p needs a {property} name");
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
c->pos++;
|
|
257
|
+
if (c->pos < c->n && c->s[c->pos] == '^') {
|
|
258
|
+
inner_neg = true;
|
|
259
|
+
c->pos++;
|
|
260
|
+
}
|
|
261
|
+
size_t start = c->pos;
|
|
262
|
+
while (c->pos < c->n && c->s[c->pos] != '}') c->pos++;
|
|
263
|
+
if (c->pos >= c->n) {
|
|
264
|
+
pfail(c, "unterminated \\p{...}");
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
size_t n = c->pos - start;
|
|
268
|
+
c->pos++; /* the closing brace */
|
|
269
|
+
if (n == 0) {
|
|
270
|
+
pfail(c, "empty \\p{} property name");
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const teptris_uc_prop *p = uc_find(c->s + start, n);
|
|
274
|
+
if (p == NULL) {
|
|
275
|
+
pfail(c, "unknown \\p{...} property name");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
bool negate = negate_letter != inner_neg;
|
|
279
|
+
cls_reserve(c, cl, negate ? (size_t)2 * p->n + 8 : (size_t)p->n + 8);
|
|
280
|
+
if (negate) {
|
|
281
|
+
cls_append_complement(c, cl, p->ranges, p->n);
|
|
282
|
+
} else {
|
|
283
|
+
for (int i = 0; i < p->n; i++) {
|
|
284
|
+
cl->ranges[cl->n_ranges].lo = p->ranges[i].lo;
|
|
285
|
+
cl->ranges[cl->n_ranges].hi = p->ranges[i].hi;
|
|
286
|
+
cl->n_ranges++;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
202
291
|
/* expand a class shorthand (\d \w \s) into its ranges */
|
|
203
292
|
static void cls_shorthand(pctx *c, ra *cl, uint32_t e) {
|
|
204
293
|
if (e == 'd' || e == 'D') {
|
|
@@ -241,6 +330,10 @@ static long class_escape(pctx *c, ra *cl) {
|
|
|
241
330
|
c->pos++;
|
|
242
331
|
cls_shorthand(c, cl, e);
|
|
243
332
|
return -1;
|
|
333
|
+
case 'p': case 'P':
|
|
334
|
+
c->pos++;
|
|
335
|
+
prop_escape(c, cl, e == 'P');
|
|
336
|
+
return -1;
|
|
244
337
|
case 'x': {
|
|
245
338
|
c->pos++;
|
|
246
339
|
if (c->pos + 2 > c->n) {
|
|
@@ -291,6 +384,34 @@ static long class_escape(pctx *c, ra *cl) {
|
|
|
291
384
|
}
|
|
292
385
|
|
|
293
386
|
/* parse the body of a [...]; c->pos sits after '[' */
|
|
387
|
+
/* sort + merge a class's ranges in place (property tables arrive
|
|
388
|
+
* sorted; literals interleave arbitrarily) so matching can binary
|
|
389
|
+
* search and negation sees a canonical form */
|
|
390
|
+
static void cls_sort_merge(pctx *c, ra *cl) {
|
|
391
|
+
(void)c;
|
|
392
|
+
int n = cl->n_ranges;
|
|
393
|
+
for (int i = 1; i < n; i++) {
|
|
394
|
+
ra_range r = cl->ranges[i];
|
|
395
|
+
int j = i - 1;
|
|
396
|
+
while (j >= 0 && (cl->ranges[j].lo > r.lo)) {
|
|
397
|
+
cl->ranges[j + 1] = cl->ranges[j];
|
|
398
|
+
j--;
|
|
399
|
+
}
|
|
400
|
+
cl->ranges[j + 1] = r;
|
|
401
|
+
}
|
|
402
|
+
int w = 0;
|
|
403
|
+
for (int i = 1; i < n; i++) {
|
|
404
|
+
if (cl->ranges[i].lo <= cl->ranges[w].hi + 1) {
|
|
405
|
+
if (cl->ranges[i].hi > cl->ranges[w].hi) {
|
|
406
|
+
cl->ranges[w].hi = cl->ranges[i].hi;
|
|
407
|
+
}
|
|
408
|
+
} else {
|
|
409
|
+
cl->ranges[++w] = cl->ranges[i];
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
cl->n_ranges = w + 1;
|
|
413
|
+
}
|
|
414
|
+
|
|
294
415
|
static ra *rclass(pctx *c) {
|
|
295
416
|
ra *cl = rn(c, RA_CLASS);
|
|
296
417
|
if (c->pos < c->n && c->s[c->pos] == '^') {
|
|
@@ -303,6 +424,7 @@ static ra *rclass(pctx *c) {
|
|
|
303
424
|
while (c->pos < c->n) {
|
|
304
425
|
if (c->s[c->pos] == ']' && !first) {
|
|
305
426
|
c->pos++;
|
|
427
|
+
cls_sort_merge(c, cl);
|
|
306
428
|
return cl;
|
|
307
429
|
}
|
|
308
430
|
first = false;
|
|
@@ -495,6 +617,13 @@ static ra *ratom(pctx *c) {
|
|
|
495
617
|
cls_shorthand(c, cl, e);
|
|
496
618
|
return cl;
|
|
497
619
|
}
|
|
620
|
+
if (e == 'p' || e == 'P') {
|
|
621
|
+
c->pos++;
|
|
622
|
+
ra *cl = rn(c, RA_CLASS);
|
|
623
|
+
prop_escape(c, cl, e == 'P');
|
|
624
|
+
if (c->err[0] != '\0') return NULL;
|
|
625
|
+
return cl;
|
|
626
|
+
}
|
|
498
627
|
if (e == 'b') {
|
|
499
628
|
c->pos++;
|
|
500
629
|
return rn(c, RA_WORDB);
|
|
@@ -701,12 +830,13 @@ static bool emit_node(nctx *c, ra *r, frag *f) {
|
|
|
701
830
|
int s = nstate(c, RS_CHAR);
|
|
702
831
|
if (s < 0) return false;
|
|
703
832
|
if (r->ci) {
|
|
704
|
-
/* a folded letter matches both cases
|
|
833
|
+
/* a folded letter matches both cases (stored ascending:
|
|
834
|
+
* cls_match binary-searches) */
|
|
705
835
|
c->states[s].ranges = teptris_arena_alloc(c->a, 2 * sizeof(ra_range));
|
|
706
|
-
c->states[s].ranges[0].lo = r->cp;
|
|
707
|
-
c->states[s].ranges[0].hi = r->cp;
|
|
708
|
-
c->states[s].ranges[1].lo =
|
|
709
|
-
c->states[s].ranges[1].hi =
|
|
836
|
+
c->states[s].ranges[0].lo = fold_cp(r->cp) - 32;
|
|
837
|
+
c->states[s].ranges[0].hi = fold_cp(r->cp) - 32;
|
|
838
|
+
c->states[s].ranges[1].lo = r->cp;
|
|
839
|
+
c->states[s].ranges[1].hi = r->cp;
|
|
710
840
|
c->states[s].n_ranges = 2;
|
|
711
841
|
} else {
|
|
712
842
|
c->states[s].ranges = teptris_arena_alloc(c->a, sizeof(ra_range));
|
|
@@ -937,9 +1067,15 @@ struct sch_regex *sch_regex_compile(teptris_arena *a, const char *pattern,
|
|
|
937
1067
|
|
|
938
1068
|
static bool cls_match(const rstate *st, uint32_t cp) {
|
|
939
1069
|
if (st->any) return true;
|
|
1070
|
+
int lo = 0, hi = st->n_ranges - 1;
|
|
940
1071
|
bool in = false;
|
|
941
|
-
|
|
942
|
-
|
|
1072
|
+
while (lo <= hi) {
|
|
1073
|
+
int mid = (lo + hi) / 2;
|
|
1074
|
+
if (cp < st->ranges[mid].lo) {
|
|
1075
|
+
hi = mid - 1;
|
|
1076
|
+
} else if (cp > st->ranges[mid].hi) {
|
|
1077
|
+
lo = mid + 1;
|
|
1078
|
+
} else {
|
|
943
1079
|
in = true;
|
|
944
1080
|
break;
|
|
945
1081
|
}
|