xbintsc 0.3.15 → 0.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/main.js +4 -4
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/state.js +8 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +8 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/graph.d.ts +8 -0
- package/dist/src/driver/bundler/graph.js +85 -0
- package/dist/src/driver/bundler/graph.js.map +1 -0
- package/dist/src/driver/bundler/merge.d.ts +11 -0
- package/dist/src/driver/bundler/merge.js +288 -0
- package/dist/src/driver/bundler/merge.js.map +1 -0
- package/dist/src/driver/bundler/resolve.d.ts +12 -0
- package/dist/src/driver/bundler/resolve.js +246 -0
- package/dist/src/driver/bundler/resolve.js.map +1 -0
- package/dist/src/driver/bundler/symbols.d.ts +15 -0
- package/dist/src/driver/bundler/symbols.js +51 -0
- package/dist/src/driver/bundler/symbols.js.map +1 -0
- package/dist/src/driver/bundler/types.d.ts +36 -0
- package/dist/src/driver/bundler/types.js +5 -0
- package/dist/src/driver/bundler/types.js.map +1 -0
- package/dist/src/driver/modules.d.ts +9 -16
- package/dist/src/driver/modules.js +8 -644
- package/dist/src/driver/modules.js.map +1 -1
- package/dist/src/extensions/catalog.js +2 -1
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/index.d.ts +24 -0
- package/dist/src/extensions/gui/index.js +101 -0
- package/dist/src/extensions/gui/index.js.map +1 -0
- package/dist/tests/e2e/compile-basics.test.d.ts +4 -0
- package/dist/tests/e2e/compile-basics.test.js +134 -0
- package/dist/tests/e2e/compile-basics.test.js.map +1 -0
- package/dist/tests/e2e/compile-builtins.test.d.ts +4 -0
- package/dist/tests/e2e/compile-builtins.test.js +191 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -0
- package/dist/tests/e2e/compile-control-flow.test.d.ts +4 -0
- package/dist/tests/e2e/compile-control-flow.test.js +190 -0
- package/dist/tests/e2e/compile-control-flow.test.js.map +1 -0
- package/dist/tests/e2e/compile-modules.test.d.ts +4 -0
- package/dist/tests/e2e/compile-modules.test.js +48 -0
- package/dist/tests/e2e/compile-modules.test.js.map +1 -0
- package/dist/tests/e2e/compile-objects-classes.test.d.ts +4 -0
- package/dist/tests/e2e/compile-objects-classes.test.js +362 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -0
- package/dist/tests/e2e/differential-helpers.d.ts +12 -0
- package/dist/tests/e2e/differential-helpers.js +16 -0
- package/dist/tests/e2e/differential-helpers.js.map +1 -0
- package/dist/tests/e2e/differential-language.test.d.ts +4 -0
- package/dist/tests/e2e/{differential.test.js → differential-language.test.js} +5 -287
- package/dist/tests/e2e/differential-language.test.js.map +1 -0
- package/dist/tests/e2e/differential-symbols.test.d.ts +4 -0
- package/dist/tests/e2e/differential-symbols.test.js +92 -0
- package/dist/tests/e2e/differential-symbols.test.js.map +1 -0
- package/dist/tests/e2e/differential-values.test.d.ts +4 -0
- package/dist/tests/e2e/differential-values.test.js +197 -0
- package/dist/tests/e2e/differential-values.test.js.map +1 -0
- package/dist/tests/e2e/gui.test.d.ts +12 -0
- package/dist/tests/e2e/gui.test.js +493 -0
- package/dist/tests/e2e/gui.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js +97 -0
- package/dist/tests/e2e/runtime-coverage-buffer.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js +149 -0
- package/dist/tests/e2e/runtime-coverage-globals.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js +177 -0
- package/dist/tests/e2e/runtime-coverage-node-modules.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js +161 -0
- package/dist/tests/e2e/runtime-coverage-streams.test.js.map +1 -0
- package/dist/tests/e2e/runtime-coverage-system.test.d.ts +4 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js +91 -0
- package/dist/tests/e2e/runtime-coverage-system.test.js.map +1 -0
- package/dist/tests/e2e/timers.test.d.ts +7 -0
- package/dist/tests/e2e/timers.test.js +63 -0
- package/dist/tests/e2e/timers.test.js.map +1 -0
- package/package.json +2 -1
- package/runtime/ext_gui/css.cpp +743 -0
- package/runtime/ext_gui/css.h +98 -0
- package/runtime/ext_gui/document.cpp +264 -0
- package/runtime/ext_gui/document.h +89 -0
- package/runtime/ext_gui/dom.cpp +472 -0
- package/runtime/ext_gui/dom.h +71 -0
- package/runtime/ext_gui/gui.cpp +457 -0
- package/runtime/ext_gui/gui_engine.h +81 -0
- package/runtime/ext_gui/image.cpp +125 -0
- package/runtime/ext_gui/image.h +42 -0
- package/runtime/ext_gui/layout.cpp +748 -0
- package/runtime/ext_gui/layout.h +93 -0
- package/runtime/ext_gui/paint.cpp +137 -0
- package/runtime/ext_gui/paint.h +75 -0
- package/runtime/ext_gui/renderer.cpp +959 -0
- package/runtime/ext_gui/renderer.h +68 -0
- package/runtime/ext_gui/stb_image.h +7988 -0
- package/runtime/ext_gui/style.cpp +771 -0
- package/runtime/ext_gui/style.h +117 -0
- package/runtime/ext_gui/text.cpp +378 -0
- package/runtime/ext_gui/text.h +78 -0
- package/runtime/ext_gui/window.cpp +405 -0
- package/runtime/ext_node/fs/fs_common.h +13 -527
- package/runtime/ext_node/fs/parts/buffer-bridge.inc +6 -0
- package/runtime/ext_node/fs/parts/builtins.inc +69 -0
- package/runtime/ext_node/fs/parts/dir.inc +47 -0
- package/runtime/ext_node/fs/parts/encoding.inc +186 -0
- package/runtime/ext_node/fs/parts/errors.inc +66 -0
- package/runtime/ext_node/fs/parts/flags.inc +39 -0
- package/runtime/ext_node/fs/parts/platform.inc +86 -0
- package/runtime/ext_node/fs/parts/promisify.inc +15 -0
- package/runtime/ext_node/fs/parts/time.inc +9 -0
- package/runtime/rt.h +33 -0
- package/runtime/xt_builtins.c +4 -0
- package/runtime/xt_containers/access.inc +168 -0
- package/runtime/xt_containers/arrays.inc +108 -0
- package/runtime/xt_containers/boxes.inc +11 -0
- package/runtime/xt_containers/objects.inc +326 -0
- package/runtime/xt_containers.c +8 -618
- package/runtime/xt_io/base64.inc +87 -0
- package/runtime/xt_io/console.inc +119 -0
- package/runtime/xt_io/exception.inc +142 -0
- package/runtime/xt_io/inspect.inc +212 -0
- package/runtime/xt_io.c +8 -553
- package/runtime/xt_loop.c +262 -24
- package/runtime/xt_regex/api.inc +58 -0
- package/runtime/xt_regex/helpers.inc +68 -0
- package/runtime/xt_regex/matcher.inc +248 -0
- package/runtime/xt_regex/parser.inc +236 -0
- package/runtime/xt_regex/types.inc +58 -0
- package/runtime/xt_regex.h +9 -672
- package/runtime/xt_values/arithmetic.inc +150 -0
- package/runtime/xt_values/comparison.inc +112 -0
- package/runtime/xt_values/constructors.inc +41 -0
- package/runtime/xt_values/conversions.inc +115 -0
- package/runtime/xt_values/number-format.inc +180 -0
- package/runtime/xt_values/strings.inc +22 -0
- package/runtime/xt_values.c +10 -626
- package/scripts/build-gui.ts +317 -0
- package/src/cli/main.ts +4 -3
- package/src/codegen/generator/state.ts +8 -0
- package/src/codegen/generator/tables.ts +8 -0
- package/src/driver/bundler/graph.ts +95 -0
- package/src/driver/bundler/merge.ts +312 -0
- package/src/driver/bundler/resolve.ts +240 -0
- package/src/driver/bundler/symbols.ts +55 -0
- package/src/driver/bundler/types.ts +37 -0
- package/src/driver/modules.ts +9 -693
- package/src/extensions/catalog.ts +2 -1
- package/src/extensions/gui/index.ts +107 -0
- package/dist/tests/e2e/compile.test.d.ts +0 -8
- package/dist/tests/e2e/compile.test.js +0 -893
- package/dist/tests/e2e/compile.test.js.map +0 -1
- package/dist/tests/e2e/differential.test.d.ts +0 -7
- package/dist/tests/e2e/differential.test.js.map +0 -1
- package/dist/tests/e2e/runtime-coverage.test.d.ts +0 -11
- package/dist/tests/e2e/runtime-coverage.test.js +0 -646
- package/dist/tests/e2e/runtime-coverage.test.js.map +0 -1
package/runtime/xt_regex.h
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
* chain of stack frames so abandoned search paths are undone automatically.
|
|
15
15
|
* Patterns are tiny, so this is fast enough and keeps the runtime free of an
|
|
16
16
|
* external dependency.
|
|
17
|
+
*
|
|
18
|
+
* The implementation is grouped by functional area under `xt_regex/` and
|
|
19
|
+
* `#include`d here as a single translation unit, so the `static` helpers stay
|
|
20
|
+
* private while each file stays focused on one area.
|
|
17
21
|
*/
|
|
18
22
|
|
|
19
23
|
#ifndef XT_REGEX_H
|
|
@@ -23,677 +27,10 @@
|
|
|
23
27
|
#include <stdlib.h>
|
|
24
28
|
#include <string.h>
|
|
25
29
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
int rm_so;
|
|
32
|
-
int rm_eo;
|
|
33
|
-
} regmatch_t;
|
|
34
|
-
|
|
35
|
-
/* Node kinds. */
|
|
36
|
-
enum {
|
|
37
|
-
XT_RE_CHAR = 0,
|
|
38
|
-
XT_RE_ANY,
|
|
39
|
-
XT_RE_CLASS,
|
|
40
|
-
XT_RE_BOL,
|
|
41
|
-
XT_RE_EOL,
|
|
42
|
-
XT_RE_GROUP
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/* Quantifiers. */
|
|
46
|
-
enum {
|
|
47
|
-
XT_RE_Q_NONE = 0,
|
|
48
|
-
XT_RE_Q_STAR,
|
|
49
|
-
XT_RE_Q_PLUS,
|
|
50
|
-
XT_RE_Q_QUEST
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
typedef struct xt_re_alt xt_re_alt;
|
|
54
|
-
|
|
55
|
-
typedef struct {
|
|
56
|
-
int type;
|
|
57
|
-
unsigned char ch;
|
|
58
|
-
unsigned char *classbits; /* 256 bits == 32 bytes, for XT_RE_CLASS */
|
|
59
|
-
xt_re_alt *group; /* for XT_RE_GROUP */
|
|
60
|
-
int groupIndex; /* 1-based capture number, for XT_RE_GROUP */
|
|
61
|
-
} xt_re_node;
|
|
62
|
-
|
|
63
|
-
typedef struct {
|
|
64
|
-
xt_re_node *node;
|
|
65
|
-
int quant;
|
|
66
|
-
} xt_re_piece;
|
|
67
|
-
|
|
68
|
-
typedef struct {
|
|
69
|
-
xt_re_piece *pieces;
|
|
70
|
-
int count;
|
|
71
|
-
int capacity;
|
|
72
|
-
} xt_re_concat;
|
|
73
|
-
|
|
74
|
-
struct xt_re_alt {
|
|
75
|
-
xt_re_concat *branches;
|
|
76
|
-
int count;
|
|
77
|
-
int capacity;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
typedef struct {
|
|
81
|
-
xt_re_alt *root;
|
|
82
|
-
int icase;
|
|
83
|
-
} regex_t;
|
|
84
|
-
|
|
85
|
-
/* -- small helpers -------------------------------------------------------- */
|
|
86
|
-
|
|
87
|
-
static void xt_re_set_bit(unsigned char *bits, unsigned char c) {
|
|
88
|
-
bits[c >> 3] |= (unsigned char)(1u << (c & 7));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
static int xt_re_bit_test(const unsigned char *bits, unsigned char c) {
|
|
92
|
-
return (bits[c >> 3] >> (c & 7)) & 1;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
static unsigned char xt_re_lower(unsigned char c) {
|
|
96
|
-
if (c >= 'A' && c <= 'Z') return (unsigned char)(c - 'A' + 'a');
|
|
97
|
-
return c;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static void xt_re_add_range(unsigned char *bits, unsigned char lo, unsigned char hi) {
|
|
101
|
-
unsigned int c;
|
|
102
|
-
if (hi < lo) {
|
|
103
|
-
unsigned char t = lo;
|
|
104
|
-
lo = hi;
|
|
105
|
-
hi = t;
|
|
106
|
-
}
|
|
107
|
-
for (c = lo; c <= hi; c++) xt_re_set_bit(bits, (unsigned char)c);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* Adds a predefined class such as \d or \w. Returns 1 when handled. */
|
|
111
|
-
static int xt_re_add_predefined(unsigned char *bits, char e) {
|
|
112
|
-
int c;
|
|
113
|
-
switch (e) {
|
|
114
|
-
case 'd':
|
|
115
|
-
xt_re_add_range(bits, '0', '9');
|
|
116
|
-
return 1;
|
|
117
|
-
case 'D':
|
|
118
|
-
for (c = 0; c < 256; c++)
|
|
119
|
-
if (!(c >= '0' && c <= '9')) xt_re_set_bit(bits, (unsigned char)c);
|
|
120
|
-
return 1;
|
|
121
|
-
case 'w':
|
|
122
|
-
xt_re_add_range(bits, 'a', 'z');
|
|
123
|
-
xt_re_add_range(bits, 'A', 'Z');
|
|
124
|
-
xt_re_add_range(bits, '0', '9');
|
|
125
|
-
xt_re_set_bit(bits, '_');
|
|
126
|
-
return 1;
|
|
127
|
-
case 'W':
|
|
128
|
-
for (c = 0; c < 256; c++) {
|
|
129
|
-
int is_word = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
130
|
-
(c >= '0' && c <= '9') || c == '_';
|
|
131
|
-
if (!is_word) xt_re_set_bit(bits, (unsigned char)c);
|
|
132
|
-
}
|
|
133
|
-
return 1;
|
|
134
|
-
case 's':
|
|
135
|
-
xt_re_set_bit(bits, ' ');
|
|
136
|
-
xt_re_set_bit(bits, '\t');
|
|
137
|
-
xt_re_set_bit(bits, '\n');
|
|
138
|
-
xt_re_set_bit(bits, '\r');
|
|
139
|
-
xt_re_set_bit(bits, '\f');
|
|
140
|
-
xt_re_set_bit(bits, '\v');
|
|
141
|
-
return 1;
|
|
142
|
-
case 'S':
|
|
143
|
-
for (c = 0; c < 256; c++) {
|
|
144
|
-
int is_space = c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
|
|
145
|
-
c == '\f' || c == '\v';
|
|
146
|
-
if (!is_space) xt_re_set_bit(bits, (unsigned char)c);
|
|
147
|
-
}
|
|
148
|
-
return 1;
|
|
149
|
-
default:
|
|
150
|
-
return 0;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/* -- parser --------------------------------------------------------------- */
|
|
155
|
-
|
|
156
|
-
typedef struct {
|
|
157
|
-
const char *s;
|
|
158
|
-
size_t i;
|
|
159
|
-
int error;
|
|
160
|
-
int groupCount;
|
|
161
|
-
} xt_re_parser;
|
|
162
|
-
|
|
163
|
-
static void xt_re_free_alt(xt_re_alt *alt);
|
|
164
|
-
|
|
165
|
-
static xt_re_node *xt_re_new_node(int type) {
|
|
166
|
-
xt_re_node *n = (xt_re_node *)calloc(1, sizeof(xt_re_node));
|
|
167
|
-
if (n) n->type = type;
|
|
168
|
-
return n;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
static xt_re_node *xt_re_new_char(unsigned char c) {
|
|
172
|
-
xt_re_node *n = xt_re_new_node(XT_RE_CHAR);
|
|
173
|
-
if (n) n->ch = c;
|
|
174
|
-
return n;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
static xt_re_node *xt_re_new_class(const unsigned char *bits) {
|
|
178
|
-
xt_re_node *n = xt_re_new_node(XT_RE_CLASS);
|
|
179
|
-
if (!n) return NULL;
|
|
180
|
-
n->classbits = (unsigned char *)malloc(32);
|
|
181
|
-
if (!n->classbits) {
|
|
182
|
-
free(n);
|
|
183
|
-
return NULL;
|
|
184
|
-
}
|
|
185
|
-
memcpy(n->classbits, bits, 32);
|
|
186
|
-
return n;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
static void xt_re_push_piece(xt_re_concat *c, xt_re_node *node, int quant) {
|
|
190
|
-
if (c->count == c->capacity) {
|
|
191
|
-
int next = c->capacity ? c->capacity * 2 : 4;
|
|
192
|
-
xt_re_piece *grown = (xt_re_piece *)realloc(c->pieces, (size_t)next * sizeof(xt_re_piece));
|
|
193
|
-
if (!grown) return;
|
|
194
|
-
c->pieces = grown;
|
|
195
|
-
c->capacity = next;
|
|
196
|
-
}
|
|
197
|
-
c->pieces[c->count].node = node;
|
|
198
|
-
c->pieces[c->count].quant = quant;
|
|
199
|
-
c->count++;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
static void xt_re_push_branch(xt_re_alt *alt, xt_re_concat c) {
|
|
203
|
-
if (alt->count == alt->capacity) {
|
|
204
|
-
int next = alt->capacity ? alt->capacity * 2 : 4;
|
|
205
|
-
xt_re_concat *grown = (xt_re_concat *)realloc(alt->branches, (size_t)next * sizeof(xt_re_concat));
|
|
206
|
-
if (!grown) return;
|
|
207
|
-
alt->branches = grown;
|
|
208
|
-
alt->capacity = next;
|
|
209
|
-
}
|
|
210
|
-
alt->branches[alt->count++] = c;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
static xt_re_alt *xt_re_parse_alt(xt_re_parser *p);
|
|
214
|
-
|
|
215
|
-
static xt_re_node *xt_re_parse_escape(xt_re_parser *p) {
|
|
216
|
-
char c;
|
|
217
|
-
p->i++; /* consume backslash */
|
|
218
|
-
c = p->s[p->i];
|
|
219
|
-
if (!c) {
|
|
220
|
-
p->error = 1;
|
|
221
|
-
return NULL;
|
|
222
|
-
}
|
|
223
|
-
p->i++;
|
|
224
|
-
if (c == 'd' || c == 'D' || c == 'w' || c == 'W' || c == 's' || c == 'S') {
|
|
225
|
-
unsigned char bits[32];
|
|
226
|
-
xt_re_node *n;
|
|
227
|
-
memset(bits, 0, sizeof(bits));
|
|
228
|
-
xt_re_add_predefined(bits, c);
|
|
229
|
-
n = xt_re_new_class(bits);
|
|
230
|
-
if (!n) p->error = 1;
|
|
231
|
-
return n;
|
|
232
|
-
}
|
|
233
|
-
if (c == 'n') return xt_re_new_char('\n');
|
|
234
|
-
if (c == 't') return xt_re_new_char('\t');
|
|
235
|
-
if (c == 'r') return xt_re_new_char('\r');
|
|
236
|
-
if (c == 'f') return xt_re_new_char('\f');
|
|
237
|
-
if (c == 'v') return xt_re_new_char('\v');
|
|
238
|
-
if (c == '0') return xt_re_new_char('\0');
|
|
239
|
-
return xt_re_new_char((unsigned char)c);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
static xt_re_node *xt_re_parse_class(xt_re_parser *p) {
|
|
243
|
-
unsigned char bits[32];
|
|
244
|
-
int negate = 0;
|
|
245
|
-
int first = 1;
|
|
246
|
-
xt_re_node *n;
|
|
247
|
-
|
|
248
|
-
memset(bits, 0, sizeof(bits));
|
|
249
|
-
p->i++; /* consume '[' */
|
|
250
|
-
if (p->s[p->i] == '^') {
|
|
251
|
-
negate = 1;
|
|
252
|
-
p->i++;
|
|
253
|
-
}
|
|
254
|
-
while (p->s[p->i] && (p->s[p->i] != ']' || first)) {
|
|
255
|
-
unsigned char lo;
|
|
256
|
-
first = 0;
|
|
257
|
-
if (p->s[p->i] == '\\' && p->s[p->i + 1]) {
|
|
258
|
-
char e;
|
|
259
|
-
p->i++;
|
|
260
|
-
e = p->s[p->i++];
|
|
261
|
-
if (xt_re_add_predefined(bits, e)) continue;
|
|
262
|
-
if (e == 'n') lo = '\n';
|
|
263
|
-
else if (e == 't') lo = '\t';
|
|
264
|
-
else if (e == 'r') lo = '\r';
|
|
265
|
-
else if (e == 'f') lo = '\f';
|
|
266
|
-
else if (e == 'v') lo = '\v';
|
|
267
|
-
else lo = (unsigned char)e;
|
|
268
|
-
} else {
|
|
269
|
-
lo = (unsigned char)p->s[p->i++];
|
|
270
|
-
}
|
|
271
|
-
if (p->s[p->i] == '-' && p->s[p->i + 1] && p->s[p->i + 1] != ']') {
|
|
272
|
-
unsigned char hi;
|
|
273
|
-
p->i++; /* consume '-' */
|
|
274
|
-
hi = (unsigned char)p->s[p->i++];
|
|
275
|
-
xt_re_add_range(bits, lo, hi);
|
|
276
|
-
} else {
|
|
277
|
-
xt_re_set_bit(bits, lo);
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (p->s[p->i] != ']') {
|
|
281
|
-
p->error = 1;
|
|
282
|
-
return NULL;
|
|
283
|
-
}
|
|
284
|
-
p->i++;
|
|
285
|
-
if (negate) {
|
|
286
|
-
int c;
|
|
287
|
-
for (c = 0; c < 32; c++) bits[c] = (unsigned char)~bits[c];
|
|
288
|
-
}
|
|
289
|
-
n = xt_re_new_class(bits);
|
|
290
|
-
if (!n) p->error = 1;
|
|
291
|
-
return n;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
static xt_re_node *xt_re_parse_atom(xt_re_parser *p) {
|
|
295
|
-
char c = p->s[p->i];
|
|
296
|
-
if (c == '(') {
|
|
297
|
-
xt_re_node *n;
|
|
298
|
-
xt_re_alt *group;
|
|
299
|
-
int index;
|
|
300
|
-
p->i++;
|
|
301
|
-
/* Number the group as soon as its '(' is seen so nested groups keep
|
|
302
|
-
* POSIX/JavaScript numbering (opening-paren order). */
|
|
303
|
-
index = ++p->groupCount;
|
|
304
|
-
group = xt_re_parse_alt(p);
|
|
305
|
-
if (p->error) return NULL;
|
|
306
|
-
if (p->s[p->i] != ')') {
|
|
307
|
-
p->error = 1;
|
|
308
|
-
xt_re_free_alt(group);
|
|
309
|
-
return NULL;
|
|
310
|
-
}
|
|
311
|
-
p->i++;
|
|
312
|
-
n = xt_re_new_node(XT_RE_GROUP);
|
|
313
|
-
if (!n) {
|
|
314
|
-
p->error = 1;
|
|
315
|
-
return NULL;
|
|
316
|
-
}
|
|
317
|
-
n->group = group;
|
|
318
|
-
n->groupIndex = index;
|
|
319
|
-
return n;
|
|
320
|
-
}
|
|
321
|
-
if (c == '[') return xt_re_parse_class(p);
|
|
322
|
-
if (c == '.') {
|
|
323
|
-
p->i++;
|
|
324
|
-
return xt_re_new_node(XT_RE_ANY);
|
|
325
|
-
}
|
|
326
|
-
if (c == '^') {
|
|
327
|
-
p->i++;
|
|
328
|
-
return xt_re_new_node(XT_RE_BOL);
|
|
329
|
-
}
|
|
330
|
-
if (c == '$') {
|
|
331
|
-
p->i++;
|
|
332
|
-
return xt_re_new_node(XT_RE_EOL);
|
|
333
|
-
}
|
|
334
|
-
if (c == '\\') return xt_re_parse_escape(p);
|
|
335
|
-
if (c == '\0') {
|
|
336
|
-
p->error = 1;
|
|
337
|
-
return NULL;
|
|
338
|
-
}
|
|
339
|
-
p->i++;
|
|
340
|
-
return xt_re_new_char((unsigned char)c);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
static void xt_re_parse_concat(xt_re_parser *p, xt_re_concat *out) {
|
|
344
|
-
while (p->s[p->i] && p->s[p->i] != '|' && p->s[p->i] != ')') {
|
|
345
|
-
xt_re_node *node = xt_re_parse_atom(p);
|
|
346
|
-
int quant = XT_RE_Q_NONE;
|
|
347
|
-
if (p->error || !node) {
|
|
348
|
-
p->error = 1;
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
if (p->s[p->i] == '*') {
|
|
352
|
-
quant = XT_RE_Q_STAR;
|
|
353
|
-
p->i++;
|
|
354
|
-
} else if (p->s[p->i] == '+') {
|
|
355
|
-
quant = XT_RE_Q_PLUS;
|
|
356
|
-
p->i++;
|
|
357
|
-
} else if (p->s[p->i] == '?') {
|
|
358
|
-
quant = XT_RE_Q_QUEST;
|
|
359
|
-
p->i++;
|
|
360
|
-
}
|
|
361
|
-
xt_re_push_piece(out, node, quant);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
static xt_re_alt *xt_re_parse_alt(xt_re_parser *p) {
|
|
366
|
-
xt_re_alt *alt = (xt_re_alt *)calloc(1, sizeof(xt_re_alt));
|
|
367
|
-
if (!alt) {
|
|
368
|
-
p->error = 1;
|
|
369
|
-
return NULL;
|
|
370
|
-
}
|
|
371
|
-
for (;;) {
|
|
372
|
-
xt_re_concat concat;
|
|
373
|
-
memset(&concat, 0, sizeof(concat));
|
|
374
|
-
xt_re_parse_concat(p, &concat);
|
|
375
|
-
if (p->error) {
|
|
376
|
-
free(concat.pieces);
|
|
377
|
-
free(alt->branches);
|
|
378
|
-
free(alt);
|
|
379
|
-
return NULL;
|
|
380
|
-
}
|
|
381
|
-
xt_re_push_branch(alt, concat);
|
|
382
|
-
if (p->s[p->i] == '|') {
|
|
383
|
-
p->i++;
|
|
384
|
-
continue;
|
|
385
|
-
}
|
|
386
|
-
break;
|
|
387
|
-
}
|
|
388
|
-
return alt;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/* -- matching ------------------------------------------------------------- */
|
|
392
|
-
|
|
393
|
-
typedef struct {
|
|
394
|
-
const char *text;
|
|
395
|
-
size_t len;
|
|
396
|
-
int icase;
|
|
397
|
-
} xt_re_input;
|
|
398
|
-
|
|
399
|
-
/* One capture on the immutable chain of the current search path. `parent`
|
|
400
|
-
* points to the captures that were live when the group was entered, so an
|
|
401
|
-
* abandoned backtrack simply drops the frame instead of restoring it. */
|
|
402
|
-
typedef struct xt_re_cap {
|
|
403
|
-
const struct xt_re_cap *parent;
|
|
404
|
-
int index; /* 1-based capture group number */
|
|
405
|
-
int start;
|
|
406
|
-
int end;
|
|
407
|
-
} xt_re_cap;
|
|
408
|
-
|
|
409
|
-
typedef int (*xt_re_cont)(void *ctx, size_t pos, const xt_re_cap *caps);
|
|
410
|
-
|
|
411
|
-
static void xt_re_free_alt(xt_re_alt *alt);
|
|
412
|
-
|
|
413
|
-
static void xt_re_free_node(xt_re_node *n) {
|
|
414
|
-
if (!n) return;
|
|
415
|
-
if (n->type == XT_RE_GROUP) xt_re_free_alt(n->group);
|
|
416
|
-
free(n->classbits);
|
|
417
|
-
free(n);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
static void xt_re_free_alt(xt_re_alt *alt) {
|
|
421
|
-
int i;
|
|
422
|
-
if (!alt) return;
|
|
423
|
-
for (i = 0; i < alt->count; i++) {
|
|
424
|
-
int j;
|
|
425
|
-
for (j = 0; j < alt->branches[i].count; j++)
|
|
426
|
-
xt_re_free_node(alt->branches[i].pieces[j].node);
|
|
427
|
-
free(alt->branches[i].pieces);
|
|
428
|
-
}
|
|
429
|
-
free(alt->branches);
|
|
430
|
-
free(alt);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
static int xt_re_char_eq(const xt_re_input *in, unsigned char a, unsigned char b) {
|
|
434
|
-
if (a == b) return 1;
|
|
435
|
-
if (in->icase && xt_re_lower(a) == xt_re_lower(b)) return 1;
|
|
436
|
-
return 0;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
static int xt_re_class_match(const unsigned char *bits, unsigned char c, int icase) {
|
|
440
|
-
if (xt_re_bit_test(bits, c)) return 1;
|
|
441
|
-
if (icase) {
|
|
442
|
-
unsigned char l = xt_re_lower(c);
|
|
443
|
-
if (xt_re_bit_test(bits, l)) return 1;
|
|
444
|
-
if (l >= 'a' && l <= 'z' && xt_re_bit_test(bits, (unsigned char)(l - 'a' + 'A'))) return 1;
|
|
445
|
-
}
|
|
446
|
-
return 0;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
static int xt_re_match_alt(xt_re_alt *alt, const xt_re_input *in, size_t pos,
|
|
450
|
-
xt_re_cont cont, void *ctx, const xt_re_cap *caps);
|
|
451
|
-
|
|
452
|
-
/* Resumes the outer continuation once a group's body has matched, recording
|
|
453
|
-
* where the group ended on the frame it pushed. */
|
|
454
|
-
typedef struct {
|
|
455
|
-
xt_re_cap *frame;
|
|
456
|
-
xt_re_cont cont;
|
|
457
|
-
void *ctx;
|
|
458
|
-
} xt_re_group_state;
|
|
459
|
-
|
|
460
|
-
static int xt_re_group_next(void *v, size_t pos, const xt_re_cap *caps) {
|
|
461
|
-
xt_re_group_state *s = (xt_re_group_state *)v;
|
|
462
|
-
/* `caps` already heads the chain that includes this group's own frame (and
|
|
463
|
-
* any groups nested inside it), so forward it as-is. */
|
|
464
|
-
s->frame->end = (int)pos;
|
|
465
|
-
return s->cont(s->ctx, pos, caps);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
static int xt_re_match_atom(xt_re_node *node, const xt_re_input *in, size_t pos,
|
|
469
|
-
xt_re_cont cont, void *ctx, const xt_re_cap *caps) {
|
|
470
|
-
switch (node->type) {
|
|
471
|
-
case XT_RE_CHAR:
|
|
472
|
-
if (pos < in->len && xt_re_char_eq(in, (unsigned char)in->text[pos], node->ch))
|
|
473
|
-
return cont(ctx, pos + 1, caps);
|
|
474
|
-
return 0;
|
|
475
|
-
case XT_RE_ANY:
|
|
476
|
-
if (pos < in->len && in->text[pos] != '\n') return cont(ctx, pos + 1, caps);
|
|
477
|
-
return 0;
|
|
478
|
-
case XT_RE_CLASS:
|
|
479
|
-
if (pos < in->len && xt_re_class_match(node->classbits, (unsigned char)in->text[pos], in->icase))
|
|
480
|
-
return cont(ctx, pos + 1, caps);
|
|
481
|
-
return 0;
|
|
482
|
-
case XT_RE_BOL:
|
|
483
|
-
return pos == 0 ? cont(ctx, pos, caps) : 0;
|
|
484
|
-
case XT_RE_EOL:
|
|
485
|
-
return pos == in->len ? cont(ctx, pos, caps) : 0;
|
|
486
|
-
case XT_RE_GROUP: {
|
|
487
|
-
xt_re_cap frame;
|
|
488
|
-
xt_re_group_state state;
|
|
489
|
-
frame.parent = caps;
|
|
490
|
-
frame.index = node->groupIndex;
|
|
491
|
-
frame.start = (int)pos;
|
|
492
|
-
frame.end = -1;
|
|
493
|
-
state.frame = &frame;
|
|
494
|
-
state.cont = cont;
|
|
495
|
-
state.ctx = ctx;
|
|
496
|
-
return xt_re_match_alt(node->group, in, pos, xt_re_group_next, &state, &frame);
|
|
497
|
-
}
|
|
498
|
-
default:
|
|
499
|
-
return 0;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
typedef struct {
|
|
504
|
-
xt_re_node *atom;
|
|
505
|
-
const xt_re_input *in;
|
|
506
|
-
int min;
|
|
507
|
-
int max; /* -1 == unbounded */
|
|
508
|
-
xt_re_cont cont;
|
|
509
|
-
void *ctx;
|
|
510
|
-
} xt_re_repeat;
|
|
511
|
-
|
|
512
|
-
typedef struct {
|
|
513
|
-
xt_re_repeat *rep;
|
|
514
|
-
size_t pos;
|
|
515
|
-
int count;
|
|
516
|
-
} xt_re_repeat_step;
|
|
517
|
-
|
|
518
|
-
static int xt_re_repeat_try(xt_re_repeat *rep, size_t pos, int count, const xt_re_cap *caps);
|
|
519
|
-
|
|
520
|
-
static int xt_re_repeat_next(void *v, size_t newpos, const xt_re_cap *caps) {
|
|
521
|
-
xt_re_repeat_step *s = (xt_re_repeat_step *)v;
|
|
522
|
-
if (newpos == s->pos) return 0; /* no progress -> stop to avoid loops */
|
|
523
|
-
return xt_re_repeat_try(s->rep, newpos, s->count + 1, caps);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
static int xt_re_repeat_try(xt_re_repeat *rep, size_t pos, int count, const xt_re_cap *caps) {
|
|
527
|
-
if (rep->max < 0 || count < rep->max) {
|
|
528
|
-
xt_re_repeat_step step;
|
|
529
|
-
step.rep = rep;
|
|
530
|
-
step.pos = pos;
|
|
531
|
-
step.count = count;
|
|
532
|
-
if (xt_re_match_atom(rep->atom, rep->in, pos, xt_re_repeat_next, &step, caps)) return 1;
|
|
533
|
-
}
|
|
534
|
-
if (count >= rep->min) return rep->cont(rep->ctx, pos, caps);
|
|
535
|
-
return 0;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
static int xt_re_match_piece(xt_re_piece *piece, const xt_re_input *in, size_t pos,
|
|
539
|
-
xt_re_cont cont, void *ctx, const xt_re_cap *caps) {
|
|
540
|
-
xt_re_repeat rep;
|
|
541
|
-
switch (piece->quant) {
|
|
542
|
-
case XT_RE_Q_STAR:
|
|
543
|
-
rep.atom = piece->node;
|
|
544
|
-
rep.in = in;
|
|
545
|
-
rep.min = 0;
|
|
546
|
-
rep.max = -1;
|
|
547
|
-
rep.cont = cont;
|
|
548
|
-
rep.ctx = ctx;
|
|
549
|
-
return xt_re_repeat_try(&rep, pos, 0, caps);
|
|
550
|
-
case XT_RE_Q_PLUS:
|
|
551
|
-
rep.atom = piece->node;
|
|
552
|
-
rep.in = in;
|
|
553
|
-
rep.min = 1;
|
|
554
|
-
rep.max = -1;
|
|
555
|
-
rep.cont = cont;
|
|
556
|
-
rep.ctx = ctx;
|
|
557
|
-
return xt_re_repeat_try(&rep, pos, 0, caps);
|
|
558
|
-
case XT_RE_Q_QUEST:
|
|
559
|
-
rep.atom = piece->node;
|
|
560
|
-
rep.in = in;
|
|
561
|
-
rep.min = 0;
|
|
562
|
-
rep.max = 1;
|
|
563
|
-
rep.cont = cont;
|
|
564
|
-
rep.ctx = ctx;
|
|
565
|
-
return xt_re_repeat_try(&rep, pos, 0, caps);
|
|
566
|
-
default:
|
|
567
|
-
return xt_re_match_atom(piece->node, in, pos, cont, ctx, caps);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
typedef struct {
|
|
572
|
-
xt_re_concat *concat;
|
|
573
|
-
const xt_re_input *in;
|
|
574
|
-
xt_re_cont cont;
|
|
575
|
-
void *ctx;
|
|
576
|
-
} xt_re_concat_state;
|
|
577
|
-
|
|
578
|
-
typedef struct {
|
|
579
|
-
xt_re_concat_state *state;
|
|
580
|
-
int index;
|
|
581
|
-
} xt_re_concat_step;
|
|
582
|
-
|
|
583
|
-
static int xt_re_match_concat(xt_re_concat_state *state, int index, size_t pos, const xt_re_cap *caps);
|
|
584
|
-
|
|
585
|
-
/* The continuation for a concat piece resumes matching at the next piece. */
|
|
586
|
-
static int xt_re_concat_next(void *v, size_t pos, const xt_re_cap *caps) {
|
|
587
|
-
xt_re_concat_step *s = (xt_re_concat_step *)v;
|
|
588
|
-
return xt_re_match_concat(s->state, s->index + 1, pos, caps);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
static int xt_re_match_concat(xt_re_concat_state *state, int index, size_t pos, const xt_re_cap *caps) {
|
|
592
|
-
xt_re_concat_step step;
|
|
593
|
-
if (index >= state->concat->count) return state->cont(state->ctx, pos, caps);
|
|
594
|
-
step.state = state;
|
|
595
|
-
step.index = index;
|
|
596
|
-
return xt_re_match_piece(&state->concat->pieces[index], state->in, pos,
|
|
597
|
-
xt_re_concat_next, &step, caps);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
static int xt_re_match_alt(xt_re_alt *alt, const xt_re_input *in, size_t pos,
|
|
601
|
-
xt_re_cont cont, void *ctx, const xt_re_cap *caps) {
|
|
602
|
-
int i;
|
|
603
|
-
for (i = 0; i < alt->count; i++) {
|
|
604
|
-
xt_re_concat_state state;
|
|
605
|
-
state.concat = &alt->branches[i];
|
|
606
|
-
state.in = in;
|
|
607
|
-
state.cont = cont;
|
|
608
|
-
state.ctx = ctx;
|
|
609
|
-
if (xt_re_match_concat(&state, 0, pos, caps)) return 1;
|
|
610
|
-
}
|
|
611
|
-
return 0;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
typedef struct {
|
|
615
|
-
size_t end;
|
|
616
|
-
regmatch_t *pmatch;
|
|
617
|
-
size_t nmatch;
|
|
618
|
-
} xt_re_match_result;
|
|
619
|
-
|
|
620
|
-
/* Final continuation: records the whole-match end offset and copies every
|
|
621
|
-
* capture on the successful path into `pmatch`. Walking from the head means
|
|
622
|
-
* the most recent frame wins, which is what a quantified group such as
|
|
623
|
-
* `(a)+` should report (its last iteration). */
|
|
624
|
-
static int xt_re_record_match(void *ctx, size_t pos, const xt_re_cap *caps) {
|
|
625
|
-
xt_re_match_result *result = (xt_re_match_result *)ctx;
|
|
626
|
-
const xt_re_cap *cap;
|
|
627
|
-
result->end = pos;
|
|
628
|
-
for (cap = caps; cap; cap = cap->parent) {
|
|
629
|
-
if (cap->index >= 1 && (size_t)cap->index < result->nmatch) {
|
|
630
|
-
regmatch_t *slot = &result->pmatch[cap->index];
|
|
631
|
-
if (slot->rm_so < 0) {
|
|
632
|
-
slot->rm_so = cap->start;
|
|
633
|
-
slot->rm_eo = cap->end;
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
return 1;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/* -- public API ----------------------------------------------------------- */
|
|
641
|
-
|
|
642
|
-
static int regcomp(regex_t *preg, const char *pattern, int cflags) {
|
|
643
|
-
xt_re_parser p;
|
|
644
|
-
xt_re_alt *root;
|
|
645
|
-
if (!preg || !pattern) return 1;
|
|
646
|
-
memset(preg, 0, sizeof(*preg));
|
|
647
|
-
p.s = pattern;
|
|
648
|
-
p.i = 0;
|
|
649
|
-
p.error = 0;
|
|
650
|
-
p.groupCount = 0;
|
|
651
|
-
root = xt_re_parse_alt(&p);
|
|
652
|
-
if (!root || p.error || p.s[p.i] != '\0') {
|
|
653
|
-
if (root) xt_re_free_alt(root);
|
|
654
|
-
return 1;
|
|
655
|
-
}
|
|
656
|
-
preg->root = root;
|
|
657
|
-
preg->icase = (cflags & REG_ICASE) ? 1 : 0;
|
|
658
|
-
return 0;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
static int regexec(const regex_t *preg, const char *string, size_t nmatch,
|
|
662
|
-
regmatch_t pmatch[], int eflags) {
|
|
663
|
-
xt_re_input in;
|
|
664
|
-
size_t start;
|
|
665
|
-
size_t i;
|
|
666
|
-
(void)eflags;
|
|
667
|
-
if (!preg || !preg->root || !string) return 1;
|
|
668
|
-
if (pmatch) {
|
|
669
|
-
for (i = 0; i < nmatch; i++) {
|
|
670
|
-
pmatch[i].rm_so = -1;
|
|
671
|
-
pmatch[i].rm_eo = -1;
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
in.text = string;
|
|
675
|
-
in.len = strlen(string);
|
|
676
|
-
in.icase = preg->icase;
|
|
677
|
-
for (start = 0; start <= in.len; start++) {
|
|
678
|
-
xt_re_match_result result;
|
|
679
|
-
result.end = 0;
|
|
680
|
-
result.pmatch = pmatch;
|
|
681
|
-
result.nmatch = nmatch;
|
|
682
|
-
if (xt_re_match_alt(preg->root, &in, start, xt_re_record_match, &result, NULL)) {
|
|
683
|
-
if (nmatch > 0 && pmatch) {
|
|
684
|
-
pmatch[0].rm_so = (int)start;
|
|
685
|
-
pmatch[0].rm_eo = (int)result.end;
|
|
686
|
-
}
|
|
687
|
-
return 0;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
return 1;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
static void regfree(regex_t *preg) {
|
|
694
|
-
if (!preg) return;
|
|
695
|
-
xt_re_free_alt(preg->root);
|
|
696
|
-
preg->root = NULL;
|
|
697
|
-
}
|
|
30
|
+
#include "xt_regex/types.inc"
|
|
31
|
+
#include "xt_regex/helpers.inc"
|
|
32
|
+
#include "xt_regex/parser.inc"
|
|
33
|
+
#include "xt_regex/matcher.inc"
|
|
34
|
+
#include "xt_regex/api.inc"
|
|
698
35
|
|
|
699
36
|
#endif /* XT_REGEX_H */
|