pyscriptc 0.1.0__py3-none-any.whl

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.
Files changed (54) hide show
  1. pyscriptc/__init__.py +3 -0
  2. pyscriptc/__main__.py +3 -0
  3. pyscriptc/_posthog_token.py +1 -0
  4. pyscriptc/builtins.py +156 -0
  5. pyscriptc/canonical.py +167 -0
  6. pyscriptc/check.py +49 -0
  7. pyscriptc/cli.py +271 -0
  8. pyscriptc/coverage.py +388 -0
  9. pyscriptc/debug.py +120 -0
  10. pyscriptc/diagnostics.py +179 -0
  11. pyscriptc/errors.py +56 -0
  12. pyscriptc/ir.py +365 -0
  13. pyscriptc/llvm.py +2129 -0
  14. pyscriptc/log.py +127 -0
  15. pyscriptc/lower/__init__.py +1071 -0
  16. pyscriptc/lower/_calls.py +1499 -0
  17. pyscriptc/lower/_classes.py +969 -0
  18. pyscriptc/lower/_core.py +301 -0
  19. pyscriptc/lower/_expr.py +886 -0
  20. pyscriptc/lower/_stdlib.py +491 -0
  21. pyscriptc/lower/_stdlib_shared.py +93 -0
  22. pyscriptc/lower/_stmt.py +1173 -0
  23. pyscriptc/package.py +249 -0
  24. pyscriptc/restlower.py +1008 -0
  25. pyscriptc/runtime/ps_argv.c +28 -0
  26. pyscriptc/runtime/ps_b64.c +168 -0
  27. pyscriptc/runtime/ps_coll.c +133 -0
  28. pyscriptc/runtime/ps_dt.c +388 -0
  29. pyscriptc/runtime/ps_hash.c +411 -0
  30. pyscriptc/runtime/ps_help.c +219 -0
  31. pyscriptc/runtime/ps_hmac.c +120 -0
  32. pyscriptc/runtime/ps_io.c +198 -0
  33. pyscriptc/runtime/ps_island.c +272 -0
  34. pyscriptc/runtime/ps_json.c +402 -0
  35. pyscriptc/runtime/ps_mix.c +47 -0
  36. pyscriptc/runtime/ps_more.c +1089 -0
  37. pyscriptc/runtime/ps_osmore.c +447 -0
  38. pyscriptc/runtime/ps_path.c +547 -0
  39. pyscriptc/runtime/ps_re.c +1102 -0
  40. pyscriptc/runtime/ps_rt.c +1175 -0
  41. pyscriptc/runtime/ps_rt.h +189 -0
  42. pyscriptc/runtime/ps_struct.c +291 -0
  43. pyscriptc/runtime/ps_time.c +207 -0
  44. pyscriptc/runtime/ps_unicode.c +1521 -0
  45. pyscriptc/runtime/ps_url.c +327 -0
  46. pyscriptc/stdlib_queue.py +191 -0
  47. pyscriptc/stdmore.py +1596 -0
  48. pyscriptc/telemetry.py +219 -0
  49. pyscriptc-0.1.0.dist-info/METADATA +187 -0
  50. pyscriptc-0.1.0.dist-info/RECORD +54 -0
  51. pyscriptc-0.1.0.dist-info/WHEEL +5 -0
  52. pyscriptc-0.1.0.dist-info/entry_points.txt +2 -0
  53. pyscriptc-0.1.0.dist-info/licenses/LICENSE +201 -0
  54. pyscriptc-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1102 @@
