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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a15759fbe1769570b78923b39bb95576a8d42fed349e61fde761085dcf0c7b85
4
- data.tar.gz: 2622149afc41e720402bfbbba2f1f85499ec887e44ab6fa2f7604f27cb6db50c
3
+ metadata.gz: 4063376572c74e54b603e2c960d0c37a6f7322fcb60fc13c851ba537a5ecc3f4
4
+ data.tar.gz: 2c9216707cc91cb020909c0606ee1db5c6303de629eae1db1b9f81e003d4e512
5
5
  SHA512:
6
- metadata.gz: 7b32e4a4e8165a739221d26b2904593be57b9c6b12d55f4a29d5ff10ede9becfb2c7dca61e8b70e6374acb859b972812b1d21bf17ff46c0216c3c048fc33187e
7
- data.tar.gz: 83a570f3731f22e40570200251d4daae427e3a39c74ef96cb8259b0a5a9247ef810bab18638b59ae0f2711fb2bfdc38d0cad37afdf0ca3cdcaa240d76b08a500
6
+ metadata.gz: 634870c546775f3b2405803b9a0a34b80e8aeda5be6c7da5b488e481b216bafa1cfa4b04391c959633937c0bc4ba20e0379a3e3dc393a43311298e59eac2c0b3
7
+ data.tar.gz: 242e90ad01de5cf198eaf34bf0ac212fba289b9dd2ee70dc10846fbbf84c8eeca88e91851d9334ead183b8f2c7c697bd9e2f53f4903c51b1d425111cc33bf8b8
@@ -1,4 +1,4 @@
1
- # libteptris 0.3.23 — vendored source
1
+ # libteptris 0.3.24 — vendored source
2
2
 
3
3
  This directory carries the COMPLETE C source of the engine this
4
4
  gem's extension was built from (the packaging doctrine: compiled
@@ -3,7 +3,7 @@
3
3
 
4
4
  #define TEPTRIS_VERSION_MAJOR 0
5
5
  #define TEPTRIS_VERSION_MINOR 3
6
- #define TEPTRIS_VERSION_PATCH 23
7
- #define TEPTRIS_VERSION_STRING "0.3.23"
6
+ #define TEPTRIS_VERSION_PATCH 24
7
+ #define TEPTRIS_VERSION_STRING "0.3.24"
8
8
 
9
9
  #endif /* TEPTRIS_VERSION_H */
@@ -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 = fold_cp(r->cp) - 32;
709
- c->states[s].ranges[1].hi = fold_cp(r->cp) - 32;
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
- for (int i = 0; i < st->n_ranges; i++) {
942
- if (cp >= st->ranges[i].lo && cp <= st->ranges[i].hi) {
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
  }