1
+ /* Backtracking subset of re. Patterns that can loop without consuming
2
+ (for example "()*") stop with RuntimeError once the fuel is spent.
3
+ ps_re_findall is the one-group form. Two to four groups go through
4
+ ps_re_findall_groups, which returns pointers to rows of PsBuf. A dynamic
5
+ pattern that actually has two or more groups still raises ValueError here. */
6
+
7
+ #include "ps_rt.h"
8
+
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ enum {
13
+ OP_CHAR = 1,
14
+ OP_ANY,
15
+ OP_CLASS,
16
+ OP_BOL,
17
+ OP_EOL,
18
+ OP_WB,
19
+ OP_NWB,
20
+ OP_BACK,
21
+ OP_SPLIT,
22
+ OP_JUMP,
23
+ OP_SAVE,
24
+ OP_MATCH
25
+ };
26
+
27
+ typedef struct Op {
28
+ int op;
29
+ int a;
30
+ int b;
31
+ int c;
32
+ } Op;
33
+
34
+ typedef struct Bits {
35
+ unsigned char b[32];
36
+ int negate;
37
+ } Bits;
38
+
39
+ typedef struct Comp {
40
+ const char *p;
41
+ int64_t n;
42
+ int64_t i;
43
+ Op *ops;
44
+ int64_t len;
45
+ int64_t cap;
46
+ Bits *bits;
47
+ int nbits;
48
+ int groups;
49
+ const char *err;
50
+ } Comp;
51
+
52
+ typedef struct Frame {
53
+ int pc;
54
+ int64_t sp;
55
+ int64_t cs[32];
56
+ int64_t ce[32];
57
+ } Frame;
58
+
59
+ typedef struct Eng {
60
+ const char *text;
61
+ int64_t tlen;
62
+ Op *ops;
63
+ Bits *bits;
64
+ int64_t fuel;
65
+ int64_t cs[32];
66
+ int64_t ce[32];
67
+ int64_t end;
68
+ Frame *stack;
69
+ int64_t top;
70
+ int64_t scap;
71
+ Comp *pool;
72
+ } Eng;
73
+
74
+ static void re_err(Comp *c, const char *msg) {
75
+ if (c->err == NULL) {
76
+ c->err = msg;
77
+ }
78
+ }
79
+
80
+ static int emit(Comp *c, Op op) {
81
+ if (c->err) {
82
+ return 0;
83
+ }
84
+ if (c->len == c->cap) {
85
+ int64_t cap = c->cap == 0 ? 32 : c->cap * 2;
86
+ Op *ops = realloc(c->ops, (size_t)cap * sizeof(Op));
87
+ if (ops == NULL) {
88
+ abort();
89
+ }
90
+ c->ops = ops;
91
+ c->cap = cap;
92
+ }
93
+ c->ops[c->len] = op;
94
+ return (int)c->len++;
95
+ }
96
+
97
+ static void bit_set(Bits *bits, int ch) { bits->b[ch >> 3] |= (unsigned char)(1u << (ch & 7)); }
98
+
99
+ static int bit_has(const Bits *bits, int ch) { return (bits->b[ch >> 3] >> (ch & 7)) & 1; }
100
+
101
+ static int is_word(int ch) {
102
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_';
103
+ }
104
+
105
+ static int starts_atom(Comp *c) {
106
+ if (c->i >= c->n) {
107
+ return 0;
108
+ }
109
+ char ch = c->p[c->i];
110
+ if (ch == '|' || ch == ')') {
111
+ return 0;
112
+ }
113
+ if (ch == '*' || ch == '+' || ch == '?') {
114
+ re_err(c, "nothing to repeat");
115
+ return 0;
116
+ }
117
+ return 1;
118
+ }
119
+
120
+ static void compile_alt(Comp *c);
121
+
122
+ static int skip_class(const char *p, int64_t n, int64_t i) {
123
+ if (i < n && p[i] == '^') {
124
+ i++;
125
+ }
126
+ if (i < n && p[i] == ']') {
127
+ i++;
128
+ }
129
+ while (i < n && p[i] != ']') {
130
+ if (p[i] == '\\' && i + 1 < n) {
131
+ i += 2;
132
+ continue;
133
+ }
134
+ i++;
135
+ }
136
+ if (i < n && p[i] == ']') {
137
+ i++;
138
+ }
139
+ return (int)i;
140
+ }
141
+
142
+ static int has_top_alt(Comp *c) {
143
+ int64_t i = c->i;
144
+ int depth = 0;
145
+ while (i < c->n) {
146
+ char ch = c->p[i];
147
+ if (ch == '\\') {
148
+ i += 2;
149
+ continue;
150
+ }
151
+ if (ch == '[') {
152
+ i = skip_class(c->p, c->n, i + 1);
153
+ continue;
154
+ }
155
+ if (ch == '(') {
156
+ depth++;
157
+ } else if (ch == ')') {
158
+ if (depth == 0) {
159
+ break;
160
+ }
161
+ depth--;
162
+ } else if (ch == '|' && depth == 0) {
163
+ return 1;
164
+ }
165
+ i++;
166
+ }
167
+ return 0;
168
+ }
169
+
170
+ static void add_class_escape(Comp *c, Bits *bits, char e) {
171
+ if (e == 'd') {
172
+ for (int ch = '0'; ch <= '9'; ch++) {
173
+ bit_set(bits, ch);
174
+ }
175
+ return;
176
+ }
177
+ if (e == 'D') {
178
+ for (int ch = 0; ch < 256; ch++) {
179
+ if (ch < '0' || ch > '9') {
180
+ bit_set(bits, ch);
181
+ }
182
+ }
183
+ return;
184
+ }
185
+ if (e == 'w') {
186
+ for (int ch = 0; ch < 256; ch++) {
187
+ if (is_word(ch)) {
188
+ bit_set(bits, ch);
189
+ }
190
+ }
191
+ return;
192
+ }
193
+ if (e == 'W') {
194
+ for (int ch = 0; ch < 256; ch++) {
195
+ if (!is_word(ch)) {
196
+ bit_set(bits, ch);
197
+ }
198
+ }
199
+ return;
200
+ }
201
+ if (e == 's') {
202
+ bit_set(bits, ' ');
203
+ bit_set(bits, '\t');
204
+ bit_set(bits, '\n');
205
+ bit_set(bits, '\r');
206
+ bit_set(bits, '\f');
207
+ bit_set(bits, '\v');
208
+ return;
209
+ }
210
+ if (e == 'S') {
211
+ for (int ch = 0; ch < 256; ch++) {
212
+ if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != '\f' && ch != '\v') {
213
+ bit_set(bits, ch);
214
+ }
215
+ }
216
+ return;
217
+ }
218
+ if (e == 'n') {
219
+ bit_set(bits, '\n');
220
+ return;
221
+ }
222
+ if (e == 't') {
223
+ bit_set(bits, '\t');
224
+ return;
225
+ }
226
+ if (e == 'r') {
227
+ bit_set(bits, '\r');
228
+ return;
229
+ }
230
+ if (e == 'b') {
231
+ bit_set(bits, '\b');
232
+ return;
233
+ }
234
+ if ((e >= 'A' && e <= 'Z') || (e >= 'a' && e <= 'z') || (e >= '0' && e <= '9')) {
235
+ re_err(c, "bad escape");
236
+ return;
237
+ }
238
+ bit_set(bits, (unsigned char)e);
239
+ }
240
+
241
+ static void compile_class(Comp *c) {
242
+ c->i++;
243
+ Bits bits;
244
+ memset(&bits, 0, sizeof bits);
245
+ if (c->i < c->n && c->p[c->i] == '^') {
246
+ bits.negate = 1;
247
+ c->i++;
248
+ }
249
+ int first = 1;
250
+ if (c->i >= c->n) {
251
+ re_err(c, "unterminated character set");
252
+ return;
253
+ }
254
+ while (c->i < c->n && !(c->p[c->i] == ']' && !first)) {
255
+ first = 0;
256
+ unsigned char ch;
257
+ if (c->p[c->i] == '\\') {
258
+ if (c->i + 1 >= c->n) {
259
+ re_err(c, "bad escape");
260
+ return;
261
+ }
262
+ char e = c->p[c->i + 1];
263
+ c->i += 2;
264
+ if (e == 'd' || e == 'D' || e == 'w' || e == 'W' || e == 's' || e == 'S') {
265
+ add_class_escape(c, &bits, e);
266
+ continue;
267
+ }
268
+ add_class_escape(c, &bits, e);
269
+ ch = (unsigned char)e;
270
+ if (e == 'n') {
271
+ ch = '\n';
272
+ } else if (e == 't') {
273
+ ch = '\t';
274
+ } else if (e == 'r') {
275
+ ch = '\r';
276
+ } else if (e == 'b') {
277
+ ch = '\b';
278
+ }
279
+ } else {
280
+ ch = (unsigned char)c->p[c->i++];
281
+ }
282
+ if (c->i + 1 < c->n && c->p[c->i] == '-' && c->p[c->i + 1] != ']') {
283
+ c->i++;
284
+ unsigned char end;
285
+ if (c->p[c->i] == '\\') {
286
+ re_err(c, "unsupported class range");
287
+ return;
288
+ }
289
+ end = (unsigned char)c->p[c->i++];
290
+ if (end < ch) {
291
+ re_err(c, "bad character range");
292
+ return;
293
+ }
294
+ for (int k = ch; k <= end; k++) {
295
+ bit_set(&bits, k);
296
+ }
297
+ } else if (!(c->p[c->i - 1] == '\\' && (ch == 'd' || ch == 'w' || ch == 's'))) {
298
+ /* Single characters were already set for ordinary chars. Escapes that
299
+ expanded a set returned early. A plain character still needs a bit. */
300
+ if (c->i >= 1 && c->p[c->i - 1] != '\\') {
301
+ bit_set(&bits, ch);
302
+ }
303
+ }
304
+ }
305
+ if (c->i >= c->n || c->p[c->i] != ']') {
306
+ re_err(c, "unterminated character set");
307
+ return;
308
+ }
309
+ c->i++;
310
+ if (c->nbits == 0) {
311
+ c->bits = NULL;
312
+ }
313
+ c->bits = realloc(c->bits, (size_t)(c->nbits + 1) * sizeof(Bits));
314
+ if (c->bits == NULL) {
315
+ abort();
316
+ }
317
+ c->bits[c->nbits] = bits;
318
+ Op op = {OP_CLASS, c->nbits, 0, 0};
319
+ c->nbits++;
320
+ emit(c, op);
321
+ }
322
+
323
+ static void compile_escape(Comp *c) {
324
+ if (c->i + 1 >= c->n) {
325
+ re_err(c, "bad escape");
326
+ return;
327
+ }
328
+ char e = c->p[++c->i];
329
+ c->i++;
330
+ if (e >= '1' && e <= '9') {
331
+ int g = e - '0';
332
+ Op op = {OP_BACK, g, 0, 0};
333
+ emit(c, op);
334
+ return;
335
+ }
336
+ if (e == 'd' || e == 'D' || e == 'w' || e == 'W' || e == 's' || e == 'S') {
337
+ Bits bits;
338
+ memset(&bits, 0, sizeof bits);
339
+ add_class_escape(c, &bits, e);
340
+ c->bits = realloc(c->bits, (size_t)(c->nbits + 1) * sizeof(Bits));
341
+ if (c->bits == NULL) {
342
+ abort();
343
+ }
344
+ c->bits[c->nbits] = bits;
345
+ Op op = {OP_CLASS, c->nbits, 0, 0};
346
+ c->nbits++;
347
+ emit(c, op);
348
+ return;
349
+ }
350
+ if (e == 'n' || e == 't' || e == 'r') {
351
+ char ch = e == 'n' ? '\n' : e == 't' ? '\t' : '\r';
352
+ Op op = {OP_CHAR, 0, 0, (unsigned char)ch};
353
+ emit(c, op);
354
+ return;
355
+ }
356
+ if (e == 'b') {
357
+ Op op = {OP_WB, 0, 0, 0};
358
+ emit(c, op);
359
+ return;
360
+ }
361
+ if (e == 'B') {
362
+ Op op = {OP_NWB, 0, 0, 0};
363
+ emit(c, op);
364
+ return;
365
+ }
366
+ if ((e >= 'A' && e <= 'Z') || (e >= 'a' && e <= 'z') || e == '0') {
367
+ re_err(c, "bad escape");
368
+ return;
369
+ }
370
+ Op op = {OP_CHAR, 0, 0, (unsigned char)e};
371
+ emit(c, op);
372
+ }
373
+
374
+ static void compile_atom(Comp *c) {
375
+ if (c->i >= c->n) {
376
+ re_err(c, "unexpected end of pattern");
377
+ return;
378
+ }
379
+ char ch = c->p[c->i];
380
+ if (ch == '(') {
381
+ c->i++;
382
+ int cap = 1;
383
+ if (c->i + 1 < c->n && c->p[c->i] == '?' && c->p[c->i + 1] == ':') {
384
+ cap = 0;
385
+ c->i += 2;
386
+ } else if (c->i < c->n && c->p[c->i] == '?') {
387
+ re_err(c, "unsupported regular expression");
388
+ return;
389
+ }
390
+ int g = 0;
391
+ if (cap) {
392
+ c->groups++;
393
+ if (c->groups >= 32) {
394
+ re_err(c, "too many capturing groups");
395
+ return;
396
+ }
397
+ g = c->groups;
398
+ Op save = {OP_SAVE, g, 0, 0};
399
+ emit(c, save);
400
+ }
401
+ compile_alt(c);
402
+ if (c->i >= c->n || c->p[c->i] != ')') {
403
+ re_err(c, "missing )");
404
+ return;
405
+ }
406
+ c->i++;
407
+ if (cap) {
408
+ Op save = {OP_SAVE, g, 1, 0};
409
+ emit(c, save);
410
+ }
411
+ return;
412
+ }
413
+ if (ch == '[') {
414
+ compile_class(c);
415
+ return;
416
+ }
417
+ if (ch == '^') {
418
+ c->i++;
419
+ Op op = {OP_BOL, 0, 0, 0};
420
+ emit(c, op);
421
+ return;
422
+ }
423
+ if (ch == '$') {
424
+ c->i++;
425
+ Op op = {OP_EOL, 0, 0, 0};
426
+ emit(c, op);
427
+ return;
428
+ }
429
+ if (ch == '.') {
430
+ c->i++;
431
+ Op op = {OP_ANY, 0, 0, 0};
432
+ emit(c, op);
433
+ return;
434
+ }
435
+ if (ch == '\\') {
436
+ compile_escape(c);
437
+ return;
438
+ }
439
+ c->i++;
440
+ Op op = {OP_CHAR, 0, 0, (unsigned char)ch};
441
+ emit(c, op);
442
+ }
443
+
444
+ static void relocate(Op *ops, int count, int delta) {
445
+ for (int i = 0; i < count; i++) {
446
+ if (ops[i].op == OP_SPLIT || ops[i].op == OP_JUMP) {
447
+ ops[i].a += delta;
448
+ if (ops[i].op == OP_SPLIT) {
449
+ ops[i].b += delta;
450
+ }
451
+ }
452
+ }
453
+ }
454
+
455
+ static void append_ops(Comp *c, Op *ops, int count, int base_was) {
456
+ int delta = (int)c->len - base_was;
457
+ for (int i = 0; i < count; i++) {
458
+ Op op = ops[i];
459
+ if (op.op == OP_SPLIT || op.op == OP_JUMP) {
460
+ op.a += delta;
461
+ if (op.op == OP_SPLIT) {
462
+ op.b += delta;
463
+ }
464
+ }
465
+ emit(c, op);
466
+ }
467
+ }
468
+
469
+ static int parse_quant(Comp *c, int *min, int *max, int *greedy) {
470
+ if (c->i >= c->n) {
471
+ return 0;
472
+ }
473
+ char ch = c->p[c->i];
474
+ if (ch == '*') {
475
+ *min = 0;
476
+ *max = -1;
477
+ c->i++;
478
+ } else if (ch == '+') {
479
+ *min = 1;
480
+ *max = -1;
481
+ c->i++;
482
+ } else if (ch == '?') {
483
+ *min = 0;
484
+ *max = 1;
485
+ c->i++;
486
+ } else if (ch == '{') {
487
+ int64_t save = c->i;
488
+ c->i++;
489
+ int saw_num = 0;
490
+ int lo = 0;
491
+ while (c->i < c->n && c->p[c->i] >= '0' && c->p[c->i] <= '9') {
492
+ saw_num = 1;
493
+ lo = lo * 10 + (c->p[c->i] - '0');
494
+ if (lo > 100000) {
495
+ re_err(c, "repeat is too large");
496
+ return 0;
497
+ }
498
+ c->i++;
499
+ }
500
+ int hi = lo;
501
+ int unbounded = 0;
502
+ if (c->i < c->n && c->p[c->i] == ',') {
503
+ c->i++;
504
+ if (c->i < c->n && c->p[c->i] >= '0' && c->p[c->i] <= '9') {
505
+ hi = 0;
506
+ while (c->i < c->n && c->p[c->i] >= '0' && c->p[c->i] <= '9') {
507
+ hi = hi * 10 + (c->p[c->i] - '0');
508
+ if (hi > 100000) {
509
+ re_err(c, "repeat is too large");
510
+ return 0;
511
+ }
512
+ c->i++;
513
+ }
514
+ } else {
515
+ unbounded = 1;
516
+ hi = -1;
517
+ }
518
+ } else if (!saw_num) {
519
+ c->i = save;
520
+ return 0;
521
+ }
522
+ if (c->i >= c->n || c->p[c->i] != '}') {
523
+ c->i = save;
524
+ return 0;
525
+ }
526
+ c->i++;
527
+ if (!unbounded && hi < lo) {
528
+ re_err(c, "min repeat greater than max");
529
+ return 0;
530
+ }
531
+ *min = saw_num ? lo : 0;
532
+ *max = unbounded ? -1 : hi;
533
+ } else {
534
+ return 0;
535
+ }
536
+ *greedy = 1;
537
+ if (c->i < c->n && c->p[c->i] == '?') {
538
+ *greedy = 0;
539
+ c->i++;
540
+ }
541
+ return 1;
542
+ }
543
+
544
+ static void emit_copy(Comp *c, Op *atom, int count) {
545
+ append_ops(c, atom, count, 0);
546
+ }
547
+
548
+ static void emit_star(Comp *c, Op *atom, int count, int greedy) {
549
+ int split = emit(c, (Op){OP_SPLIT, 0, 0, 0});
550
+ int take = (int)c->len;
551
+ emit_copy(c, atom, count);
552
+ emit(c, (Op){OP_JUMP, split, 0, 0});
553
+ int done = (int)c->len;
554
+ if (greedy) {
555
+ c->ops[split].a = take;
556
+ c->ops[split].b = done;
557
+ } else {
558
+ c->ops[split].a = done;
559
+ c->ops[split].b = take;
560
+ }
561
+ }
562
+
563
+ static void emit_opt(Comp *c, Op *atom, int count, int greedy) {
564
+ int split = emit(c, (Op){OP_SPLIT, 0, 0, 0});
565
+ int take = (int)c->len;
566
+ emit_copy(c, atom, count);
567
+ int done = (int)c->len;
568
+ if (greedy) {
569
+ c->ops[split].a = take;
570
+ c->ops[split].b = done;
571
+ } else {
572
+ c->ops[split].a = done;
573
+ c->ops[split].b = take;
574
+ }
575
+ }
576
+
577
+ static void compile_repeat(Comp *c) {
578
+ int op_at = (int)c->len;
579
+ compile_atom(c);
580
+ if (c->err) {
581
+ return;
582
+ }
583
+ int count = (int)c->len - op_at;
584
+ int min = 0;
585
+ int max = 0;
586
+ int greedy = 1;
587
+ if (!parse_quant(c, &min, &max, &greedy)) {
588
+ return;
589
+ }
590
+ if (min > 64 || (max >= 0 && max - min > 64)) {
591
+ re_err(c, "repeat is too large");
592
+ return;
593
+ }
594
+ Op *atom = malloc((size_t)count * sizeof(Op));
595
+ if (atom == NULL) {
596
+ abort();
597
+ }
598
+ memcpy(atom, c->ops + op_at, (size_t)count * sizeof(Op));
599
+ relocate(atom, count, -op_at);
600
+ c->len = op_at;
601
+ for (int k = 0; k < min; k++) {
602
+ emit_copy(c, atom, count);
603
+ }
604
+ if (max < 0) {
605
+ emit_star(c, atom, count, greedy);
606
+ } else {
607
+ for (int k = min; k < max; k++) {
608
+ emit_opt(c, atom, count, greedy);
609
+ }
610
+ }
611
+ free(atom);
612
+ }
613
+
614
+ static void compile_concat(Comp *c) {
615
+ while (starts_atom(c) && c->err == NULL) {
616
+ compile_repeat(c);
617
+ }
618
+ }
619
+
620
+ static void compile_alt(Comp *c) {
621
+ if (!has_top_alt(c)) {
622
+ compile_concat(c);
623
+ return;
624
+ }
625
+ int split = emit(c, (Op){OP_SPLIT, 0, 0, 0});
626
+ compile_concat(c);
627
+ int jump = emit(c, (Op){OP_JUMP, 0, 0, 0});
628
+ if (c->i >= c->n || c->p[c->i] != '|') {
629
+ re_err(c, "expected alternation");
630
+ return;
631
+ }
632
+ c->i++;
633
+ int right = (int)c->len;
634
+ compile_alt(c);
635
+ int end = (int)c->len;
636
+ c->ops[split].a = split + 1;
637
+ c->ops[split].b = right;
638
+ c->ops[jump].a = end;
639
+ }
640
+
641
+ static void compile_pattern(Comp *c) {
642
+ compile_alt(c);
643
+ if (c->err) {
644
+ return;
645
+ }
646
+ if (c->i != c->n) {
647
+ re_err(c, "unbalanced pattern");
648
+ return;
649
+ }
650
+ emit(c, (Op){OP_MATCH, 0, 0, 0});
651
+ }
652
+
653
+ static void eng_fail(Eng *e, int code, const char *msg) {
654
+ free(e->stack);
655
+ e->stack = NULL;
656
+ if (e->pool) {
657
+ free(e->pool->ops);
658
+ free(e->pool->bits);
659
+ e->pool->ops = NULL;
660
+ e->pool->bits = NULL;
661
+ }
662
+ ps_raise_cstr(code, msg);
663
+ }
664
+
665
+ static void eng_push(Eng *e, int pc, int64_t sp) {
666
+ if (e->top == e->scap) {
667
+ int64_t cap = e->scap == 0 ? 64 : e->scap * 2;
668
+ if (cap > 1000000) {
669
+ eng_fail(e, PS_RUNTIME, "regular expression fuel exhausted");
670
+ }
671
+ Frame *stack = realloc(e->stack, (size_t)cap * sizeof(Frame));
672
+ if (stack == NULL) {
673
+ abort();
674
+ }
675
+ e->stack = stack;
676
+ e->scap = cap;
677
+ }
678
+ Frame *fr = &e->stack[e->top++];
679
+ fr->pc = pc;
680
+ fr->sp = sp;
681
+ memcpy(fr->cs, e->cs, sizeof fr->cs);
682
+ memcpy(fr->ce, e->ce, sizeof fr->ce);
683
+ }
684
+
685
+ static int eng_pop(Eng *e, int *pc, int64_t *sp) {
686
+ if (e->top == 0) {
687
+ return 0;
688
+ }
689
+ Frame *fr = &e->stack[--e->top];
690
+ *pc = fr->pc;
691
+ *sp = fr->sp;
692
+ memcpy(e->cs, fr->cs, sizeof e->cs);
693
+ memcpy(e->ce, fr->ce, sizeof e->ce);
694
+ return 1;
695
+ }
696
+
697
+ static int word_at(Eng *e, int64_t sp) {
698
+ if (sp < 0 || sp >= e->tlen) {
699
+ return 0;
700
+ }
701
+ return is_word((unsigned char)e->text[sp]);
702
+ }
703
+
704
+ static int eng_run(Eng *e, int pc, int64_t sp) {
705
+ while (1) {
706
+ if (--e->fuel < 0) {
707
+ eng_fail(e, PS_RUNTIME, "regular expression fuel exhausted");
708
+ }
709
+ Op op = e->ops[pc];
710
+ switch (op.op) {
711
+ case OP_CHAR:
712
+ if (sp < e->tlen && (unsigned char)e->text[sp] == (unsigned char)op.c) {
713
+ pc++;
714
+ sp++;
715
+ break;
716
+ }
717
+ if (!eng_pop(e, &pc, &sp)) {
718
+ return 0;
719
+ }
720
+ break;
721
+ case OP_ANY:
722
+ if (sp < e->tlen && e->text[sp] != '\n') {
723
+ pc++;
724
+ sp++;
725
+ break;
726
+ }
727
+ if (!eng_pop(e, &pc, &sp)) {
728
+ return 0;
729
+ }
730
+ break;
731
+ case OP_CLASS: {
732
+ int ok = 0;
733
+ if (sp < e->tlen) {
734
+ int has = bit_has(&e->bits[op.a], (unsigned char)e->text[sp]);
735
+ ok = e->bits[op.a].negate ? !has : has;
736
+ }
737
+ if (ok) {
738
+ pc++;
739
+ sp++;
740
+ break;
741
+ }
742
+ if (!eng_pop(e, &pc, &sp)) {
743
+ return 0;
744
+ }
745
+ break;
746
+ }
747
+ case OP_BOL:
748
+ if (sp == 0) {
749
+ pc++;
750
+ break;
751
+ }
752
+ if (!eng_pop(e, &pc, &sp)) {
753
+ return 0;
754
+ }
755
+ break;
756
+ case OP_EOL:
757
+ if (sp == e->tlen || (sp == e->tlen - 1 && e->text[sp] == '\n')) {
758
+ pc++;
759
+ break;
760
+ }
761
+ if (!eng_pop(e, &pc, &sp)) {
762
+ return 0;
763
+ }
764
+ break;
765
+ case OP_WB:
766
+ case OP_NWB: {
767
+ int bound = word_at(e, sp - 1) != word_at(e, sp);
768
+ int ok = op.op == OP_WB ? bound : !bound;
769
+ if (ok) {
770
+ pc++;
771
+ break;
772
+ }
773
+ if (!eng_pop(e, &pc, &sp)) {
774
+ return 0;
775
+ }
776
+ break;
777
+ }
778
+ case OP_BACK: {
779
+ int g = op.a;
780
+ if (e->cs[g] < 0 || e->ce[g] < e->cs[g]) {
781
+ if (!eng_pop(e, &pc, &sp)) {
782
+ return 0;
783
+ }
784
+ break;
785
+ }
786
+ int64_t n = e->ce[g] - e->cs[g];
787
+ if (sp + n <= e->tlen && (n == 0 || memcmp(e->text + sp, e->text + e->cs[g], (size_t)n) == 0)) {
788
+ sp += n;
789
+ pc++;
790
+ break;
791
+ }
792
+ if (!eng_pop(e, &pc, &sp)) {
793
+ return 0;
794
+ }
795
+ break;
796
+ }
797
+ case OP_SPLIT:
798
+ eng_push(e, op.b, sp);
799
+ pc = op.a;
800
+ break;
801
+ case OP_JUMP:
802
+ pc = op.a;
803
+ break;
804
+ case OP_SAVE:
805
+ if (op.b == 0) {
806
+ e->cs[op.a] = sp;
807
+ } else {
808
+ e->ce[op.a] = sp;
809
+ }
810
+ pc++;
811
+ break;
812
+ case OP_MATCH:
813
+ e->end = sp;
814
+ return 1;
815
+ default:
816
+ eng_fail(e, PS_VALUE, "bad regular expression program");
817
+ }
818
+ }
819
+ }
820
+
821
+ static void eng_clear(Eng *e) {
822
+ for (int i = 0; i < 32; i++) {
823
+ e->cs[i] = -1;
824
+ e->ce[i] = -1;
825
+ }
826
+ e->top = 0;
827
+ }
828
+
829
+ static int eng_search(Eng *e, int64_t pos, int64_t *start, int64_t *end) {
830
+ for (int64_t i = pos; i <= e->tlen; i++) {
831
+ eng_clear(e);
832
+ if (eng_run(e, 0, i)) {
833
+ *start = i;
834
+ *end = e->end;
835
+ e->cs[0] = i;
836
+ e->ce[0] = e->end;
837
+ return 1;
838
+ }
839
+ }
840
+ return 0;
841
+ }
842
+
843
+ static void compile_or_raise(Comp *c) {
844
+ compile_pattern(c);
845
+ if (c->err) {
846
+ const char *msg = c->err;
847
+ free(c->ops);
848
+ free(c->bits);
849
+ c->ops = NULL;
850
+ c->bits = NULL;
851
+ ps_raise_cstr(PS_VALUE, msg);
852
+ }
853
+ }
854
+
855
+ static void eng_init(Eng *e, Comp *c, const char *text, int64_t tlen) {
856
+ memset(e, 0, sizeof *e);
857
+ e->text = text;
858
+ e->tlen = tlen;
859
+ e->ops = c->ops;
860
+ e->bits = c->bits;
861
+ e->fuel = 2000000;
862
+ e->pool = c;
863
+ eng_clear(e);
864
+ }
865
+
866
+ static void eng_free(Eng *e) {
867
+ free(e->stack);
868
+ free(e->pool->ops);
869
+ free(e->pool->bits);
870
+ }
871
+
872
+ static PsBuf slice_of(const char *text, int64_t a, int64_t b) {
873
+ PsBuf out;
874
+ if (a < 0 || b < a) {
875
+ ps_buf_copy(&out, "", 0);
876
+ return out;
877
+ }
878
+ ps_buf_view(&out, text + a, b - a);
879
+ return out;
880
+ }
881
+
882
+ static void push_piece(PsSeq *seq, const char *text, int64_t a, int64_t b) {
883
+ PsBuf piece = slice_of(text, a, b);
884
+ ps_seq_push(seq, &piece);
885
+ }
886
+
887
+ PsSeq *ps_re_findall(int64_t pn, char *pat, int64_t tn, char *text) {
888
+ Comp comp;
889
+ memset(&comp, 0, sizeof comp);
890
+ comp.p = pat;
891
+ comp.n = pn;
892
+ compile_or_raise(&comp);
893
+ if (comp.groups >= 2) {
894
+ free(comp.ops);
895
+ free(comp.bits);
896
+ ps_raise_cstr(PS_VALUE, "re.findall with multiple capturing groups returns tuples");
897
+ }
898
+ Eng eng;
899
+ eng_init(&eng, &comp, text, tn);
900
+ PsSeq *seq = ps_seq_new(16, 0);
901
+ int64_t pos = 0;
902
+ while (pos <= tn) {
903
+ int64_t a = 0;
904
+ int64_t b = 0;
905
+ if (!eng_search(&eng, pos, &a, &b)) {
906
+ break;
907
+ }
908
+ if (comp.groups == 0) {
909
+ push_piece(seq, text, a, b);
910
+ } else if (eng.cs[1] < 0) {
911
+ push_piece(seq, text, 0, 0);
912
+ } else {
913
+ push_piece(seq, text, eng.cs[1], eng.ce[1]);
914
+ }
915
+ if (b > a) {
916
+ pos = b;
917
+ } else if (b == tn) {
918
+ break;
919
+ } else {
920
+ pos = b + 1;
921
+ }
922
+ }
923
+ eng_free(&eng);
924
+ return seq;
925
+ }
926
+
927
+ PsSeq *ps_re_findall_groups(int64_t pn, char *pat, int64_t tn, char *text) {
928
+ Comp comp;
929
+ int g;
930
+ memset(&comp, 0, sizeof comp);
931
+ comp.p = pat;
932
+ comp.n = pn;
933
+ compile_or_raise(&comp);
934
+ if (comp.groups < 2 || comp.groups > 4) {
935
+ free(comp.ops);
936
+ free(comp.bits);
937
+ ps_raise_cstr(PS_VALUE, "re.findall group count is not 2 to 4");
938
+ }
939
+ Eng eng;
940
+ eng_init(&eng, &comp, text, tn);
941
+ PsSeq *seq = ps_seq_new((int64_t)sizeof(void *), 0);
942
+ int64_t pos = 0;
943
+ while (pos <= tn) {
944
+ int64_t a = 0;
945
+ int64_t b = 0;
946
+ PsBuf *row;
947
+ if (!eng_search(&eng, pos, &a, &b)) {
948
+ break;
949
+ }
950
+ row = malloc(sizeof(PsBuf) * (size_t)comp.groups);
951
+ if (row == NULL) {
952
+ abort();
953
+ }
954
+ for (g = 0; g < comp.groups; g++) {
955
+ if (eng.cs[g + 1] < 0) {
956
+ ps_buf_copy(&row[g], "", 0);
957
+ } else {
958
+ row[g] = slice_of(text, eng.cs[g + 1], eng.ce[g + 1]);
959
+ }
960
+ }
961
+ ps_seq_push(seq, &row);
962
+ if (b > a) {
963
+ pos = b;
964
+ } else if (b == tn) {
965
+ break;
966
+ } else {
967
+ pos = b + 1;
968
+ }
969
+ }
970
+ eng_free(&eng);
971
+ return seq;
972
+ }
973
+
974
+ static int repl_expand(Eng *e, const char *repl, int64_t rn, int groups, PsGrow *g) {
975
+ for (int64_t i = 0; i < rn; i++) {
976
+ char ch = repl[i];
977
+ if (ch != '\\') {
978
+ ps_grow_byte(g, (unsigned char)ch);
979
+ continue;
980
+ }
981
+ if (i + 1 >= rn) {
982
+ return 0;
983
+ }
984
+ char ech = repl[++i];
985
+ if (ech == '\\') {
986
+ ps_grow_byte(g, '\\');
987
+ continue;
988
+ }
989
+ if (ech == '0' && (i + 1 >= rn || repl[i + 1] < '0' || repl[i + 1] > '9')) {
990
+ ps_grow_byte(g, 0);
991
+ continue;
992
+ }
993
+ if (ech >= '1' && ech <= '9') {
994
+ int val = ech - '0';
995
+ while (i + 1 < rn && repl[i + 1] >= '0' && repl[i + 1] <= '9') {
996
+ val = val * 10 + (repl[i + 1] - '0');
997
+ i++;
998
+ }
999
+ if (val < 1 || val > groups) {
1000
+ return 0;
1001
+ }
1002
+ if (e->cs[val] >= 0) {
1003
+ ps_grow_add(g, e->text + e->cs[val], e->ce[val] - e->cs[val]);
1004
+ }
1005
+ continue;
1006
+ }
1007
+ return 0;
1008
+ }
1009
+ return 1;
1010
+ }
1011
+
1012
+ void ps_re_sub(int64_t pn, char *pat, int64_t rn, char *repl, int64_t tn, char *text, PsBuf *out) {
1013
+ Comp comp;
1014
+ memset(&comp, 0, sizeof comp);
1015
+ comp.p = pat;
1016
+ comp.n = pn;
1017
+ compile_or_raise(&comp);
1018
+ Eng eng;
1019
+ eng_init(&eng, &comp, text, tn);
1020
+ PsGrow g;
1021
+ ps_grow_init(&g);
1022
+ int64_t pos = 0;
1023
+ while (pos <= tn) {
1024
+ int64_t a = 0;
1025
+ int64_t b = 0;
1026
+ if (!eng_search(&eng, pos, &a, &b)) {
1027
+ ps_grow_add(&g, text + pos, tn - pos);
1028
+ break;
1029
+ }
1030
+ ps_grow_add(&g, text + pos, a - pos);
1031
+ if (!repl_expand(&eng, repl, rn, comp.groups, &g)) {
1032
+ free(g.data);
1033
+ eng_free(&eng);
1034
+ ps_raise_cstr(PS_VALUE, "bad escape in replacement");
1035
+ }
1036
+ if (b > a) {
1037
+ pos = b;
1038
+ } else if (b == tn) {
1039
+ break;
1040
+ } else {
1041
+ ps_grow_add(&g, text + b, 1);
1042
+ pos = b + 1;
1043
+ }
1044
+ }
1045
+ eng_free(&eng);
1046
+ ps_grow_finish(&g, out);
1047
+ }
1048
+
1049
+ PsSeq *ps_re_split(int64_t pn, char *pat, int64_t tn, char *text) {
1050
+ Comp comp;
1051
+ memset(&comp, 0, sizeof comp);
1052
+ comp.p = pat;
1053
+ comp.n = pn;
1054
+ compile_or_raise(&comp);
1055
+ Eng eng;
1056
+ eng_init(&eng, &comp, text, tn);
1057
+ PsSeq *seq = ps_seq_new(16, 0);
1058
+ int64_t last = 0;
1059
+ int64_t pos = 0;
1060
+ while (pos <= tn) {
1061
+ int64_t a = 0;
1062
+ int64_t b = 0;
1063
+ if (!eng_search(&eng, pos, &a, &b)) {
1064
+ push_piece(seq, text, last, tn);
1065
+ break;
1066
+ }
1067
+ push_piece(seq, text, last, a);
1068
+ for (int g = 1; g <= comp.groups; g++) {
1069
+ if (eng.cs[g] < 0) {
1070
+ push_piece(seq, text, 0, 0);
1071
+ } else {
1072
+ push_piece(seq, text, eng.cs[g], eng.ce[g]);
1073
+ }
1074
+ }
1075
+ if (b > a) {
1076
+ last = b;
1077
+ pos = b;
1078
+ } else if (b == tn) {
1079
+ push_piece(seq, text, last, tn);
1080
+ break;
1081
+ } else {
1082
+ last = b;
1083
+ pos = b + 1;
1084
+ }
1085
+ }
1086
+ eng_free(&eng);
1087
+ return seq;
1088
+ }
1089
+
1090
+ void ps_re_escape(int64_t n, char *p, PsBuf *out) {
1091
+ PsGrow g;
1092
+ ps_grow_init(&g);
1093
+ for (int64_t i = 0; i < n; i++) {
1094
+ unsigned char c = (unsigned char)p[i];
1095
+ int plain = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_';
1096
+ if (!plain) {
1097
+ ps_grow_byte(&g, '\\');
1098
+ }
1099
+ ps_grow_byte(&g, c);
1100
+ }
1101
+ ps_grow_finish(&g, out);
1102
+ }