tree-sitter-sed 0.1.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.
- package/LICENSE +21 -0
- package/README.md +27 -0
- package/common/dsl.js +17 -0
- package/common/grammar.js +1832 -0
- package/common/regex.js +678 -0
- package/common/scanner.h +3142 -0
- package/package.json +35 -0
- package/sed/grammar.js +8 -0
- package/sed/src/grammar.json +11492 -0
- package/sed/src/node-types.json +3882 -0
- package/sed/src/parser.c +57910 -0
- package/sed/src/scanner.c +31 -0
- package/sed/src/tree_sitter/alloc.h +54 -0
- package/sed/src/tree_sitter/array.h +336 -0
- package/sed/src/tree_sitter/parser.h +286 -0
- package/sed-ere/grammar.js +8 -0
- package/sed-ere/src/grammar.json +11311 -0
- package/sed-ere/src/node-types.json +3764 -0
- package/sed-ere/src/parser.c +55874 -0
- package/sed-ere/src/scanner.c +31 -0
- package/sed-ere/src/tree_sitter/alloc.h +54 -0
- package/sed-ere/src/tree_sitter/array.h +336 -0
- package/sed-ere/src/tree_sitter/parser.h +286 -0
- package/tree-sitter.json +42 -0
package/common/scanner.h
ADDED
|
@@ -0,0 +1,3142 @@
|
|
|
1
|
+
#ifndef TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
|
|
2
|
+
#define TREE_SITTER_POSIX_SED_COMMON_SCANNER_H_
|
|
3
|
+
|
|
4
|
+
#ifndef SED_REGEX_EXTENDED
|
|
5
|
+
#error "SED_REGEX_EXTENDED must be defined before including scanner.h"
|
|
6
|
+
#endif
|
|
7
|
+
#include "tree_sitter/alloc.h"
|
|
8
|
+
#include "tree_sitter/parser.h"
|
|
9
|
+
|
|
10
|
+
#include <stdbool.h>
|
|
11
|
+
#include <stdint.h>
|
|
12
|
+
|
|
13
|
+
enum TokenType {
|
|
14
|
+
REGEX_ADDRESS_START,
|
|
15
|
+
ESCAPED_REGEX_ADDRESS_START,
|
|
16
|
+
REGEX_ADDRESS_END,
|
|
17
|
+
SUBSTITUTE_START,
|
|
18
|
+
SUBSTITUTE_MIDDLE,
|
|
19
|
+
SUBSTITUTE_END,
|
|
20
|
+
TRANSLATE_START,
|
|
21
|
+
TRANSLATE_MIDDLE,
|
|
22
|
+
TRANSLATE_END,
|
|
23
|
+
REGEX_LITERAL,
|
|
24
|
+
REGEX_BEGINNING_ANCHOR,
|
|
25
|
+
REGEX_END_ANCHOR,
|
|
26
|
+
REGEX_PERIOD,
|
|
27
|
+
REGEX_QUOTED_ESCAPE,
|
|
28
|
+
REGEX_NEWLINE_ESCAPE,
|
|
29
|
+
REGEX_ESCAPED_DELIMITER,
|
|
30
|
+
REGEX_SPECIAL_ESCAPED_DELIMITER,
|
|
31
|
+
REGEX_GROUP_OPEN,
|
|
32
|
+
REGEX_GROUP_CLOSE,
|
|
33
|
+
REGEX_UNCLOSED_GROUP,
|
|
34
|
+
#if !SED_REGEX_EXTENDED
|
|
35
|
+
REGEX_UNMATCHED_GROUP_CLOSE,
|
|
36
|
+
REGEX_BRE_VERTICAL_LINE_ESCAPE,
|
|
37
|
+
REGEX_BRE_QUESTION_MARK_ESCAPE,
|
|
38
|
+
REGEX_BRE_PLUS_ESCAPE,
|
|
39
|
+
REGEX_BRE_SUBEXPRESSION_CARET,
|
|
40
|
+
REGEX_BRE_SUBEXPRESSION_DOLLAR,
|
|
41
|
+
BRE_VERTICAL_LINE_ESCAPE_MARKER,
|
|
42
|
+
BRE_QUESTION_MARK_ESCAPE_MARKER,
|
|
43
|
+
BRE_PLUS_ESCAPE_MARKER,
|
|
44
|
+
REGEX_UNMATCHED_INTERVAL_CLOSE,
|
|
45
|
+
UNMATCHED_INTERVAL_CLOSE_MARKER,
|
|
46
|
+
#endif
|
|
47
|
+
#if SED_REGEX_EXTENDED
|
|
48
|
+
REGEX_ALTERNATION_OPERATOR,
|
|
49
|
+
#endif
|
|
50
|
+
REGEX_LEADING_DUPLICATION_MARKER,
|
|
51
|
+
REGEX_ADJACENT_DUPLICATION_MARKER,
|
|
52
|
+
REGEX_ZERO_OR_MORE,
|
|
53
|
+
#if SED_REGEX_EXTENDED
|
|
54
|
+
REGEX_ONE_OR_MORE,
|
|
55
|
+
REGEX_ZERO_OR_ONE,
|
|
56
|
+
REGEX_REPETITION_MODIFIER,
|
|
57
|
+
#endif
|
|
58
|
+
REGEX_INTERVAL_OPEN,
|
|
59
|
+
REGEX_DUP_COUNT,
|
|
60
|
+
REGEX_INTERVAL_SEPARATOR,
|
|
61
|
+
REGEX_INTERVAL_CLOSE,
|
|
62
|
+
#if !SED_REGEX_EXTENDED
|
|
63
|
+
REGEX_BACKREFERENCE,
|
|
64
|
+
#endif
|
|
65
|
+
REGEX_INVALID_INTERVAL,
|
|
66
|
+
REGEX_NONPORTABLE_ESCAPE,
|
|
67
|
+
REGEX_INCOMPLETE_ESCAPE,
|
|
68
|
+
REGEX_BRACKET_OPEN,
|
|
69
|
+
REGEX_BRACKET_CLOSE,
|
|
70
|
+
REGEX_BRACKET_LITERAL,
|
|
71
|
+
REGEX_BRACKET_NEGATION,
|
|
72
|
+
REGEX_BRACKET_HYPHEN,
|
|
73
|
+
REGEX_BRACKET_RANGE_END_HYPHEN,
|
|
74
|
+
REGEX_BRACKET_TRAILING_HYPHEN,
|
|
75
|
+
REGEX_OPEN_COLON,
|
|
76
|
+
REGEX_CLASS_NAME,
|
|
77
|
+
REGEX_COLON_CLOSE,
|
|
78
|
+
REGEX_OPEN_DOT,
|
|
79
|
+
REGEX_COLL_ELEM_SINGLE,
|
|
80
|
+
REGEX_COLL_ELEM_MULTI,
|
|
81
|
+
REGEX_META_CHAR,
|
|
82
|
+
REGEX_DOT_CLOSE,
|
|
83
|
+
REGEX_OPEN_EQUAL,
|
|
84
|
+
REGEX_EQUAL_CLOSE,
|
|
85
|
+
REGEX_MALFORMED_BRACKET_TERM,
|
|
86
|
+
REGEX_SHARED_RANGE_ENDPOINT,
|
|
87
|
+
AMBIGUOUS_BRACKET_EXPRESSION_MARKER,
|
|
88
|
+
MISSING_BRACKET_LIST_MARKER,
|
|
89
|
+
UNCLOSED_BRACKET_EXPRESSION_MARKER,
|
|
90
|
+
NONPORTABLE_RANGE_START_MARKER,
|
|
91
|
+
NONPORTABLE_RANGE_END_MARKER,
|
|
92
|
+
REGEX_UNTERMINATED_ADDRESS,
|
|
93
|
+
REGEX_UNTERMINATED_SUBSTITUTE,
|
|
94
|
+
REPLACEMENT_LITERAL,
|
|
95
|
+
REPLACEMENT_MATCH_REFERENCE,
|
|
96
|
+
REPLACEMENT_BACKREFERENCE,
|
|
97
|
+
REPLACEMENT_ESCAPED_DELIMITER,
|
|
98
|
+
REPLACEMENT_AMPERSAND_ESCAPED_DELIMITER,
|
|
99
|
+
REPLACEMENT_ESCAPE_SEQUENCE,
|
|
100
|
+
REPLACEMENT_NONPORTABLE_ESCAPE,
|
|
101
|
+
REPLACEMENT_ESCAPED_NEWLINE,
|
|
102
|
+
REPLACEMENT_INCOMPLETE_ESCAPE,
|
|
103
|
+
REPLACEMENT_UNTERMINATED,
|
|
104
|
+
TRANSLATE_LITERAL,
|
|
105
|
+
TRANSLATE_ESCAPED_DELIMITER,
|
|
106
|
+
TRANSLATE_ESCAPE,
|
|
107
|
+
TRANSLATE_NONPORTABLE_ESCAPE,
|
|
108
|
+
TRANSLATE_INCOMPLETE_ESCAPE,
|
|
109
|
+
TRANSLATE_UNTERMINATED_SOURCE,
|
|
110
|
+
TRANSLATE_UNTERMINATED_DESTINATION,
|
|
111
|
+
INVALID_SUBSTITUTION_FLAG,
|
|
112
|
+
TEXT_COMMAND_START,
|
|
113
|
+
TEXT_LITERAL,
|
|
114
|
+
TEXT_BACKSLASH_ESCAPE,
|
|
115
|
+
TEXT_ESCAPED_NEWLINE,
|
|
116
|
+
TEXT_UNSPECIFIED_ESCAPE,
|
|
117
|
+
TEXT_LINE_END,
|
|
118
|
+
TEXT_EOF,
|
|
119
|
+
DEFAULT_OUTPUT_SUPPRESSION,
|
|
120
|
+
COMMENT_TEXT,
|
|
121
|
+
FILE_ARGUMENT,
|
|
122
|
+
SUBSTITUTION_WFILE_ARGUMENT,
|
|
123
|
+
LINE_WORD,
|
|
124
|
+
RIGHT_BRACE,
|
|
125
|
+
RESERVED_UNKNOWN_FUNCTION,
|
|
126
|
+
REGEX_INCOMPLETE_GROUP,
|
|
127
|
+
REGEX_INCOMPLETE_BRACKET_TERM,
|
|
128
|
+
REGEX_INCOMPLETE_INTERVAL,
|
|
129
|
+
REGEX_FORBIDDEN_NEWLINE_ESCAPE,
|
|
130
|
+
REGEX_LINE_UNTERMINATED_ADDRESS,
|
|
131
|
+
REGEX_LINE_UNTERMINATED_SUBSTITUTE,
|
|
132
|
+
REPLACEMENT_LINE_UNTERMINATED,
|
|
133
|
+
TRANSLATE_LINE_UNTERMINATED_SOURCE,
|
|
134
|
+
TRANSLATE_LINE_UNTERMINATED_DESTINATION,
|
|
135
|
+
OMITTED_ADDRESS_MARKER,
|
|
136
|
+
OMITTED_FIRST_ADDRESS_MARKER,
|
|
137
|
+
EMPTY_SUBEXPRESSION_MARKER,
|
|
138
|
+
MISSING_SUBEXPRESSION_MARKER,
|
|
139
|
+
#if SED_REGEX_EXTENDED
|
|
140
|
+
EMPTY_ALTERNATIVE_MARKER,
|
|
141
|
+
#endif
|
|
142
|
+
EXCESS_ADDRESSES_MARKER,
|
|
143
|
+
ADDITIONAL_ADDRESS_MARKER,
|
|
144
|
+
MISSING_FUNCTION_MARKER,
|
|
145
|
+
MISSING_LABEL_MARKER,
|
|
146
|
+
MISSING_RFILE_MARKER,
|
|
147
|
+
MISSING_WFILE_MARKER,
|
|
148
|
+
OMITTED_FILE_SEPARATOR_MARKER,
|
|
149
|
+
MISSING_TEXT_INTRODUCER_MARKER,
|
|
150
|
+
MISSING_TEXT_MARKER,
|
|
151
|
+
MISSING_COMMAND_SEPARATOR_MARKER,
|
|
152
|
+
BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER,
|
|
153
|
+
MISSING_ADDRESS_SEPARATOR_MARKER,
|
|
154
|
+
DUPLICATE_NEGATION_MARKER,
|
|
155
|
+
MISSING_CLOSING_BRACE_MARKER,
|
|
156
|
+
MISSING_OPENING_DELIMITER_MARKER,
|
|
157
|
+
MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER,
|
|
158
|
+
MISSING_SEPARATOR_AFTER_UNMATCHED_BRACE_MARKER,
|
|
159
|
+
NONCONFORMING_MISSING_FUNCTION_MARKER,
|
|
160
|
+
NONCONFORMING_MISSING_LABEL_MARKER,
|
|
161
|
+
NONCONFORMING_MISSING_RFILE_MARKER,
|
|
162
|
+
NONCONFORMING_MISSING_WFILE_MARKER,
|
|
163
|
+
NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER,
|
|
164
|
+
NONCONFORMING_MISSING_OPENING_DELIMITER_MARKER,
|
|
165
|
+
MISSING_SUBEXPRESSION_PLACEHOLDER_MARKER,
|
|
166
|
+
INCOMPLETE_BRACKET_LIST_MARKER,
|
|
167
|
+
INCOMPLETE_BRACKET_EXPRESSION_MARKER,
|
|
168
|
+
#if SED_REGEX_EXTENDED
|
|
169
|
+
INCOMPLETE_ALTERNATIVE_MARKER,
|
|
170
|
+
#endif
|
|
171
|
+
INCOMPLETE_COMMAND_SEPARATOR_MARKER,
|
|
172
|
+
ERROR_SENTINEL,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
enum ScannerMode {
|
|
176
|
+
MODE_NONE,
|
|
177
|
+
MODE_REGEX_ADDRESS,
|
|
178
|
+
MODE_SUBSTITUTE_PATTERN,
|
|
179
|
+
MODE_SUBSTITUTE_REPLACEMENT,
|
|
180
|
+
MODE_TRANSLATE_SOURCE,
|
|
181
|
+
MODE_TRANSLATE_DESTINATION,
|
|
182
|
+
MODE_TEXT,
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
enum RegexState {
|
|
186
|
+
REGEX_OUTSIDE_BRACKET,
|
|
187
|
+
REGEX_BRACKET_FIRST,
|
|
188
|
+
REGEX_BRACKET_AFTER_CARET,
|
|
189
|
+
REGEX_BRACKET_BODY,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
enum TextState {
|
|
193
|
+
TEXT_EMPTY,
|
|
194
|
+
TEXT_HAS_CONTENT,
|
|
195
|
+
TEXT_AFTER_ESCAPED_NEWLINE,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
enum RegexIntervalState {
|
|
199
|
+
REGEX_INTERVAL_NONE,
|
|
200
|
+
REGEX_INTERVAL_EXPECT_MINIMUM,
|
|
201
|
+
REGEX_INTERVAL_AFTER_MINIMUM,
|
|
202
|
+
REGEX_INTERVAL_EXPECT_MAXIMUM,
|
|
203
|
+
REGEX_INTERVAL_AFTER_MAXIMUM,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
enum RegexDuplicationState {
|
|
207
|
+
REGEX_DUPLICATION_NONE,
|
|
208
|
+
REGEX_AFTER_DUPLICATION_SYMBOL,
|
|
209
|
+
REGEX_AFTER_REPETITION_MODIFIER,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
enum RegexBracketTermState {
|
|
213
|
+
REGEX_BRACKET_TERM_NONE,
|
|
214
|
+
REGEX_BRACKET_TERM_COLON,
|
|
215
|
+
REGEX_BRACKET_TERM_DOT,
|
|
216
|
+
REGEX_BRACKET_TERM_EQUAL,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
enum RegexBracketPendingElement {
|
|
220
|
+
REGEX_BRACKET_PENDING_NONE,
|
|
221
|
+
REGEX_BRACKET_PENDING_OTHER,
|
|
222
|
+
REGEX_BRACKET_PENDING_DOT,
|
|
223
|
+
REGEX_BRACKET_PENDING_EQUAL,
|
|
224
|
+
REGEX_BRACKET_PENDING_COLON,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
typedef struct {
|
|
228
|
+
int32_t delimiter;
|
|
229
|
+
enum ScannerMode mode;
|
|
230
|
+
enum RegexState regex_state;
|
|
231
|
+
bool regex_at_branch_start;
|
|
232
|
+
enum RegexDuplicationState regex_duplication_state;
|
|
233
|
+
bool regex_after_alternation;
|
|
234
|
+
bool regex_after_anchor;
|
|
235
|
+
enum TextState text_state;
|
|
236
|
+
enum RegexIntervalState regex_interval_state;
|
|
237
|
+
enum RegexBracketTermState regex_bracket_term_state;
|
|
238
|
+
enum RegexBracketPendingElement regex_bracket_pending_element;
|
|
239
|
+
enum RegexBracketPendingElement regex_bracket_first_element;
|
|
240
|
+
enum RegexBracketPendingElement regex_bracket_last_element;
|
|
241
|
+
uint8_t regex_bracket_element_count;
|
|
242
|
+
bool regex_bracket_range_pending;
|
|
243
|
+
uint16_t regex_group_depth;
|
|
244
|
+
} ScannerState;
|
|
245
|
+
|
|
246
|
+
enum {
|
|
247
|
+
SCANNER_SERIALIZATION_VERSION = 14,
|
|
248
|
+
SCANNER_SERIALIZED_STATE_SIZE = 17,
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
static void reset_bracket_tracking(ScannerState *state) {
|
|
252
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
253
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
254
|
+
state->regex_bracket_first_element = REGEX_BRACKET_PENDING_NONE;
|
|
255
|
+
state->regex_bracket_last_element = REGEX_BRACKET_PENDING_NONE;
|
|
256
|
+
state->regex_bracket_element_count = 0;
|
|
257
|
+
state->regex_bracket_range_pending = false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static void set_regex_position(
|
|
261
|
+
ScannerState *state,
|
|
262
|
+
bool at_branch_start,
|
|
263
|
+
enum RegexDuplicationState duplication_state,
|
|
264
|
+
bool after_alternation,
|
|
265
|
+
bool after_anchor
|
|
266
|
+
) {
|
|
267
|
+
state->regex_at_branch_start = at_branch_start;
|
|
268
|
+
state->regex_duplication_state = duplication_state;
|
|
269
|
+
state->regex_after_alternation = after_alternation;
|
|
270
|
+
state->regex_after_anchor = after_anchor;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
static void reset_mode_tracking(ScannerState *state) {
|
|
274
|
+
state->regex_state = REGEX_OUTSIDE_BRACKET;
|
|
275
|
+
state->regex_at_branch_start = false;
|
|
276
|
+
state->regex_duplication_state = REGEX_DUPLICATION_NONE;
|
|
277
|
+
state->regex_after_alternation = false;
|
|
278
|
+
state->regex_after_anchor = false;
|
|
279
|
+
state->text_state = TEXT_EMPTY;
|
|
280
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
281
|
+
reset_bracket_tracking(state);
|
|
282
|
+
state->regex_group_depth = 0;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static void reset_state(ScannerState *state) {
|
|
286
|
+
state->delimiter = 0;
|
|
287
|
+
state->mode = MODE_NONE;
|
|
288
|
+
reset_mode_tracking(state);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static void *sed_scanner_create(void) {
|
|
292
|
+
return ts_calloc(1, sizeof(ScannerState));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
static void sed_scanner_destroy(void *payload) {
|
|
296
|
+
ts_free(payload);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
static void serialize_uint16(char *buffer, unsigned offset, uint16_t value) {
|
|
300
|
+
buffer[offset] = (char)(value & UINT16_C(0xff));
|
|
301
|
+
buffer[offset + 1] = (char)((value >> 8) & UINT16_C(0xff));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static uint16_t deserialize_uint16(const char *buffer, unsigned offset) {
|
|
305
|
+
return (uint16_t)((uint16_t)(unsigned char)buffer[offset] |
|
|
306
|
+
((uint16_t)(unsigned char)buffer[offset + 1] << 8));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
static unsigned sed_scanner_serialize(void *payload, char *buffer) {
|
|
310
|
+
const ScannerState *state = payload;
|
|
311
|
+
const uint32_t delimiter = (uint32_t)state->delimiter;
|
|
312
|
+
|
|
313
|
+
buffer[0] = SCANNER_SERIALIZATION_VERSION;
|
|
314
|
+
buffer[1] = (char)state->mode;
|
|
315
|
+
buffer[2] = (char)state->regex_state;
|
|
316
|
+
buffer[3] = (state->regex_at_branch_start ? 1 : 0) |
|
|
317
|
+
(state->regex_after_alternation ? 2 : 0) |
|
|
318
|
+
(state->regex_after_anchor ? 4 : 0) |
|
|
319
|
+
((unsigned char)state->text_state << 3);
|
|
320
|
+
buffer[4] = (char)(delimiter & UINT32_C(0xff));
|
|
321
|
+
buffer[5] = (char)((delimiter >> 8) & UINT32_C(0xff));
|
|
322
|
+
buffer[6] = (char)((delimiter >> 16) & UINT32_C(0xff));
|
|
323
|
+
buffer[7] = (char)((delimiter >> 24) & UINT32_C(0xff));
|
|
324
|
+
serialize_uint16(buffer, 8, state->regex_group_depth);
|
|
325
|
+
buffer[10] = (char)state->regex_interval_state;
|
|
326
|
+
buffer[11] = (char)state->regex_bracket_term_state;
|
|
327
|
+
buffer[12] = (char)state->regex_bracket_pending_element;
|
|
328
|
+
buffer[13] = (char)state->regex_bracket_first_element;
|
|
329
|
+
buffer[14] = (char)state->regex_bracket_last_element;
|
|
330
|
+
buffer[15] = (char)state->regex_bracket_element_count;
|
|
331
|
+
buffer[16] = (state->regex_bracket_range_pending ? 1 : 0) |
|
|
332
|
+
((unsigned char)state->regex_duplication_state << 1);
|
|
333
|
+
return SCANNER_SERIALIZED_STATE_SIZE;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static void
|
|
337
|
+
sed_scanner_deserialize(void *payload, const char *buffer, unsigned length) {
|
|
338
|
+
ScannerState *state = payload;
|
|
339
|
+
reset_state(state);
|
|
340
|
+
|
|
341
|
+
if (
|
|
342
|
+
length !=
|
|
343
|
+
SCANNER_SERIALIZED_STATE_SIZE ||
|
|
344
|
+
(unsigned char)buffer[0] != SCANNER_SERIALIZATION_VERSION
|
|
345
|
+
) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const enum ScannerMode mode = (enum ScannerMode)(unsigned char)buffer[1];
|
|
350
|
+
const enum RegexState regex_state = (enum RegexState)(unsigned char)buffer[2];
|
|
351
|
+
const unsigned char mode_flags = (unsigned char)buffer[3];
|
|
352
|
+
const uint32_t delimiter = (uint32_t)(unsigned char)buffer[4] |
|
|
353
|
+
((uint32_t)(unsigned char)buffer[5] << 8) |
|
|
354
|
+
((uint32_t)(unsigned char)buffer[6] << 16) |
|
|
355
|
+
((uint32_t)(unsigned char)buffer[7] << 24);
|
|
356
|
+
const uint16_t regex_group_depth = deserialize_uint16(buffer, 8);
|
|
357
|
+
const enum RegexIntervalState regex_interval_state =
|
|
358
|
+
(enum RegexIntervalState)(unsigned char)buffer[10];
|
|
359
|
+
const enum RegexBracketTermState regex_bracket_term_state =
|
|
360
|
+
(enum RegexBracketTermState)(unsigned char)buffer[11];
|
|
361
|
+
const enum RegexBracketPendingElement regex_bracket_pending_element =
|
|
362
|
+
(enum RegexBracketPendingElement)(unsigned char)buffer[12];
|
|
363
|
+
const enum RegexBracketPendingElement regex_bracket_first_element =
|
|
364
|
+
(enum RegexBracketPendingElement)(unsigned char)buffer[13];
|
|
365
|
+
const enum RegexBracketPendingElement regex_bracket_last_element =
|
|
366
|
+
(enum RegexBracketPendingElement)(unsigned char)buffer[14];
|
|
367
|
+
const uint8_t regex_bracket_element_count =
|
|
368
|
+
(uint8_t)(unsigned char)buffer[15];
|
|
369
|
+
const unsigned char regex_bracket_flags = (unsigned char)buffer[16];
|
|
370
|
+
const bool regex_bracket_range_pending = (regex_bracket_flags & 1U) != 0;
|
|
371
|
+
const enum RegexDuplicationState regex_duplication_state =
|
|
372
|
+
(enum RegexDuplicationState)((regex_bracket_flags >> 1) & 3U);
|
|
373
|
+
|
|
374
|
+
if (mode > MODE_TEXT) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (regex_state > REGEX_BRACKET_BODY) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if ((mode_flags & (unsigned char)~31U) != 0) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const bool regex_at_branch_start = (mode_flags & 1U) != 0;
|
|
386
|
+
const bool regex_after_alternation = (mode_flags & 2U) != 0;
|
|
387
|
+
const bool regex_after_anchor = (mode_flags & 4U) != 0;
|
|
388
|
+
const enum TextState text_state = (enum TextState)((mode_flags >> 3) & 3U);
|
|
389
|
+
if (text_state > TEXT_AFTER_ESCAPED_NEWLINE) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
#if !SED_REGEX_EXTENDED
|
|
393
|
+
if (regex_after_alternation) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
#endif
|
|
397
|
+
|
|
398
|
+
if (regex_interval_state > REGEX_INTERVAL_AFTER_MAXIMUM) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (regex_bracket_term_state > REGEX_BRACKET_TERM_EQUAL) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (
|
|
405
|
+
regex_bracket_pending_element >
|
|
406
|
+
REGEX_BRACKET_PENDING_COLON ||
|
|
407
|
+
regex_bracket_first_element >
|
|
408
|
+
REGEX_BRACKET_PENDING_COLON ||
|
|
409
|
+
regex_bracket_last_element >
|
|
410
|
+
REGEX_BRACKET_PENDING_COLON ||
|
|
411
|
+
regex_bracket_element_count >
|
|
412
|
+
3U ||
|
|
413
|
+
(regex_bracket_flags & (unsigned char)~7U) !=
|
|
414
|
+
0 ||
|
|
415
|
+
#if SED_REGEX_EXTENDED
|
|
416
|
+
regex_duplication_state > REGEX_AFTER_REPETITION_MODIFIER
|
|
417
|
+
#else
|
|
418
|
+
regex_duplication_state > REGEX_AFTER_DUPLICATION_SYMBOL
|
|
419
|
+
#endif
|
|
420
|
+
) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (
|
|
424
|
+
(regex_bracket_element_count ==
|
|
425
|
+
0 &&
|
|
426
|
+
(regex_bracket_first_element !=
|
|
427
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
428
|
+
regex_bracket_last_element != REGEX_BRACKET_PENDING_NONE)) ||
|
|
429
|
+
(regex_bracket_element_count >
|
|
430
|
+
0 &&
|
|
431
|
+
(regex_bracket_first_element ==
|
|
432
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
433
|
+
regex_bracket_last_element == REGEX_BRACKET_PENDING_NONE)) ||
|
|
434
|
+
(regex_bracket_pending_element !=
|
|
435
|
+
REGEX_BRACKET_PENDING_NONE &&
|
|
436
|
+
regex_bracket_range_pending)
|
|
437
|
+
) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (mode == MODE_NONE) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (mode == MODE_TEXT) {
|
|
446
|
+
if (
|
|
447
|
+
delimiter ==
|
|
448
|
+
0 &&
|
|
449
|
+
regex_state ==
|
|
450
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
451
|
+
!regex_at_branch_start &&
|
|
452
|
+
regex_duplication_state ==
|
|
453
|
+
REGEX_DUPLICATION_NONE &&
|
|
454
|
+
regex_group_depth ==
|
|
455
|
+
0 &&
|
|
456
|
+
!regex_after_anchor &&
|
|
457
|
+
regex_interval_state ==
|
|
458
|
+
REGEX_INTERVAL_NONE &&
|
|
459
|
+
!regex_after_alternation &&
|
|
460
|
+
regex_bracket_term_state ==
|
|
461
|
+
REGEX_BRACKET_TERM_NONE &&
|
|
462
|
+
regex_bracket_pending_element ==
|
|
463
|
+
REGEX_BRACKET_PENDING_NONE &&
|
|
464
|
+
regex_bracket_first_element ==
|
|
465
|
+
REGEX_BRACKET_PENDING_NONE &&
|
|
466
|
+
regex_bracket_last_element ==
|
|
467
|
+
REGEX_BRACKET_PENDING_NONE &&
|
|
468
|
+
regex_bracket_element_count ==
|
|
469
|
+
0 &&
|
|
470
|
+
!regex_bracket_range_pending
|
|
471
|
+
) {
|
|
472
|
+
state->mode = mode;
|
|
473
|
+
state->text_state = text_state;
|
|
474
|
+
}
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (
|
|
479
|
+
delimiter ==
|
|
480
|
+
0 ||
|
|
481
|
+
delimiter >
|
|
482
|
+
UINT32_C(0x10ffff) ||
|
|
483
|
+
(delimiter >= UINT32_C(0xd800) && delimiter <= UINT32_C(0xdfff)) ||
|
|
484
|
+
delimiter ==
|
|
485
|
+
(uint32_t)'\\' ||
|
|
486
|
+
delimiter == (uint32_t)'\n'
|
|
487
|
+
) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (
|
|
492
|
+
mode !=
|
|
493
|
+
MODE_REGEX_ADDRESS &&
|
|
494
|
+
mode !=
|
|
495
|
+
MODE_SUBSTITUTE_PATTERN &&
|
|
496
|
+
(regex_state !=
|
|
497
|
+
REGEX_OUTSIDE_BRACKET ||
|
|
498
|
+
regex_at_branch_start ||
|
|
499
|
+
regex_duplication_state !=
|
|
500
|
+
REGEX_DUPLICATION_NONE ||
|
|
501
|
+
regex_after_alternation ||
|
|
502
|
+
regex_after_anchor ||
|
|
503
|
+
text_state !=
|
|
504
|
+
TEXT_EMPTY ||
|
|
505
|
+
regex_interval_state !=
|
|
506
|
+
REGEX_INTERVAL_NONE ||
|
|
507
|
+
regex_bracket_term_state !=
|
|
508
|
+
REGEX_BRACKET_TERM_NONE ||
|
|
509
|
+
regex_bracket_pending_element !=
|
|
510
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
511
|
+
regex_bracket_first_element !=
|
|
512
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
513
|
+
regex_bracket_last_element !=
|
|
514
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
515
|
+
regex_bracket_element_count !=
|
|
516
|
+
0 ||
|
|
517
|
+
regex_bracket_range_pending)
|
|
518
|
+
) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (
|
|
523
|
+
regex_state !=
|
|
524
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
525
|
+
(regex_at_branch_start ||
|
|
526
|
+
regex_duplication_state !=
|
|
527
|
+
REGEX_DUPLICATION_NONE ||
|
|
528
|
+
regex_after_alternation ||
|
|
529
|
+
regex_after_anchor)
|
|
530
|
+
) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (
|
|
535
|
+
regex_state ==
|
|
536
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
537
|
+
(regex_bracket_term_state !=
|
|
538
|
+
REGEX_BRACKET_TERM_NONE ||
|
|
539
|
+
regex_bracket_pending_element !=
|
|
540
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
541
|
+
regex_bracket_first_element !=
|
|
542
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
543
|
+
regex_bracket_last_element !=
|
|
544
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
545
|
+
regex_bracket_element_count !=
|
|
546
|
+
0 ||
|
|
547
|
+
regex_bracket_range_pending)
|
|
548
|
+
) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (
|
|
553
|
+
(regex_state ==
|
|
554
|
+
REGEX_BRACKET_FIRST ||
|
|
555
|
+
regex_state == REGEX_BRACKET_AFTER_CARET) &&
|
|
556
|
+
(regex_bracket_term_state !=
|
|
557
|
+
REGEX_BRACKET_TERM_NONE ||
|
|
558
|
+
regex_bracket_pending_element !=
|
|
559
|
+
REGEX_BRACKET_PENDING_NONE ||
|
|
560
|
+
regex_bracket_element_count !=
|
|
561
|
+
0 ||
|
|
562
|
+
regex_bracket_range_pending)
|
|
563
|
+
) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (
|
|
568
|
+
(mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN) &&
|
|
569
|
+
text_state != TEXT_EMPTY
|
|
570
|
+
) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (
|
|
575
|
+
mode !=
|
|
576
|
+
MODE_REGEX_ADDRESS &&
|
|
577
|
+
mode !=
|
|
578
|
+
MODE_SUBSTITUTE_PATTERN &&
|
|
579
|
+
regex_group_depth != 0
|
|
580
|
+
) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
state->mode = mode;
|
|
585
|
+
state->delimiter = (int32_t)delimiter;
|
|
586
|
+
state->regex_state = regex_state;
|
|
587
|
+
state->regex_at_branch_start = regex_at_branch_start;
|
|
588
|
+
state->regex_duplication_state = regex_duplication_state;
|
|
589
|
+
state->regex_after_alternation = regex_after_alternation;
|
|
590
|
+
state->regex_after_anchor = regex_after_anchor;
|
|
591
|
+
state->regex_interval_state = regex_interval_state;
|
|
592
|
+
state->regex_bracket_term_state = regex_bracket_term_state;
|
|
593
|
+
state->regex_bracket_pending_element = regex_bracket_pending_element;
|
|
594
|
+
state->regex_bracket_first_element = regex_bracket_first_element;
|
|
595
|
+
state->regex_bracket_last_element = regex_bracket_last_element;
|
|
596
|
+
state->regex_bracket_element_count = regex_bracket_element_count;
|
|
597
|
+
state->regex_bracket_range_pending = regex_bracket_range_pending;
|
|
598
|
+
state->regex_group_depth = regex_group_depth;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
static void advance(TSLexer *lexer) {
|
|
602
|
+
lexer->advance(lexer, false);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
static bool is_blank(int32_t character) {
|
|
606
|
+
return character == ' ' || character == '\t';
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
static bool is_digit(int32_t character) {
|
|
610
|
+
return character >= '0' && character <= '9';
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
static void advance_past_blanks(TSLexer *lexer) {
|
|
614
|
+
while (is_blank(lexer->lookahead)) {
|
|
615
|
+
advance(lexer);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
static void advance_past_escaped_character(TSLexer *lexer) {
|
|
620
|
+
if (!lexer->eof(lexer) && lexer->lookahead != '\n') {
|
|
621
|
+
advance(lexer);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
static void skip_blanks(TSLexer *lexer) {
|
|
626
|
+
while (is_blank(lexer->lookahead)) {
|
|
627
|
+
lexer->advance(lexer, true);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
static bool invalid_delimiter(TSLexer *lexer) {
|
|
632
|
+
return lexer->eof(lexer) ||
|
|
633
|
+
lexer->lookahead ==
|
|
634
|
+
0 ||
|
|
635
|
+
lexer->lookahead ==
|
|
636
|
+
'\\' ||
|
|
637
|
+
lexer->lookahead == '\n';
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
static bool delimiter_is_missing(TSLexer *lexer) {
|
|
641
|
+
return lexer->eof(lexer) || lexer->lookahead == '\n';
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
static bool scan_simple_delimiter(
|
|
645
|
+
TSLexer *lexer,
|
|
646
|
+
ScannerState *state,
|
|
647
|
+
enum ScannerMode next_mode
|
|
648
|
+
) {
|
|
649
|
+
if (invalid_delimiter(lexer)) {
|
|
650
|
+
return false;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
state->delimiter = lexer->lookahead;
|
|
654
|
+
state->mode = next_mode;
|
|
655
|
+
reset_mode_tracking(state);
|
|
656
|
+
state->regex_at_branch_start =
|
|
657
|
+
next_mode == MODE_REGEX_ADDRESS || next_mode == MODE_SUBSTITUTE_PATTERN;
|
|
658
|
+
advance(lexer);
|
|
659
|
+
lexer->mark_end(lexer);
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
static bool scan_mode_delimiter(
|
|
664
|
+
TSLexer *lexer,
|
|
665
|
+
ScannerState *state,
|
|
666
|
+
enum ScannerMode next_mode
|
|
667
|
+
) {
|
|
668
|
+
if (lexer->lookahead != state->delimiter) {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
state->mode = next_mode;
|
|
673
|
+
reset_mode_tracking(state);
|
|
674
|
+
if (next_mode == MODE_NONE) {
|
|
675
|
+
state->delimiter = 0;
|
|
676
|
+
}
|
|
677
|
+
advance(lexer);
|
|
678
|
+
lexer->mark_end(lexer);
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
static bool scan_active_mode_delimiter(
|
|
683
|
+
TSLexer *lexer,
|
|
684
|
+
ScannerState *state,
|
|
685
|
+
const bool *valid_symbols,
|
|
686
|
+
TSSymbol *symbol
|
|
687
|
+
) {
|
|
688
|
+
TSSymbol candidate;
|
|
689
|
+
enum ScannerMode next_mode;
|
|
690
|
+
|
|
691
|
+
switch (state->mode) {
|
|
692
|
+
case MODE_REGEX_ADDRESS:
|
|
693
|
+
candidate = REGEX_ADDRESS_END;
|
|
694
|
+
next_mode = MODE_NONE;
|
|
695
|
+
break;
|
|
696
|
+
case MODE_SUBSTITUTE_PATTERN:
|
|
697
|
+
candidate = SUBSTITUTE_MIDDLE;
|
|
698
|
+
next_mode = MODE_SUBSTITUTE_REPLACEMENT;
|
|
699
|
+
break;
|
|
700
|
+
case MODE_SUBSTITUTE_REPLACEMENT:
|
|
701
|
+
candidate = SUBSTITUTE_END;
|
|
702
|
+
next_mode = MODE_NONE;
|
|
703
|
+
break;
|
|
704
|
+
case MODE_TRANSLATE_SOURCE:
|
|
705
|
+
candidate = TRANSLATE_MIDDLE;
|
|
706
|
+
next_mode = MODE_TRANSLATE_DESTINATION;
|
|
707
|
+
break;
|
|
708
|
+
case MODE_TRANSLATE_DESTINATION:
|
|
709
|
+
candidate = TRANSLATE_END;
|
|
710
|
+
next_mode = MODE_NONE;
|
|
711
|
+
break;
|
|
712
|
+
case MODE_NONE:
|
|
713
|
+
case MODE_TEXT:
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (
|
|
718
|
+
!valid_symbols[candidate] || !scan_mode_delimiter(lexer, state, next_mode)
|
|
719
|
+
) {
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
*symbol = candidate;
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
static void consume(TSLexer *lexer) {
|
|
728
|
+
advance(lexer);
|
|
729
|
+
lexer->mark_end(lexer);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
static bool scan_text_command_start(TSLexer *lexer, ScannerState *state) {
|
|
733
|
+
if (state->mode != MODE_NONE || lexer->lookahead != '\\') {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
lexer->mark_end(lexer);
|
|
738
|
+
advance(lexer);
|
|
739
|
+
|
|
740
|
+
if (lexer->lookahead != '\n') {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
consume(lexer);
|
|
745
|
+
state->mode = MODE_TEXT;
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
static bool scan_to_physical_line_end(TSLexer *lexer, bool consumed) {
|
|
750
|
+
while (!lexer->eof(lexer)) {
|
|
751
|
+
if (lexer->lookahead == '\n') {
|
|
752
|
+
return consumed;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
consume(lexer);
|
|
756
|
+
consumed = true;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return consumed;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
static bool scan_file_argument(TSLexer *lexer) {
|
|
763
|
+
if (
|
|
764
|
+
lexer->eof(lexer) || is_blank(lexer->lookahead) || lexer->lookahead == '\n'
|
|
765
|
+
) {
|
|
766
|
+
return false;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
consume(lexer);
|
|
770
|
+
return scan_to_physical_line_end(lexer, true);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
static bool scan_substitution_wfile_argument(TSLexer *lexer) {
|
|
774
|
+
if (
|
|
775
|
+
lexer->eof(lexer) ||
|
|
776
|
+
is_blank(lexer->lookahead) ||
|
|
777
|
+
lexer->lookahead ==
|
|
778
|
+
'\n' ||
|
|
779
|
+
lexer->lookahead == ';'
|
|
780
|
+
) {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
do {
|
|
785
|
+
consume(lexer);
|
|
786
|
+
} while (
|
|
787
|
+
!lexer->eof(lexer) && lexer->lookahead != '\n' && lexer->lookahead != ';'
|
|
788
|
+
);
|
|
789
|
+
return true;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static bool scan_right_brace(TSLexer *lexer, ScannerState *state) {
|
|
793
|
+
if (state->mode != MODE_NONE) {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
skip_blanks(lexer);
|
|
798
|
+
|
|
799
|
+
if (lexer->lookahead != '}') {
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
consume(lexer);
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
static bool scan_reserved_unknown_function(TSLexer *lexer) {
|
|
808
|
+
const int32_t character = lexer->lookahead;
|
|
809
|
+
if (
|
|
810
|
+
!is_digit(character) &&
|
|
811
|
+
character !=
|
|
812
|
+
'$' &&
|
|
813
|
+
character !=
|
|
814
|
+
'/' &&
|
|
815
|
+
character != '\\'
|
|
816
|
+
) {
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
consume(lexer);
|
|
821
|
+
return true;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
enum LiteralScanResult {
|
|
825
|
+
LITERAL_SCAN_NONE,
|
|
826
|
+
LITERAL_SCAN_TOKEN,
|
|
827
|
+
LITERAL_SCAN_LINE_END,
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
static bool
|
|
831
|
+
emit_symbol(const bool *valid_symbols, TSSymbol candidate, TSSymbol *symbol) {
|
|
832
|
+
if (!valid_symbols[candidate]) {
|
|
833
|
+
return false;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
*symbol = candidate;
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
static bool emit_missing_marker(
|
|
841
|
+
TSLexer *lexer,
|
|
842
|
+
const bool *valid_symbols,
|
|
843
|
+
TSSymbol candidate,
|
|
844
|
+
TSSymbol *symbol
|
|
845
|
+
) {
|
|
846
|
+
if (!valid_symbols[candidate]) {
|
|
847
|
+
return false;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
lexer->mark_end(lexer);
|
|
851
|
+
*symbol = candidate;
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
static bool at_command_boundary(TSLexer *lexer) {
|
|
856
|
+
return lexer->eof(lexer) ||
|
|
857
|
+
lexer->lookahead ==
|
|
858
|
+
'\n' ||
|
|
859
|
+
lexer->lookahead ==
|
|
860
|
+
';' ||
|
|
861
|
+
lexer->lookahead == '}';
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
static bool can_start_address(TSLexer *lexer) {
|
|
865
|
+
return is_digit(lexer->lookahead) ||
|
|
866
|
+
lexer->lookahead ==
|
|
867
|
+
'$' ||
|
|
868
|
+
lexer->lookahead ==
|
|
869
|
+
'/' ||
|
|
870
|
+
lexer->lookahead == '\\';
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
enum PostBlankRecoveryScan {
|
|
874
|
+
POST_BLANK_RECOVERY_SKIPPED,
|
|
875
|
+
POST_BLANK_RECOVERY_TOKEN,
|
|
876
|
+
POST_BLANK_RECOVERY_FAILED,
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
static enum PostBlankRecoveryScan scan_post_blank_recovery(
|
|
880
|
+
TSLexer *lexer,
|
|
881
|
+
const bool *valid_symbols,
|
|
882
|
+
TSSymbol *symbol
|
|
883
|
+
) {
|
|
884
|
+
if (
|
|
885
|
+
!valid_symbols[OMITTED_ADDRESS_MARKER] &&
|
|
886
|
+
!valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
|
|
887
|
+
!valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
|
|
888
|
+
!valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] &&
|
|
889
|
+
!valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER] &&
|
|
890
|
+
!valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER] &&
|
|
891
|
+
!valid_symbols[INCOMPLETE_COMMAND_SEPARATOR_MARKER]
|
|
892
|
+
) {
|
|
893
|
+
return POST_BLANK_RECOVERY_SKIPPED;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
lexer->mark_end(lexer);
|
|
897
|
+
advance_past_blanks(lexer);
|
|
898
|
+
|
|
899
|
+
if (valid_symbols[OMITTED_ADDRESS_MARKER] && !can_start_address(lexer)) {
|
|
900
|
+
*symbol = OMITTED_ADDRESS_MARKER;
|
|
901
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
902
|
+
}
|
|
903
|
+
if (
|
|
904
|
+
valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
|
|
905
|
+
(lexer->lookahead == ',' || can_start_address(lexer))
|
|
906
|
+
) {
|
|
907
|
+
*symbol = ADDITIONAL_ADDRESS_MARKER;
|
|
908
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
909
|
+
}
|
|
910
|
+
if (
|
|
911
|
+
valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
|
|
912
|
+
lexer->lookahead == ','
|
|
913
|
+
) {
|
|
914
|
+
*symbol = BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER;
|
|
915
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
916
|
+
}
|
|
917
|
+
if (
|
|
918
|
+
valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
|
|
919
|
+
) {
|
|
920
|
+
*symbol = MISSING_ADDRESS_SEPARATOR_MARKER;
|
|
921
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
922
|
+
}
|
|
923
|
+
if (lexer->lookahead == '}') {
|
|
924
|
+
if (valid_symbols[MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER]) {
|
|
925
|
+
*symbol = MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER;
|
|
926
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
927
|
+
}
|
|
928
|
+
if (valid_symbols[MISSING_COMMAND_SEPARATOR_MARKER]) {
|
|
929
|
+
*symbol = MISSING_COMMAND_SEPARATOR_MARKER;
|
|
930
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
931
|
+
}
|
|
932
|
+
return POST_BLANK_RECOVERY_FAILED;
|
|
933
|
+
}
|
|
934
|
+
if (lexer->eof(lexer) && valid_symbols[INCOMPLETE_COMMAND_SEPARATOR_MARKER]) {
|
|
935
|
+
*symbol = INCOMPLETE_COMMAND_SEPARATOR_MARKER;
|
|
936
|
+
return POST_BLANK_RECOVERY_TOKEN;
|
|
937
|
+
}
|
|
938
|
+
return POST_BLANK_RECOVERY_FAILED;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
static bool scan_text_token(
|
|
942
|
+
TSLexer *lexer,
|
|
943
|
+
ScannerState *state,
|
|
944
|
+
const bool *valid_symbols,
|
|
945
|
+
TSSymbol *symbol
|
|
946
|
+
) {
|
|
947
|
+
if (lexer->eof(lexer)) {
|
|
948
|
+
if (state->text_state == TEXT_AFTER_ESCAPED_NEWLINE) {
|
|
949
|
+
if (!emit_missing_marker(
|
|
950
|
+
lexer,
|
|
951
|
+
valid_symbols,
|
|
952
|
+
MISSING_TEXT_MARKER,
|
|
953
|
+
symbol
|
|
954
|
+
)) {
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
958
|
+
return true;
|
|
959
|
+
}
|
|
960
|
+
if (
|
|
961
|
+
state->text_state ==
|
|
962
|
+
TEXT_EMPTY &&
|
|
963
|
+
emit_missing_marker(lexer, valid_symbols, MISSING_TEXT_MARKER, symbol)
|
|
964
|
+
) {
|
|
965
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
if (!valid_symbols[TEXT_EOF]) {
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
lexer->mark_end(lexer);
|
|
972
|
+
reset_state(state);
|
|
973
|
+
*symbol = TEXT_EOF;
|
|
974
|
+
return true;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
if (lexer->lookahead == '\n') {
|
|
978
|
+
if (!valid_symbols[TEXT_LINE_END]) {
|
|
979
|
+
return false;
|
|
980
|
+
}
|
|
981
|
+
lexer->mark_end(lexer);
|
|
982
|
+
reset_state(state);
|
|
983
|
+
*symbol = TEXT_LINE_END;
|
|
984
|
+
return true;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (lexer->lookahead == '\\') {
|
|
988
|
+
advance(lexer);
|
|
989
|
+
lexer->mark_end(lexer);
|
|
990
|
+
|
|
991
|
+
if (lexer->eof(lexer)) {
|
|
992
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
993
|
+
return emit_symbol(valid_symbols, TEXT_UNSPECIFIED_ESCAPE, symbol);
|
|
994
|
+
}
|
|
995
|
+
if (lexer->lookahead == '\\') {
|
|
996
|
+
consume(lexer);
|
|
997
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
998
|
+
return emit_symbol(valid_symbols, TEXT_BACKSLASH_ESCAPE, symbol);
|
|
999
|
+
}
|
|
1000
|
+
if (lexer->lookahead == '\n') {
|
|
1001
|
+
consume(lexer);
|
|
1002
|
+
state->text_state = TEXT_AFTER_ESCAPED_NEWLINE;
|
|
1003
|
+
return emit_symbol(valid_symbols, TEXT_ESCAPED_NEWLINE, symbol);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
consume(lexer);
|
|
1007
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
1008
|
+
return emit_symbol(valid_symbols, TEXT_UNSPECIFIED_ESCAPE, symbol);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
if (!valid_symbols[TEXT_LITERAL]) {
|
|
1012
|
+
return false;
|
|
1013
|
+
}
|
|
1014
|
+
do {
|
|
1015
|
+
consume(lexer);
|
|
1016
|
+
} while (
|
|
1017
|
+
!lexer->eof(lexer) && lexer->lookahead != '\\' && lexer->lookahead != '\n'
|
|
1018
|
+
);
|
|
1019
|
+
state->text_state = TEXT_HAS_CONTENT;
|
|
1020
|
+
*symbol = TEXT_LITERAL;
|
|
1021
|
+
return true;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
static bool is_regex_mode(enum ScannerMode mode) {
|
|
1025
|
+
return mode == MODE_REGEX_ADDRESS || mode == MODE_SUBSTITUTE_PATTERN;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
static bool regex_is_inside_bracket(const ScannerState *state) {
|
|
1029
|
+
return state->regex_state != REGEX_OUTSIDE_BRACKET;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
static enum RegexBracketPendingElement
|
|
1033
|
+
bracket_element_for_character(int32_t character) {
|
|
1034
|
+
switch (character) {
|
|
1035
|
+
case '.':
|
|
1036
|
+
return REGEX_BRACKET_PENDING_DOT;
|
|
1037
|
+
case '=':
|
|
1038
|
+
return REGEX_BRACKET_PENDING_EQUAL;
|
|
1039
|
+
case ':':
|
|
1040
|
+
return REGEX_BRACKET_PENDING_COLON;
|
|
1041
|
+
default:
|
|
1042
|
+
return REGEX_BRACKET_PENDING_OTHER;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
static void record_bracket_element(
|
|
1047
|
+
ScannerState *state,
|
|
1048
|
+
enum RegexBracketPendingElement element
|
|
1049
|
+
) {
|
|
1050
|
+
if (state->regex_bracket_element_count == 0) {
|
|
1051
|
+
state->regex_bracket_first_element = element;
|
|
1052
|
+
}
|
|
1053
|
+
if (state->regex_bracket_element_count < 3U) {
|
|
1054
|
+
state->regex_bracket_element_count++;
|
|
1055
|
+
}
|
|
1056
|
+
state->regex_bracket_last_element = element;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
static void commit_pending_bracket_element(ScannerState *state) {
|
|
1060
|
+
if (state->regex_bracket_pending_element == REGEX_BRACKET_PENDING_NONE) {
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
record_bracket_element(state, state->regex_bracket_pending_element);
|
|
1065
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
static void
|
|
1069
|
+
begin_single_bracket_element(ScannerState *state, int32_t character) {
|
|
1070
|
+
if (state->regex_bracket_range_pending) {
|
|
1071
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
1072
|
+
state->regex_bracket_range_pending = false;
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
commit_pending_bracket_element(state);
|
|
1077
|
+
state->regex_bracket_pending_element =
|
|
1078
|
+
bracket_element_for_character(character);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
static void begin_compound_bracket_element(ScannerState *state) {
|
|
1082
|
+
if (!state->regex_bracket_range_pending) {
|
|
1083
|
+
commit_pending_bracket_element(state);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
static void finish_compound_bracket_element(ScannerState *state) {
|
|
1088
|
+
if (state->regex_bracket_range_pending) {
|
|
1089
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
1090
|
+
state->regex_bracket_range_pending = false;
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_OTHER;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
static bool bracket_expression_is_ambiguous(const ScannerState *state) {
|
|
1098
|
+
return state->regex_bracket_element_count >=
|
|
1099
|
+
3U &&
|
|
1100
|
+
state->regex_bracket_first_element >=
|
|
1101
|
+
REGEX_BRACKET_PENDING_DOT &&
|
|
1102
|
+
state->regex_bracket_first_element == state->regex_bracket_last_element;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
static void finish_first_bracket_element(ScannerState *state) {
|
|
1106
|
+
if (
|
|
1107
|
+
state->regex_state ==
|
|
1108
|
+
REGEX_BRACKET_FIRST ||
|
|
1109
|
+
state->regex_state == REGEX_BRACKET_AFTER_CARET
|
|
1110
|
+
) {
|
|
1111
|
+
state->regex_state = REGEX_BRACKET_BODY;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
static void
|
|
1116
|
+
update_bracket_state_after_literal(ScannerState *state, int32_t character) {
|
|
1117
|
+
if (state->regex_state == REGEX_BRACKET_FIRST) {
|
|
1118
|
+
state->regex_state =
|
|
1119
|
+
character == '^' ? REGEX_BRACKET_AFTER_CARET : REGEX_BRACKET_BODY;
|
|
1120
|
+
} else if (state->regex_state == REGEX_BRACKET_AFTER_CARET) {
|
|
1121
|
+
state->regex_state = REGEX_BRACKET_BODY;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
static bool
|
|
1126
|
+
regex_literal_boundary(const ScannerState *state, int32_t character) {
|
|
1127
|
+
if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
|
|
1128
|
+
return character ==
|
|
1129
|
+
state->delimiter ||
|
|
1130
|
+
character ==
|
|
1131
|
+
'\\' ||
|
|
1132
|
+
character ==
|
|
1133
|
+
'(' ||
|
|
1134
|
+
character ==
|
|
1135
|
+
')' ||
|
|
1136
|
+
character ==
|
|
1137
|
+
'[' ||
|
|
1138
|
+
character ==
|
|
1139
|
+
'*' ||
|
|
1140
|
+
character ==
|
|
1141
|
+
'+' ||
|
|
1142
|
+
character ==
|
|
1143
|
+
'?' ||
|
|
1144
|
+
character ==
|
|
1145
|
+
'|' ||
|
|
1146
|
+
character ==
|
|
1147
|
+
'{' ||
|
|
1148
|
+
character ==
|
|
1149
|
+
'.' ||
|
|
1150
|
+
character ==
|
|
1151
|
+
'^' ||
|
|
1152
|
+
character == '$';
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (
|
|
1156
|
+
character ==
|
|
1157
|
+
'[' ||
|
|
1158
|
+
(state->regex_state == REGEX_BRACKET_FIRST && character == '^') ||
|
|
1159
|
+
(state->regex_state == REGEX_BRACKET_BODY && character == '-') ||
|
|
1160
|
+
(state->regex_state == REGEX_BRACKET_BODY && character == ']')
|
|
1161
|
+
) {
|
|
1162
|
+
return true;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
static enum LiteralScanResult
|
|
1169
|
+
scan_regex_literal(TSLexer *lexer, ScannerState *state) {
|
|
1170
|
+
lexer->mark_end(lexer);
|
|
1171
|
+
|
|
1172
|
+
if (lexer->eof(lexer) || lexer->lookahead == '\n') {
|
|
1173
|
+
return LITERAL_SCAN_LINE_END;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
if (regex_literal_boundary(state, lexer->lookahead)) {
|
|
1177
|
+
return LITERAL_SCAN_NONE;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const int32_t character = lexer->lookahead;
|
|
1181
|
+
consume(lexer);
|
|
1182
|
+
if (regex_is_inside_bracket(state)) {
|
|
1183
|
+
begin_single_bracket_element(state, character);
|
|
1184
|
+
}
|
|
1185
|
+
update_bracket_state_after_literal(state, character);
|
|
1186
|
+
return LITERAL_SCAN_TOKEN;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
static TSSymbol
|
|
1190
|
+
regex_unterminated_symbol(enum ScannerMode mode, bool at_end_of_source) {
|
|
1191
|
+
if (mode == MODE_REGEX_ADDRESS) {
|
|
1192
|
+
return at_end_of_source ? REGEX_UNTERMINATED_ADDRESS
|
|
1193
|
+
: REGEX_LINE_UNTERMINATED_ADDRESS;
|
|
1194
|
+
}
|
|
1195
|
+
return at_end_of_source ? REGEX_UNTERMINATED_SUBSTITUTE
|
|
1196
|
+
: REGEX_LINE_UNTERMINATED_SUBSTITUTE;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
static bool emit_unterminated(
|
|
1200
|
+
ScannerState *state,
|
|
1201
|
+
const bool *valid_symbols,
|
|
1202
|
+
TSSymbol candidate,
|
|
1203
|
+
TSSymbol *symbol
|
|
1204
|
+
) {
|
|
1205
|
+
if (!emit_symbol(valid_symbols, candidate, symbol)) {
|
|
1206
|
+
return false;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
reset_state(state);
|
|
1210
|
+
return true;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
static bool scan_regex_bracket_opener(
|
|
1214
|
+
TSLexer *lexer,
|
|
1215
|
+
ScannerState *state,
|
|
1216
|
+
const bool *valid_symbols,
|
|
1217
|
+
TSSymbol *symbol
|
|
1218
|
+
) {
|
|
1219
|
+
lexer->mark_end(lexer);
|
|
1220
|
+
advance(lexer);
|
|
1221
|
+
|
|
1222
|
+
if (
|
|
1223
|
+
valid_symbols[NONPORTABLE_RANGE_END_MARKER] &&
|
|
1224
|
+
(lexer->lookahead == ':' || lexer->lookahead == '=')
|
|
1225
|
+
) {
|
|
1226
|
+
*symbol = NONPORTABLE_RANGE_END_MARKER;
|
|
1227
|
+
return true;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
lexer->mark_end(lexer);
|
|
1231
|
+
|
|
1232
|
+
TSSymbol candidate;
|
|
1233
|
+
switch (lexer->lookahead) {
|
|
1234
|
+
case ':':
|
|
1235
|
+
candidate = REGEX_OPEN_COLON;
|
|
1236
|
+
break;
|
|
1237
|
+
case '.':
|
|
1238
|
+
candidate = REGEX_OPEN_DOT;
|
|
1239
|
+
break;
|
|
1240
|
+
case '=':
|
|
1241
|
+
candidate = REGEX_OPEN_EQUAL;
|
|
1242
|
+
break;
|
|
1243
|
+
default:
|
|
1244
|
+
begin_single_bracket_element(state, '[');
|
|
1245
|
+
finish_first_bracket_element(state);
|
|
1246
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_LITERAL, symbol);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
if (!valid_symbols[candidate]) {
|
|
1250
|
+
return false;
|
|
1251
|
+
}
|
|
1252
|
+
consume(lexer);
|
|
1253
|
+
begin_compound_bracket_element(state);
|
|
1254
|
+
finish_first_bracket_element(state);
|
|
1255
|
+
state->regex_bracket_term_state = candidate == REGEX_OPEN_COLON
|
|
1256
|
+
? REGEX_BRACKET_TERM_COLON
|
|
1257
|
+
: candidate == REGEX_OPEN_DOT ? REGEX_BRACKET_TERM_DOT
|
|
1258
|
+
: REGEX_BRACKET_TERM_EQUAL;
|
|
1259
|
+
*symbol = candidate;
|
|
1260
|
+
return true;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
static void record_bracket_term_character(
|
|
1264
|
+
uint8_t *character_count,
|
|
1265
|
+
int32_t *single_character,
|
|
1266
|
+
int32_t character
|
|
1267
|
+
) {
|
|
1268
|
+
if (*character_count == 0) {
|
|
1269
|
+
*single_character = character;
|
|
1270
|
+
}
|
|
1271
|
+
if (*character_count < 2U) {
|
|
1272
|
+
(*character_count)++;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
static bool bracket_meta_character(int32_t character) {
|
|
1277
|
+
return character == '^' || character == '-' || character == ']';
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
static TSSymbol regex_bracket_term_content_symbol(
|
|
1281
|
+
const ScannerState *state,
|
|
1282
|
+
uint8_t character_count,
|
|
1283
|
+
int32_t single_character
|
|
1284
|
+
) {
|
|
1285
|
+
if (state->regex_bracket_term_state == REGEX_BRACKET_TERM_COLON) {
|
|
1286
|
+
return REGEX_CLASS_NAME;
|
|
1287
|
+
}
|
|
1288
|
+
if (character_count > 1U) {
|
|
1289
|
+
return REGEX_COLL_ELEM_MULTI;
|
|
1290
|
+
}
|
|
1291
|
+
if (
|
|
1292
|
+
state->regex_bracket_term_state ==
|
|
1293
|
+
REGEX_BRACKET_TERM_DOT &&
|
|
1294
|
+
bracket_meta_character(single_character)
|
|
1295
|
+
) {
|
|
1296
|
+
return REGEX_META_CHAR;
|
|
1297
|
+
}
|
|
1298
|
+
return REGEX_COLL_ELEM_SINGLE;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
static bool scan_regex_bracket_term_content(
|
|
1302
|
+
TSLexer *lexer,
|
|
1303
|
+
ScannerState *state,
|
|
1304
|
+
int32_t close_marker,
|
|
1305
|
+
const bool *valid_symbols,
|
|
1306
|
+
TSSymbol *symbol
|
|
1307
|
+
) {
|
|
1308
|
+
uint8_t character_count = 0;
|
|
1309
|
+
int32_t single_character = 0;
|
|
1310
|
+
bool stopped_at_close = false;
|
|
1311
|
+
lexer->mark_end(lexer);
|
|
1312
|
+
|
|
1313
|
+
if (
|
|
1314
|
+
lexer->lookahead ==
|
|
1315
|
+
']' &&
|
|
1316
|
+
state->regex_bracket_term_state != REGEX_BRACKET_TERM_COLON
|
|
1317
|
+
) {
|
|
1318
|
+
advance(lexer);
|
|
1319
|
+
lexer->mark_end(lexer);
|
|
1320
|
+
record_bracket_term_character(&character_count, &single_character, ']');
|
|
1321
|
+
if (lexer->lookahead == close_marker) {
|
|
1322
|
+
advance(lexer);
|
|
1323
|
+
if (lexer->lookahead == ']') {
|
|
1324
|
+
const TSSymbol candidate = regex_bracket_term_content_symbol(
|
|
1325
|
+
state,
|
|
1326
|
+
character_count,
|
|
1327
|
+
single_character
|
|
1328
|
+
);
|
|
1329
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1330
|
+
}
|
|
1331
|
+
lexer->mark_end(lexer);
|
|
1332
|
+
record_bracket_term_character(
|
|
1333
|
+
&character_count,
|
|
1334
|
+
&single_character,
|
|
1335
|
+
close_marker
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
for (;;) {
|
|
1341
|
+
if (
|
|
1342
|
+
lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
|
|
1343
|
+
) {
|
|
1344
|
+
break;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
if (lexer->lookahead == close_marker) {
|
|
1348
|
+
advance(lexer);
|
|
1349
|
+
if (lexer->lookahead == ']') {
|
|
1350
|
+
stopped_at_close = true;
|
|
1351
|
+
break;
|
|
1352
|
+
}
|
|
1353
|
+
lexer->mark_end(lexer);
|
|
1354
|
+
record_bracket_term_character(
|
|
1355
|
+
&character_count,
|
|
1356
|
+
&single_character,
|
|
1357
|
+
close_marker
|
|
1358
|
+
);
|
|
1359
|
+
continue;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
const int32_t character = lexer->lookahead;
|
|
1363
|
+
consume(lexer);
|
|
1364
|
+
record_bracket_term_character(
|
|
1365
|
+
&character_count,
|
|
1366
|
+
&single_character,
|
|
1367
|
+
character
|
|
1368
|
+
);
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
if (character_count == 0) {
|
|
1372
|
+
if (!stopped_at_close) {
|
|
1373
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
1374
|
+
finish_compound_bracket_element(state);
|
|
1375
|
+
}
|
|
1376
|
+
return emit_symbol(valid_symbols, REGEX_MALFORMED_BRACKET_TERM, symbol);
|
|
1377
|
+
}
|
|
1378
|
+
const TSSymbol candidate =
|
|
1379
|
+
regex_bracket_term_content_symbol(state, character_count, single_character);
|
|
1380
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
static bool scan_regex_bracket_term_close(
|
|
1384
|
+
TSLexer *lexer,
|
|
1385
|
+
ScannerState *state,
|
|
1386
|
+
int32_t marker,
|
|
1387
|
+
TSSymbol candidate,
|
|
1388
|
+
const bool *valid_symbols,
|
|
1389
|
+
TSSymbol *symbol
|
|
1390
|
+
) {
|
|
1391
|
+
if (lexer->lookahead != marker) {
|
|
1392
|
+
return false;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
advance(lexer);
|
|
1396
|
+
if (lexer->lookahead != ']') {
|
|
1397
|
+
return false;
|
|
1398
|
+
}
|
|
1399
|
+
consume(lexer);
|
|
1400
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
1401
|
+
finish_compound_bracket_element(state);
|
|
1402
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
enum RegexIntervalPartResult {
|
|
1406
|
+
REGEX_INTERVAL_PART_END,
|
|
1407
|
+
REGEX_INTERVAL_PART_ESCAPED_CLOSE,
|
|
1408
|
+
REGEX_INTERVAL_PART_INVALID,
|
|
1409
|
+
};
|
|
1410
|
+
|
|
1411
|
+
static enum RegexIntervalPartResult scan_regex_interval_digits(
|
|
1412
|
+
TSLexer *lexer,
|
|
1413
|
+
const ScannerState *state,
|
|
1414
|
+
bool escaped_close,
|
|
1415
|
+
bool *has_digits
|
|
1416
|
+
) {
|
|
1417
|
+
for (;;) {
|
|
1418
|
+
if (is_digit(lexer->lookahead) && lexer->lookahead != state->delimiter) {
|
|
1419
|
+
advance(lexer);
|
|
1420
|
+
if (has_digits != NULL) {
|
|
1421
|
+
*has_digits = true;
|
|
1422
|
+
}
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
if (escaped_close && lexer->lookahead == '\\') {
|
|
1427
|
+
advance(lexer);
|
|
1428
|
+
if (lexer->lookahead == '}' && state->delimiter != '}') {
|
|
1429
|
+
return REGEX_INTERVAL_PART_ESCAPED_CLOSE;
|
|
1430
|
+
}
|
|
1431
|
+
advance_past_escaped_character(lexer);
|
|
1432
|
+
return REGEX_INTERVAL_PART_INVALID;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
return REGEX_INTERVAL_PART_END;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
static bool
|
|
1440
|
+
scan_regex_interval_separator(TSLexer *lexer, const ScannerState *state) {
|
|
1441
|
+
if (lexer->lookahead != ',' || state->delimiter == ',') {
|
|
1442
|
+
return false;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
advance(lexer);
|
|
1446
|
+
return true;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
static bool scan_regex_interval_tail(
|
|
1450
|
+
TSLexer *lexer,
|
|
1451
|
+
const ScannerState *state,
|
|
1452
|
+
bool escaped_close
|
|
1453
|
+
) {
|
|
1454
|
+
bool has_minimum = false;
|
|
1455
|
+
enum RegexIntervalPartResult result =
|
|
1456
|
+
scan_regex_interval_digits(lexer, state, escaped_close, &has_minimum);
|
|
1457
|
+
if (result == REGEX_INTERVAL_PART_INVALID) {
|
|
1458
|
+
return false;
|
|
1459
|
+
}
|
|
1460
|
+
if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
|
|
1461
|
+
advance(lexer);
|
|
1462
|
+
return has_minimum;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
const bool has_separator = scan_regex_interval_separator(lexer, state);
|
|
1466
|
+
if (!has_minimum) {
|
|
1467
|
+
return false;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if (has_separator) {
|
|
1471
|
+
result = scan_regex_interval_digits(lexer, state, escaped_close, NULL);
|
|
1472
|
+
if (result == REGEX_INTERVAL_PART_INVALID) {
|
|
1473
|
+
return false;
|
|
1474
|
+
}
|
|
1475
|
+
if (result == REGEX_INTERVAL_PART_ESCAPED_CLOSE) {
|
|
1476
|
+
advance(lexer);
|
|
1477
|
+
return true;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
if (escaped_close) {
|
|
1482
|
+
if (lexer->lookahead != '\\') {
|
|
1483
|
+
return false;
|
|
1484
|
+
}
|
|
1485
|
+
advance(lexer);
|
|
1486
|
+
if (lexer->lookahead != '}' || state->delimiter == '}') {
|
|
1487
|
+
advance_past_escaped_character(lexer);
|
|
1488
|
+
return false;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if (lexer->lookahead != '}' || state->delimiter == '}') {
|
|
1493
|
+
return false;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
advance(lexer);
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
static bool scan_regex_interval(
|
|
1501
|
+
TSLexer *lexer,
|
|
1502
|
+
ScannerState *state,
|
|
1503
|
+
const bool *valid_symbols,
|
|
1504
|
+
TSSymbol *symbol
|
|
1505
|
+
) {
|
|
1506
|
+
advance(lexer);
|
|
1507
|
+
lexer->mark_end(lexer);
|
|
1508
|
+
state->regex_interval_state = REGEX_INTERVAL_EXPECT_MINIMUM;
|
|
1509
|
+
return emit_symbol(valid_symbols, REGEX_INTERVAL_OPEN, symbol);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
static bool
|
|
1513
|
+
scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state);
|
|
1514
|
+
|
|
1515
|
+
#if !SED_REGEX_EXTENDED
|
|
1516
|
+
static bool scan_regex_after_backslash(
|
|
1517
|
+
TSLexer *lexer,
|
|
1518
|
+
ScannerState *state,
|
|
1519
|
+
const bool *valid_symbols,
|
|
1520
|
+
TSSymbol *symbol
|
|
1521
|
+
);
|
|
1522
|
+
#endif
|
|
1523
|
+
|
|
1524
|
+
static bool raw_duplication_symbol_follows(
|
|
1525
|
+
const TSLexer *lexer,
|
|
1526
|
+
const ScannerState *state
|
|
1527
|
+
) {
|
|
1528
|
+
#if SED_REGEX_EXTENDED
|
|
1529
|
+
(void)state;
|
|
1530
|
+
return lexer->lookahead ==
|
|
1531
|
+
'*' ||
|
|
1532
|
+
lexer->lookahead ==
|
|
1533
|
+
'+' ||
|
|
1534
|
+
lexer->lookahead == '?';
|
|
1535
|
+
#else
|
|
1536
|
+
return lexer->lookahead == '*' && !state->regex_at_branch_start;
|
|
1537
|
+
#endif
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
enum DuplicationContextScan {
|
|
1541
|
+
DUPLICATION_CONTEXT_SKIPPED,
|
|
1542
|
+
DUPLICATION_CONTEXT_TOKEN,
|
|
1543
|
+
DUPLICATION_CONTEXT_CONSUMED,
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
static enum DuplicationContextScan scan_regex_duplication_context_marker(
|
|
1547
|
+
TSLexer *lexer,
|
|
1548
|
+
ScannerState *state,
|
|
1549
|
+
const bool *valid_symbols,
|
|
1550
|
+
TSSymbol *symbol
|
|
1551
|
+
) {
|
|
1552
|
+
TSSymbol candidate;
|
|
1553
|
+
if (state->regex_at_branch_start) {
|
|
1554
|
+
candidate = REGEX_LEADING_DUPLICATION_MARKER;
|
|
1555
|
+
} else if (state->regex_duplication_state != REGEX_DUPLICATION_NONE) {
|
|
1556
|
+
#if SED_REGEX_EXTENDED
|
|
1557
|
+
if (
|
|
1558
|
+
state->regex_duplication_state ==
|
|
1559
|
+
REGEX_AFTER_DUPLICATION_SYMBOL &&
|
|
1560
|
+
lexer->lookahead == '?'
|
|
1561
|
+
) {
|
|
1562
|
+
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1563
|
+
}
|
|
1564
|
+
#endif
|
|
1565
|
+
candidate = REGEX_ADJACENT_DUPLICATION_MARKER;
|
|
1566
|
+
} else {
|
|
1567
|
+
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
if (!valid_symbols[candidate]) {
|
|
1571
|
+
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
lexer->mark_end(lexer);
|
|
1575
|
+
if (raw_duplication_symbol_follows(lexer, state)) {
|
|
1576
|
+
*symbol = candidate;
|
|
1577
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
#if SED_REGEX_EXTENDED
|
|
1581
|
+
if (lexer->lookahead != '{' || state->delimiter == '{') {
|
|
1582
|
+
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1583
|
+
}
|
|
1584
|
+
advance(lexer);
|
|
1585
|
+
if (scan_regex_interval_tail(lexer, state, false)) {
|
|
1586
|
+
*symbol = candidate;
|
|
1587
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1588
|
+
}
|
|
1589
|
+
#else
|
|
1590
|
+
if (lexer->lookahead != '\\') {
|
|
1591
|
+
return DUPLICATION_CONTEXT_SKIPPED;
|
|
1592
|
+
}
|
|
1593
|
+
advance(lexer);
|
|
1594
|
+
if (lexer->lookahead != '{' || state->delimiter == '{') {
|
|
1595
|
+
return scan_regex_after_backslash(lexer, state, valid_symbols, symbol)
|
|
1596
|
+
? DUPLICATION_CONTEXT_TOKEN
|
|
1597
|
+
: DUPLICATION_CONTEXT_CONSUMED;
|
|
1598
|
+
}
|
|
1599
|
+
advance(lexer);
|
|
1600
|
+
if (scan_regex_interval_tail(lexer, state, true)) {
|
|
1601
|
+
*symbol = candidate;
|
|
1602
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1603
|
+
}
|
|
1604
|
+
#endif
|
|
1605
|
+
|
|
1606
|
+
if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
|
|
1607
|
+
lexer->mark_end(lexer);
|
|
1608
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1609
|
+
*symbol = REGEX_INCOMPLETE_INTERVAL;
|
|
1610
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
|
|
1614
|
+
*symbol = candidate;
|
|
1615
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1616
|
+
}
|
|
1617
|
+
scan_invalid_interval_remainder(lexer, state);
|
|
1618
|
+
lexer->mark_end(lexer);
|
|
1619
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1620
|
+
*symbol = REGEX_INVALID_INTERVAL;
|
|
1621
|
+
return DUPLICATION_CONTEXT_TOKEN;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
static bool scan_raw_regex_operator(
|
|
1625
|
+
TSLexer *lexer,
|
|
1626
|
+
ScannerState *state,
|
|
1627
|
+
const bool *valid_symbols,
|
|
1628
|
+
TSSymbol *symbol
|
|
1629
|
+
) {
|
|
1630
|
+
const int32_t character = lexer->lookahead;
|
|
1631
|
+
|
|
1632
|
+
if (character == '{') {
|
|
1633
|
+
#if SED_REGEX_EXTENDED
|
|
1634
|
+
return scan_regex_interval(lexer, state, valid_symbols, symbol);
|
|
1635
|
+
#else
|
|
1636
|
+
consume(lexer);
|
|
1637
|
+
return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
|
|
1638
|
+
#endif
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
consume(lexer);
|
|
1642
|
+
|
|
1643
|
+
if (character == '*') {
|
|
1644
|
+
#if SED_REGEX_EXTENDED
|
|
1645
|
+
return emit_symbol(valid_symbols, REGEX_ZERO_OR_MORE, symbol);
|
|
1646
|
+
#else
|
|
1647
|
+
return emit_symbol(
|
|
1648
|
+
valid_symbols,
|
|
1649
|
+
state->regex_at_branch_start ? REGEX_LITERAL : REGEX_ZERO_OR_MORE,
|
|
1650
|
+
symbol
|
|
1651
|
+
);
|
|
1652
|
+
#endif
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
#if SED_REGEX_EXTENDED
|
|
1656
|
+
if (character == '(') {
|
|
1657
|
+
return emit_symbol(valid_symbols, REGEX_GROUP_OPEN, symbol);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
if (character == ')') {
|
|
1661
|
+
return emit_symbol(
|
|
1662
|
+
valid_symbols,
|
|
1663
|
+
state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE : REGEX_LITERAL,
|
|
1664
|
+
symbol
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
if (character == '|') {
|
|
1669
|
+
return emit_symbol(valid_symbols, REGEX_ALTERNATION_OPERATOR, symbol);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
if (character == '+') {
|
|
1673
|
+
return emit_symbol(valid_symbols, REGEX_ONE_OR_MORE, symbol);
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
if (character == '?') {
|
|
1677
|
+
if (
|
|
1678
|
+
state->regex_duplication_state ==
|
|
1679
|
+
REGEX_AFTER_DUPLICATION_SYMBOL &&
|
|
1680
|
+
valid_symbols[REGEX_REPETITION_MODIFIER]
|
|
1681
|
+
) {
|
|
1682
|
+
return emit_symbol(valid_symbols, REGEX_REPETITION_MODIFIER, symbol);
|
|
1683
|
+
}
|
|
1684
|
+
return emit_symbol(valid_symbols, REGEX_ZERO_OR_ONE, symbol);
|
|
1685
|
+
}
|
|
1686
|
+
#endif
|
|
1687
|
+
|
|
1688
|
+
return emit_symbol(valid_symbols, REGEX_LITERAL, symbol);
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
static bool regex_delimiter_is_special(int32_t character) {
|
|
1692
|
+
#if SED_REGEX_EXTENDED
|
|
1693
|
+
return character ==
|
|
1694
|
+
'.' ||
|
|
1695
|
+
character ==
|
|
1696
|
+
'[' ||
|
|
1697
|
+
character ==
|
|
1698
|
+
'(' ||
|
|
1699
|
+
character ==
|
|
1700
|
+
')' ||
|
|
1701
|
+
character ==
|
|
1702
|
+
'*' ||
|
|
1703
|
+
character ==
|
|
1704
|
+
'+' ||
|
|
1705
|
+
character ==
|
|
1706
|
+
'?' ||
|
|
1707
|
+
character ==
|
|
1708
|
+
'{' ||
|
|
1709
|
+
character ==
|
|
1710
|
+
'|' ||
|
|
1711
|
+
character ==
|
|
1712
|
+
'^' ||
|
|
1713
|
+
character == '$';
|
|
1714
|
+
#else
|
|
1715
|
+
return character ==
|
|
1716
|
+
'.' ||
|
|
1717
|
+
character ==
|
|
1718
|
+
'[' ||
|
|
1719
|
+
character ==
|
|
1720
|
+
'*' ||
|
|
1721
|
+
character ==
|
|
1722
|
+
'^' ||
|
|
1723
|
+
character == '$';
|
|
1724
|
+
#endif
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
static bool scan_regex_escaped_delimiter(
|
|
1728
|
+
TSLexer *lexer,
|
|
1729
|
+
const bool *valid_symbols,
|
|
1730
|
+
TSSymbol *symbol
|
|
1731
|
+
) {
|
|
1732
|
+
const bool special = regex_delimiter_is_special(lexer->lookahead);
|
|
1733
|
+
consume(lexer);
|
|
1734
|
+
return emit_symbol(
|
|
1735
|
+
valid_symbols,
|
|
1736
|
+
special ? REGEX_SPECIAL_ESCAPED_DELIMITER : REGEX_ESCAPED_DELIMITER,
|
|
1737
|
+
symbol
|
|
1738
|
+
);
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
static bool scan_regex_escape_after_backslash(
|
|
1742
|
+
TSLexer *lexer,
|
|
1743
|
+
ScannerState *state,
|
|
1744
|
+
const bool *valid_symbols,
|
|
1745
|
+
TSSymbol *symbol
|
|
1746
|
+
) {
|
|
1747
|
+
if (lexer->eof(lexer)) {
|
|
1748
|
+
return emit_symbol(valid_symbols, REGEX_INCOMPLETE_ESCAPE, symbol);
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
if (lexer->lookahead == '\n') {
|
|
1752
|
+
return emit_symbol(valid_symbols, REGEX_FORBIDDEN_NEWLINE_ESCAPE, symbol);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
if (lexer->lookahead == state->delimiter) {
|
|
1756
|
+
return scan_regex_escaped_delimiter(lexer, valid_symbols, symbol);
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
#if !SED_REGEX_EXTENDED
|
|
1760
|
+
if (lexer->lookahead == '}') {
|
|
1761
|
+
if (valid_symbols[REGEX_INTERVAL_CLOSE]) {
|
|
1762
|
+
consume(lexer);
|
|
1763
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1764
|
+
return emit_symbol(valid_symbols, REGEX_INTERVAL_CLOSE, symbol);
|
|
1765
|
+
}
|
|
1766
|
+
if (valid_symbols[REGEX_UNMATCHED_INTERVAL_CLOSE]) {
|
|
1767
|
+
consume(lexer);
|
|
1768
|
+
return emit_symbol(valid_symbols, REGEX_UNMATCHED_INTERVAL_CLOSE, symbol);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
#endif
|
|
1772
|
+
|
|
1773
|
+
if (lexer->lookahead == '(' || lexer->lookahead == ')') {
|
|
1774
|
+
#if !SED_REGEX_EXTENDED
|
|
1775
|
+
const int32_t character = lexer->lookahead;
|
|
1776
|
+
#endif
|
|
1777
|
+
consume(lexer);
|
|
1778
|
+
#if SED_REGEX_EXTENDED
|
|
1779
|
+
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1780
|
+
#else
|
|
1781
|
+
return character == '('
|
|
1782
|
+
? emit_symbol(valid_symbols, REGEX_GROUP_OPEN, symbol)
|
|
1783
|
+
: emit_symbol(
|
|
1784
|
+
valid_symbols,
|
|
1785
|
+
state->regex_group_depth > 0 ? REGEX_GROUP_CLOSE
|
|
1786
|
+
: REGEX_UNMATCHED_GROUP_CLOSE,
|
|
1787
|
+
symbol
|
|
1788
|
+
);
|
|
1789
|
+
#endif
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
if (lexer->lookahead >= '1' && lexer->lookahead <= '9') {
|
|
1793
|
+
#if SED_REGEX_EXTENDED
|
|
1794
|
+
consume(lexer);
|
|
1795
|
+
return emit_symbol(valid_symbols, REGEX_NONPORTABLE_ESCAPE, symbol);
|
|
1796
|
+
#else
|
|
1797
|
+
consume(lexer);
|
|
1798
|
+
return emit_symbol(valid_symbols, REGEX_BACKREFERENCE, symbol);
|
|
1799
|
+
#endif
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
if (lexer->lookahead == '{') {
|
|
1803
|
+
#if SED_REGEX_EXTENDED
|
|
1804
|
+
consume(lexer);
|
|
1805
|
+
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1806
|
+
#else
|
|
1807
|
+
return scan_regex_interval(lexer, state, valid_symbols, symbol);
|
|
1808
|
+
#endif
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
if (
|
|
1812
|
+
lexer->lookahead ==
|
|
1813
|
+
'+' ||
|
|
1814
|
+
lexer->lookahead ==
|
|
1815
|
+
'?' ||
|
|
1816
|
+
lexer->lookahead == '|'
|
|
1817
|
+
) {
|
|
1818
|
+
#if SED_REGEX_EXTENDED
|
|
1819
|
+
consume(lexer);
|
|
1820
|
+
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1821
|
+
#else
|
|
1822
|
+
const int32_t character = lexer->lookahead;
|
|
1823
|
+
consume(lexer);
|
|
1824
|
+
if (character == '|') {
|
|
1825
|
+
return emit_symbol(valid_symbols, REGEX_BRE_VERTICAL_LINE_ESCAPE, symbol);
|
|
1826
|
+
}
|
|
1827
|
+
return emit_symbol(
|
|
1828
|
+
valid_symbols,
|
|
1829
|
+
character == '?' ? REGEX_BRE_QUESTION_MARK_ESCAPE : REGEX_BRE_PLUS_ESCAPE,
|
|
1830
|
+
symbol
|
|
1831
|
+
);
|
|
1832
|
+
#endif
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
if (lexer->lookahead == 'n') {
|
|
1836
|
+
consume(lexer);
|
|
1837
|
+
return emit_symbol(valid_symbols, REGEX_NEWLINE_ESCAPE, symbol);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
const int32_t character = lexer->lookahead;
|
|
1841
|
+
const bool quotes_regex_syntax = character ==
|
|
1842
|
+
'.' ||
|
|
1843
|
+
character ==
|
|
1844
|
+
'*' ||
|
|
1845
|
+
character ==
|
|
1846
|
+
'^' ||
|
|
1847
|
+
character ==
|
|
1848
|
+
'$' ||
|
|
1849
|
+
character ==
|
|
1850
|
+
'[' ||
|
|
1851
|
+
character ==
|
|
1852
|
+
'\\' ||
|
|
1853
|
+
character ==
|
|
1854
|
+
']' ||
|
|
1855
|
+
(SED_REGEX_EXTENDED && character == '}');
|
|
1856
|
+
if (!quotes_regex_syntax) {
|
|
1857
|
+
consume(lexer);
|
|
1858
|
+
return emit_symbol(valid_symbols, REGEX_NONPORTABLE_ESCAPE, symbol);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
consume(lexer);
|
|
1862
|
+
return emit_symbol(valid_symbols, REGEX_QUOTED_ESCAPE, symbol);
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
#if !SED_REGEX_EXTENDED
|
|
1866
|
+
static bool scan_regex_after_backslash(
|
|
1867
|
+
TSLexer *lexer,
|
|
1868
|
+
ScannerState *state,
|
|
1869
|
+
const bool *valid_symbols,
|
|
1870
|
+
TSSymbol *symbol
|
|
1871
|
+
) {
|
|
1872
|
+
if (lexer->lookahead == state->delimiter) {
|
|
1873
|
+
return scan_regex_escaped_delimiter(lexer, valid_symbols, symbol);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
if (lexer->lookahead == ')' && valid_symbols[EMPTY_SUBEXPRESSION_MARKER]) {
|
|
1877
|
+
*symbol = EMPTY_SUBEXPRESSION_MARKER;
|
|
1878
|
+
return true;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
lexer->mark_end(lexer);
|
|
1882
|
+
return scan_regex_escape_after_backslash(lexer, state, valid_symbols, symbol);
|
|
1883
|
+
}
|
|
1884
|
+
#endif
|
|
1885
|
+
|
|
1886
|
+
static bool scan_regex_dup_count(
|
|
1887
|
+
TSLexer *lexer,
|
|
1888
|
+
ScannerState *state,
|
|
1889
|
+
const bool *valid_symbols,
|
|
1890
|
+
TSSymbol *symbol
|
|
1891
|
+
) {
|
|
1892
|
+
do {
|
|
1893
|
+
consume(lexer);
|
|
1894
|
+
} while (is_digit(lexer->lookahead) && lexer->lookahead != state->delimiter);
|
|
1895
|
+
|
|
1896
|
+
if (state->regex_interval_state == REGEX_INTERVAL_EXPECT_MINIMUM) {
|
|
1897
|
+
state->regex_interval_state = REGEX_INTERVAL_AFTER_MINIMUM;
|
|
1898
|
+
} else if (state->regex_interval_state == REGEX_INTERVAL_EXPECT_MAXIMUM) {
|
|
1899
|
+
state->regex_interval_state = REGEX_INTERVAL_AFTER_MAXIMUM;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
return emit_symbol(valid_symbols, REGEX_DUP_COUNT, symbol);
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
static bool
|
|
1906
|
+
scan_invalid_interval_remainder(TSLexer *lexer, ScannerState *state) {
|
|
1907
|
+
bool consumed_character = false;
|
|
1908
|
+
while (
|
|
1909
|
+
!lexer->eof(lexer) &&
|
|
1910
|
+
lexer->lookahead !=
|
|
1911
|
+
'\n' &&
|
|
1912
|
+
lexer->lookahead != state->delimiter
|
|
1913
|
+
) {
|
|
1914
|
+
const int32_t character = lexer->lookahead;
|
|
1915
|
+
consume(lexer);
|
|
1916
|
+
consumed_character = true;
|
|
1917
|
+
if (character == '}') {
|
|
1918
|
+
break;
|
|
1919
|
+
}
|
|
1920
|
+
if (character != '\\' || lexer->eof(lexer) || lexer->lookahead == '\n') {
|
|
1921
|
+
continue;
|
|
1922
|
+
}
|
|
1923
|
+
const int32_t escaped = lexer->lookahead;
|
|
1924
|
+
consume(lexer);
|
|
1925
|
+
if (!SED_REGEX_EXTENDED && escaped == '}') {
|
|
1926
|
+
break;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
if (consumed_character) {
|
|
1930
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
1931
|
+
}
|
|
1932
|
+
return consumed_character;
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
#if SED_REGEX_EXTENDED
|
|
1936
|
+
static bool scan_empty_regex_construct(
|
|
1937
|
+
TSLexer *lexer,
|
|
1938
|
+
const ScannerState *state,
|
|
1939
|
+
const bool *valid_symbols,
|
|
1940
|
+
TSSymbol *symbol
|
|
1941
|
+
) {
|
|
1942
|
+
if (
|
|
1943
|
+
state->regex_group_depth >
|
|
1944
|
+
0 &&
|
|
1945
|
+
lexer->lookahead ==
|
|
1946
|
+
')' &&
|
|
1947
|
+
valid_symbols[EMPTY_SUBEXPRESSION_MARKER]
|
|
1948
|
+
) {
|
|
1949
|
+
return emit_missing_marker(
|
|
1950
|
+
lexer,
|
|
1951
|
+
valid_symbols,
|
|
1952
|
+
EMPTY_SUBEXPRESSION_MARKER,
|
|
1953
|
+
symbol
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
if (
|
|
1957
|
+
valid_symbols[EMPTY_ALTERNATIVE_MARKER] &&
|
|
1958
|
+
(lexer->lookahead ==
|
|
1959
|
+
'|' ||
|
|
1960
|
+
(state->regex_group_depth > 0 && lexer->lookahead == ')'))
|
|
1961
|
+
) {
|
|
1962
|
+
return emit_missing_marker(
|
|
1963
|
+
lexer,
|
|
1964
|
+
valid_symbols,
|
|
1965
|
+
EMPTY_ALTERNATIVE_MARKER,
|
|
1966
|
+
symbol
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
#endif
|
|
1972
|
+
|
|
1973
|
+
static bool scan_regex_token(
|
|
1974
|
+
TSLexer *lexer,
|
|
1975
|
+
ScannerState *state,
|
|
1976
|
+
const bool *valid_symbols,
|
|
1977
|
+
TSSymbol *symbol
|
|
1978
|
+
) {
|
|
1979
|
+
switch (scan_regex_duplication_context_marker(
|
|
1980
|
+
lexer,
|
|
1981
|
+
state,
|
|
1982
|
+
valid_symbols,
|
|
1983
|
+
symbol
|
|
1984
|
+
)) {
|
|
1985
|
+
case DUPLICATION_CONTEXT_TOKEN:
|
|
1986
|
+
return true;
|
|
1987
|
+
case DUPLICATION_CONTEXT_CONSUMED:
|
|
1988
|
+
return false;
|
|
1989
|
+
case DUPLICATION_CONTEXT_SKIPPED:
|
|
1990
|
+
break;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
#if !SED_REGEX_EXTENDED
|
|
1994
|
+
if (lexer->lookahead == '\\' && valid_symbols[EMPTY_SUBEXPRESSION_MARKER]) {
|
|
1995
|
+
lexer->mark_end(lexer);
|
|
1996
|
+
advance(lexer);
|
|
1997
|
+
return scan_regex_after_backslash(lexer, state, valid_symbols, symbol);
|
|
1998
|
+
}
|
|
1999
|
+
#else
|
|
2000
|
+
if (scan_empty_regex_construct(lexer, state, valid_symbols, symbol)) {
|
|
2001
|
+
return true;
|
|
2002
|
+
}
|
|
2003
|
+
#endif
|
|
2004
|
+
|
|
2005
|
+
if (
|
|
2006
|
+
valid_symbols[REGEX_DUP_COUNT] &&
|
|
2007
|
+
is_digit(lexer->lookahead) &&
|
|
2008
|
+
lexer->lookahead != state->delimiter
|
|
2009
|
+
) {
|
|
2010
|
+
return scan_regex_dup_count(lexer, state, valid_symbols, symbol);
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
if (
|
|
2014
|
+
valid_symbols[REGEX_INTERVAL_SEPARATOR] &&
|
|
2015
|
+
lexer->lookahead ==
|
|
2016
|
+
',' &&
|
|
2017
|
+
lexer->lookahead != state->delimiter
|
|
2018
|
+
) {
|
|
2019
|
+
consume(lexer);
|
|
2020
|
+
state->regex_interval_state = REGEX_INTERVAL_EXPECT_MAXIMUM;
|
|
2021
|
+
*symbol = REGEX_INTERVAL_SEPARATOR;
|
|
2022
|
+
return true;
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
#if SED_REGEX_EXTENDED
|
|
2026
|
+
if (
|
|
2027
|
+
valid_symbols[REGEX_INTERVAL_CLOSE] &&
|
|
2028
|
+
lexer->lookahead ==
|
|
2029
|
+
'}' &&
|
|
2030
|
+
lexer->lookahead != state->delimiter
|
|
2031
|
+
) {
|
|
2032
|
+
consume(lexer);
|
|
2033
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2034
|
+
*symbol = REGEX_INTERVAL_CLOSE;
|
|
2035
|
+
return true;
|
|
2036
|
+
}
|
|
2037
|
+
#else
|
|
2038
|
+
if (
|
|
2039
|
+
state->regex_interval_state !=
|
|
2040
|
+
REGEX_INTERVAL_NONE &&
|
|
2041
|
+
lexer->lookahead == '\\'
|
|
2042
|
+
) {
|
|
2043
|
+
advance(lexer);
|
|
2044
|
+
if (
|
|
2045
|
+
valid_symbols[REGEX_INTERVAL_CLOSE] &&
|
|
2046
|
+
lexer->lookahead ==
|
|
2047
|
+
'}' &&
|
|
2048
|
+
lexer->lookahead != state->delimiter
|
|
2049
|
+
) {
|
|
2050
|
+
consume(lexer);
|
|
2051
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2052
|
+
*symbol = REGEX_INTERVAL_CLOSE;
|
|
2053
|
+
return true;
|
|
2054
|
+
}
|
|
2055
|
+
if (lexer->eof(lexer) && valid_symbols[REGEX_INCOMPLETE_INTERVAL]) {
|
|
2056
|
+
lexer->mark_end(lexer);
|
|
2057
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2058
|
+
*symbol = REGEX_INCOMPLETE_INTERVAL;
|
|
2059
|
+
return true;
|
|
2060
|
+
}
|
|
2061
|
+
if (!valid_symbols[REGEX_INVALID_INTERVAL]) {
|
|
2062
|
+
return false;
|
|
2063
|
+
}
|
|
2064
|
+
if (lexer->lookahead == '}') {
|
|
2065
|
+
advance(lexer);
|
|
2066
|
+
} else {
|
|
2067
|
+
advance_past_escaped_character(lexer);
|
|
2068
|
+
scan_invalid_interval_remainder(lexer, state);
|
|
2069
|
+
}
|
|
2070
|
+
lexer->mark_end(lexer);
|
|
2071
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2072
|
+
*symbol = REGEX_INVALID_INTERVAL;
|
|
2073
|
+
return true;
|
|
2074
|
+
}
|
|
2075
|
+
#endif
|
|
2076
|
+
|
|
2077
|
+
if (
|
|
2078
|
+
state->regex_interval_state !=
|
|
2079
|
+
REGEX_INTERVAL_NONE &&
|
|
2080
|
+
valid_symbols[REGEX_INVALID_INTERVAL] &&
|
|
2081
|
+
scan_invalid_interval_remainder(lexer, state)
|
|
2082
|
+
) {
|
|
2083
|
+
*symbol = REGEX_INVALID_INTERVAL;
|
|
2084
|
+
return true;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
const bool inside_bracket = regex_is_inside_bracket(state);
|
|
2088
|
+
if (inside_bracket) {
|
|
2089
|
+
if (
|
|
2090
|
+
valid_symbols[REGEX_CLASS_NAME] ||
|
|
2091
|
+
valid_symbols[REGEX_COLL_ELEM_SINGLE] ||
|
|
2092
|
+
valid_symbols[REGEX_COLL_ELEM_MULTI] ||
|
|
2093
|
+
valid_symbols[REGEX_META_CHAR]
|
|
2094
|
+
) {
|
|
2095
|
+
const int32_t close_marker =
|
|
2096
|
+
state->regex_bracket_term_state == REGEX_BRACKET_TERM_COLON ? ':'
|
|
2097
|
+
: state->regex_bracket_term_state == REGEX_BRACKET_TERM_DOT ? '.'
|
|
2098
|
+
: '=';
|
|
2099
|
+
return scan_regex_bracket_term_content(
|
|
2100
|
+
lexer,
|
|
2101
|
+
state,
|
|
2102
|
+
close_marker,
|
|
2103
|
+
valid_symbols,
|
|
2104
|
+
symbol
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
if (
|
|
2108
|
+
state->regex_bracket_term_state !=
|
|
2109
|
+
REGEX_BRACKET_TERM_NONE &&
|
|
2110
|
+
lexer->lookahead ==
|
|
2111
|
+
']' &&
|
|
2112
|
+
valid_symbols[REGEX_MALFORMED_BRACKET_TERM]
|
|
2113
|
+
) {
|
|
2114
|
+
lexer->mark_end(lexer);
|
|
2115
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
2116
|
+
finish_compound_bracket_element(state);
|
|
2117
|
+
*symbol = REGEX_MALFORMED_BRACKET_TERM;
|
|
2118
|
+
return true;
|
|
2119
|
+
}
|
|
2120
|
+
if (valid_symbols[REGEX_COLON_CLOSE] && lexer->lookahead == ':') {
|
|
2121
|
+
return scan_regex_bracket_term_close(
|
|
2122
|
+
lexer,
|
|
2123
|
+
state,
|
|
2124
|
+
':',
|
|
2125
|
+
REGEX_COLON_CLOSE,
|
|
2126
|
+
valid_symbols,
|
|
2127
|
+
symbol
|
|
2128
|
+
);
|
|
2129
|
+
}
|
|
2130
|
+
if (valid_symbols[REGEX_DOT_CLOSE] && lexer->lookahead == '.') {
|
|
2131
|
+
return scan_regex_bracket_term_close(
|
|
2132
|
+
lexer,
|
|
2133
|
+
state,
|
|
2134
|
+
'.',
|
|
2135
|
+
REGEX_DOT_CLOSE,
|
|
2136
|
+
valid_symbols,
|
|
2137
|
+
symbol
|
|
2138
|
+
);
|
|
2139
|
+
}
|
|
2140
|
+
if (valid_symbols[REGEX_EQUAL_CLOSE] && lexer->lookahead == '=') {
|
|
2141
|
+
return scan_regex_bracket_term_close(
|
|
2142
|
+
lexer,
|
|
2143
|
+
state,
|
|
2144
|
+
'=',
|
|
2145
|
+
REGEX_EQUAL_CLOSE,
|
|
2146
|
+
valid_symbols,
|
|
2147
|
+
symbol
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
const enum LiteralScanResult literal_result =
|
|
2153
|
+
scan_regex_literal(lexer, state);
|
|
2154
|
+
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2155
|
+
return emit_symbol(
|
|
2156
|
+
valid_symbols,
|
|
2157
|
+
inside_bracket ? REGEX_BRACKET_LITERAL : REGEX_LITERAL,
|
|
2158
|
+
symbol
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2162
|
+
return emit_unterminated(
|
|
2163
|
+
state,
|
|
2164
|
+
valid_symbols,
|
|
2165
|
+
regex_unterminated_symbol(state->mode, lexer->eof(lexer)),
|
|
2166
|
+
symbol
|
|
2167
|
+
);
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
if (state->regex_state == REGEX_OUTSIDE_BRACKET) {
|
|
2171
|
+
if (lexer->lookahead == '^') {
|
|
2172
|
+
consume(lexer);
|
|
2173
|
+
#if !SED_REGEX_EXTENDED
|
|
2174
|
+
if (
|
|
2175
|
+
state->regex_group_depth >
|
|
2176
|
+
0 &&
|
|
2177
|
+
state->regex_at_branch_start &&
|
|
2178
|
+
!state->regex_after_anchor
|
|
2179
|
+
) {
|
|
2180
|
+
return emit_symbol(
|
|
2181
|
+
valid_symbols,
|
|
2182
|
+
REGEX_BRE_SUBEXPRESSION_CARET,
|
|
2183
|
+
symbol
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2186
|
+
#endif
|
|
2187
|
+
const bool is_beginning_anchor = SED_REGEX_EXTENDED ||
|
|
2188
|
+
(state->regex_at_branch_start && !state->regex_after_anchor);
|
|
2189
|
+
const TSSymbol candidate =
|
|
2190
|
+
is_beginning_anchor ? REGEX_BEGINNING_ANCHOR : REGEX_LITERAL;
|
|
2191
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
if (lexer->lookahead == '$') {
|
|
2195
|
+
bool inspected_bre_escape = false;
|
|
2196
|
+
consume(lexer);
|
|
2197
|
+
#if !SED_REGEX_EXTENDED
|
|
2198
|
+
if (lexer->lookahead == '\\') {
|
|
2199
|
+
inspected_bre_escape = true;
|
|
2200
|
+
advance(lexer);
|
|
2201
|
+
if (state->regex_group_depth > 0 && lexer->lookahead == ')') {
|
|
2202
|
+
return emit_symbol(
|
|
2203
|
+
valid_symbols,
|
|
2204
|
+
REGEX_BRE_SUBEXPRESSION_DOLLAR,
|
|
2205
|
+
symbol
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
#endif
|
|
2210
|
+
const bool at_branch_end = SED_REGEX_EXTENDED ||
|
|
2211
|
+
(!inspected_bre_escape &&
|
|
2212
|
+
(lexer->eof(lexer) ||
|
|
2213
|
+
lexer->lookahead ==
|
|
2214
|
+
'\n' ||
|
|
2215
|
+
lexer->lookahead == state->delimiter));
|
|
2216
|
+
const TSSymbol candidate =
|
|
2217
|
+
at_branch_end ? REGEX_END_ANCHOR : REGEX_LITERAL;
|
|
2218
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
if (lexer->lookahead == '.') {
|
|
2222
|
+
consume(lexer);
|
|
2223
|
+
return emit_symbol(valid_symbols, REGEX_PERIOD, symbol);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
if (lexer->lookahead == '\\') {
|
|
2227
|
+
advance(lexer);
|
|
2228
|
+
lexer->mark_end(lexer);
|
|
2229
|
+
return scan_regex_escape_after_backslash(
|
|
2230
|
+
lexer,
|
|
2231
|
+
state,
|
|
2232
|
+
valid_symbols,
|
|
2233
|
+
symbol
|
|
2234
|
+
);
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
if (
|
|
2238
|
+
lexer->lookahead ==
|
|
2239
|
+
'(' ||
|
|
2240
|
+
lexer->lookahead ==
|
|
2241
|
+
')' ||
|
|
2242
|
+
lexer->lookahead ==
|
|
2243
|
+
'*' ||
|
|
2244
|
+
lexer->lookahead ==
|
|
2245
|
+
'+' ||
|
|
2246
|
+
lexer->lookahead ==
|
|
2247
|
+
'?' ||
|
|
2248
|
+
lexer->lookahead ==
|
|
2249
|
+
'|' ||
|
|
2250
|
+
lexer->lookahead == '{'
|
|
2251
|
+
) {
|
|
2252
|
+
return scan_raw_regex_operator(lexer, state, valid_symbols, symbol);
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
if (lexer->lookahead == '[') {
|
|
2256
|
+
consume(lexer);
|
|
2257
|
+
reset_bracket_tracking(state);
|
|
2258
|
+
state->regex_state = REGEX_BRACKET_FIRST;
|
|
2259
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_OPEN, symbol);
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
return false;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
if (state->regex_state == REGEX_BRACKET_FIRST && lexer->lookahead == '^') {
|
|
2266
|
+
consume(lexer);
|
|
2267
|
+
state->regex_state = REGEX_BRACKET_AFTER_CARET;
|
|
2268
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_NEGATION, symbol);
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == ']') {
|
|
2272
|
+
commit_pending_bracket_element(state);
|
|
2273
|
+
if (
|
|
2274
|
+
bracket_expression_is_ambiguous(state) &&
|
|
2275
|
+
valid_symbols[AMBIGUOUS_BRACKET_EXPRESSION_MARKER]
|
|
2276
|
+
) {
|
|
2277
|
+
lexer->mark_end(lexer);
|
|
2278
|
+
*symbol = AMBIGUOUS_BRACKET_EXPRESSION_MARKER;
|
|
2279
|
+
return true;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
consume(lexer);
|
|
2283
|
+
state->regex_state = REGEX_OUTSIDE_BRACKET;
|
|
2284
|
+
reset_bracket_tracking(state);
|
|
2285
|
+
return emit_symbol(valid_symbols, REGEX_BRACKET_CLOSE, symbol);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
if (state->regex_state == REGEX_BRACKET_BODY && lexer->lookahead == '-') {
|
|
2289
|
+
lexer->mark_end(lexer);
|
|
2290
|
+
advance(lexer);
|
|
2291
|
+
if (
|
|
2292
|
+
valid_symbols[NONPORTABLE_RANGE_START_MARKER] &&
|
|
2293
|
+
!lexer->eof(lexer) &&
|
|
2294
|
+
lexer->lookahead !=
|
|
2295
|
+
'\n' &&
|
|
2296
|
+
lexer->lookahead != ']'
|
|
2297
|
+
) {
|
|
2298
|
+
*symbol = NONPORTABLE_RANGE_START_MARKER;
|
|
2299
|
+
return true;
|
|
2300
|
+
}
|
|
2301
|
+
lexer->mark_end(lexer);
|
|
2302
|
+
|
|
2303
|
+
TSSymbol candidate;
|
|
2304
|
+
if (valid_symbols[REGEX_BRACKET_RANGE_END_HYPHEN]) {
|
|
2305
|
+
candidate = REGEX_BRACKET_RANGE_END_HYPHEN;
|
|
2306
|
+
} else if (
|
|
2307
|
+
lexer->eof(lexer) || lexer->lookahead == '\n' || lexer->lookahead == ']'
|
|
2308
|
+
) {
|
|
2309
|
+
candidate = REGEX_BRACKET_TRAILING_HYPHEN;
|
|
2310
|
+
} else {
|
|
2311
|
+
candidate = REGEX_BRACKET_HYPHEN;
|
|
2312
|
+
}
|
|
2313
|
+
if (emit_symbol(valid_symbols, candidate, symbol)) {
|
|
2314
|
+
if (candidate == REGEX_BRACKET_RANGE_END_HYPHEN) {
|
|
2315
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
2316
|
+
state->regex_bracket_range_pending = false;
|
|
2317
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
2318
|
+
} else if (candidate == REGEX_BRACKET_TRAILING_HYPHEN) {
|
|
2319
|
+
commit_pending_bracket_element(state);
|
|
2320
|
+
record_bracket_element(state, REGEX_BRACKET_PENDING_OTHER);
|
|
2321
|
+
} else {
|
|
2322
|
+
state->regex_bracket_pending_element = REGEX_BRACKET_PENDING_NONE;
|
|
2323
|
+
state->regex_bracket_range_pending = true;
|
|
2324
|
+
}
|
|
2325
|
+
return true;
|
|
2326
|
+
}
|
|
2327
|
+
if (emit_symbol(valid_symbols, REGEX_SHARED_RANGE_ENDPOINT, symbol)) {
|
|
2328
|
+
commit_pending_bracket_element(state);
|
|
2329
|
+
state->regex_bracket_range_pending = false;
|
|
2330
|
+
return true;
|
|
2331
|
+
}
|
|
2332
|
+
return false;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
if (lexer->lookahead == '[') {
|
|
2336
|
+
return scan_regex_bracket_opener(lexer, state, valid_symbols, symbol);
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
return false;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
static enum LiteralScanResult scan_operand_literal(
|
|
2343
|
+
TSLexer *lexer,
|
|
2344
|
+
const ScannerState *state,
|
|
2345
|
+
bool ampersand_is_special
|
|
2346
|
+
) {
|
|
2347
|
+
bool consumed = false;
|
|
2348
|
+
lexer->mark_end(lexer);
|
|
2349
|
+
|
|
2350
|
+
for (;;) {
|
|
2351
|
+
if (lexer->eof(lexer) || lexer->lookahead == '\n') {
|
|
2352
|
+
return consumed ? LITERAL_SCAN_TOKEN : LITERAL_SCAN_LINE_END;
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
if (
|
|
2356
|
+
lexer->lookahead ==
|
|
2357
|
+
state->delimiter ||
|
|
2358
|
+
lexer->lookahead ==
|
|
2359
|
+
'\\' ||
|
|
2360
|
+
(ampersand_is_special && lexer->lookahead == '&')
|
|
2361
|
+
) {
|
|
2362
|
+
return consumed ? LITERAL_SCAN_TOKEN : LITERAL_SCAN_NONE;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
consume(lexer);
|
|
2366
|
+
consumed = true;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
static bool scan_replacement_escape(
|
|
2371
|
+
TSLexer *lexer,
|
|
2372
|
+
const ScannerState *state,
|
|
2373
|
+
const bool *valid_symbols,
|
|
2374
|
+
TSSymbol *symbol
|
|
2375
|
+
) {
|
|
2376
|
+
advance(lexer);
|
|
2377
|
+
lexer->mark_end(lexer);
|
|
2378
|
+
|
|
2379
|
+
if (lexer->eof(lexer)) {
|
|
2380
|
+
return emit_symbol(valid_symbols, REPLACEMENT_INCOMPLETE_ESCAPE, symbol);
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
if (lexer->lookahead == '\n') {
|
|
2384
|
+
consume(lexer);
|
|
2385
|
+
return emit_symbol(valid_symbols, REPLACEMENT_ESCAPED_NEWLINE, symbol);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
TSSymbol candidate = REPLACEMENT_ESCAPE_SEQUENCE;
|
|
2389
|
+
if (
|
|
2390
|
+
lexer->lookahead !=
|
|
2391
|
+
state->delimiter &&
|
|
2392
|
+
lexer->lookahead !=
|
|
2393
|
+
'&' &&
|
|
2394
|
+
lexer->lookahead !=
|
|
2395
|
+
'\\' &&
|
|
2396
|
+
!is_digit(lexer->lookahead)
|
|
2397
|
+
) {
|
|
2398
|
+
consume(lexer);
|
|
2399
|
+
return emit_symbol(valid_symbols, REPLACEMENT_NONPORTABLE_ESCAPE, symbol);
|
|
2400
|
+
}
|
|
2401
|
+
if (lexer->lookahead == state->delimiter) {
|
|
2402
|
+
candidate = state->delimiter == '&'
|
|
2403
|
+
? REPLACEMENT_AMPERSAND_ESCAPED_DELIMITER
|
|
2404
|
+
: REPLACEMENT_ESCAPED_DELIMITER;
|
|
2405
|
+
} else if (is_digit(lexer->lookahead)) {
|
|
2406
|
+
candidate = REPLACEMENT_BACKREFERENCE;
|
|
2407
|
+
}
|
|
2408
|
+
|
|
2409
|
+
consume(lexer);
|
|
2410
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
static bool scan_replacement_token(
|
|
2414
|
+
TSLexer *lexer,
|
|
2415
|
+
ScannerState *state,
|
|
2416
|
+
const bool *valid_symbols,
|
|
2417
|
+
TSSymbol *symbol
|
|
2418
|
+
) {
|
|
2419
|
+
const enum LiteralScanResult literal_result =
|
|
2420
|
+
scan_operand_literal(lexer, state, true);
|
|
2421
|
+
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2422
|
+
return emit_symbol(valid_symbols, REPLACEMENT_LITERAL, symbol);
|
|
2423
|
+
}
|
|
2424
|
+
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2425
|
+
return emit_unterminated(
|
|
2426
|
+
state,
|
|
2427
|
+
valid_symbols,
|
|
2428
|
+
lexer->eof(lexer) ? REPLACEMENT_UNTERMINATED
|
|
2429
|
+
: REPLACEMENT_LINE_UNTERMINATED,
|
|
2430
|
+
symbol
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
if (lexer->lookahead == '\\') {
|
|
2435
|
+
return scan_replacement_escape(lexer, state, valid_symbols, symbol);
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2438
|
+
if (lexer->lookahead == '&') {
|
|
2439
|
+
consume(lexer);
|
|
2440
|
+
return emit_symbol(valid_symbols, REPLACEMENT_MATCH_REFERENCE, symbol);
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
return false;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
static TSSymbol
|
|
2447
|
+
translate_unterminated_symbol(enum ScannerMode mode, bool at_end_of_source) {
|
|
2448
|
+
if (mode == MODE_TRANSLATE_SOURCE) {
|
|
2449
|
+
return at_end_of_source ? TRANSLATE_UNTERMINATED_SOURCE
|
|
2450
|
+
: TRANSLATE_LINE_UNTERMINATED_SOURCE;
|
|
2451
|
+
}
|
|
2452
|
+
return at_end_of_source ? TRANSLATE_UNTERMINATED_DESTINATION
|
|
2453
|
+
: TRANSLATE_LINE_UNTERMINATED_DESTINATION;
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
static bool scan_translate_escape(
|
|
2457
|
+
TSLexer *lexer,
|
|
2458
|
+
const ScannerState *state,
|
|
2459
|
+
const bool *valid_symbols,
|
|
2460
|
+
TSSymbol *symbol
|
|
2461
|
+
) {
|
|
2462
|
+
advance(lexer);
|
|
2463
|
+
lexer->mark_end(lexer);
|
|
2464
|
+
|
|
2465
|
+
if (lexer->eof(lexer)) {
|
|
2466
|
+
return emit_symbol(valid_symbols, TRANSLATE_INCOMPLETE_ESCAPE, symbol);
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
if (lexer->lookahead == '\n') {
|
|
2470
|
+
return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
if (
|
|
2474
|
+
lexer->lookahead !=
|
|
2475
|
+
'n' &&
|
|
2476
|
+
lexer->lookahead !=
|
|
2477
|
+
'\\' &&
|
|
2478
|
+
(lexer->lookahead != state->delimiter || state->delimiter == 'n')
|
|
2479
|
+
) {
|
|
2480
|
+
consume(lexer);
|
|
2481
|
+
return emit_symbol(valid_symbols, TRANSLATE_NONPORTABLE_ESCAPE, symbol);
|
|
2482
|
+
}
|
|
2483
|
+
const TSSymbol candidate = lexer->lookahead == 'n' || lexer->lookahead == '\\'
|
|
2484
|
+
? TRANSLATE_ESCAPE
|
|
2485
|
+
: TRANSLATE_ESCAPED_DELIMITER;
|
|
2486
|
+
consume(lexer);
|
|
2487
|
+
return emit_symbol(valid_symbols, candidate, symbol);
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
static bool scan_translate_token(
|
|
2491
|
+
TSLexer *lexer,
|
|
2492
|
+
ScannerState *state,
|
|
2493
|
+
const bool *valid_symbols,
|
|
2494
|
+
TSSymbol *symbol
|
|
2495
|
+
) {
|
|
2496
|
+
const enum LiteralScanResult literal_result =
|
|
2497
|
+
scan_operand_literal(lexer, state, false);
|
|
2498
|
+
if (literal_result == LITERAL_SCAN_TOKEN) {
|
|
2499
|
+
return emit_symbol(valid_symbols, TRANSLATE_LITERAL, symbol);
|
|
2500
|
+
}
|
|
2501
|
+
if (literal_result == LITERAL_SCAN_LINE_END) {
|
|
2502
|
+
return emit_unterminated(
|
|
2503
|
+
state,
|
|
2504
|
+
valid_symbols,
|
|
2505
|
+
translate_unterminated_symbol(state->mode, lexer->eof(lexer)),
|
|
2506
|
+
symbol
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
if (lexer->lookahead == '\\') {
|
|
2511
|
+
return scan_translate_escape(lexer, state, valid_symbols, symbol);
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
return false;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
static bool sed_scanner_scan_impl(
|
|
2518
|
+
ScannerState *state,
|
|
2519
|
+
TSLexer *lexer,
|
|
2520
|
+
const bool *valid_symbols,
|
|
2521
|
+
TSSymbol *symbol
|
|
2522
|
+
) {
|
|
2523
|
+
if (valid_symbols[ERROR_SENTINEL]) {
|
|
2524
|
+
return false;
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
if (state->mode == MODE_TEXT) {
|
|
2528
|
+
return scan_text_token(lexer, state, valid_symbols, symbol);
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
#if !SED_REGEX_EXTENDED
|
|
2532
|
+
if (
|
|
2533
|
+
is_regex_mode(state->mode) &&
|
|
2534
|
+
(emit_missing_marker(
|
|
2535
|
+
lexer,
|
|
2536
|
+
valid_symbols,
|
|
2537
|
+
BRE_VERTICAL_LINE_ESCAPE_MARKER,
|
|
2538
|
+
symbol
|
|
2539
|
+
) ||
|
|
2540
|
+
emit_missing_marker(
|
|
2541
|
+
lexer,
|
|
2542
|
+
valid_symbols,
|
|
2543
|
+
BRE_QUESTION_MARK_ESCAPE_MARKER,
|
|
2544
|
+
symbol
|
|
2545
|
+
) ||
|
|
2546
|
+
emit_missing_marker(
|
|
2547
|
+
lexer,
|
|
2548
|
+
valid_symbols,
|
|
2549
|
+
BRE_PLUS_ESCAPE_MARKER,
|
|
2550
|
+
symbol
|
|
2551
|
+
) ||
|
|
2552
|
+
emit_missing_marker(
|
|
2553
|
+
lexer,
|
|
2554
|
+
valid_symbols,
|
|
2555
|
+
UNMATCHED_INTERVAL_CLOSE_MARKER,
|
|
2556
|
+
symbol
|
|
2557
|
+
))
|
|
2558
|
+
) {
|
|
2559
|
+
return true;
|
|
2560
|
+
}
|
|
2561
|
+
#endif
|
|
2562
|
+
|
|
2563
|
+
if (
|
|
2564
|
+
is_regex_mode(state->mode) &&
|
|
2565
|
+
state->regex_state ==
|
|
2566
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
2567
|
+
state->regex_group_depth >
|
|
2568
|
+
0 &&
|
|
2569
|
+
!state->regex_after_alternation &&
|
|
2570
|
+
(lexer->eof(lexer) ||
|
|
2571
|
+
lexer->lookahead ==
|
|
2572
|
+
'\n' ||
|
|
2573
|
+
lexer->lookahead == state->delimiter)
|
|
2574
|
+
) {
|
|
2575
|
+
const TSSymbol candidate = lexer->eof(lexer)
|
|
2576
|
+
? MISSING_SUBEXPRESSION_MARKER
|
|
2577
|
+
: MISSING_SUBEXPRESSION_PLACEHOLDER_MARKER;
|
|
2578
|
+
if (valid_symbols[candidate]) {
|
|
2579
|
+
lexer->mark_end(lexer);
|
|
2580
|
+
*symbol = candidate;
|
|
2581
|
+
return true;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
if (
|
|
2586
|
+
is_regex_mode(state->mode) &&
|
|
2587
|
+
(state->regex_state ==
|
|
2588
|
+
REGEX_BRACKET_FIRST ||
|
|
2589
|
+
state->regex_state == REGEX_BRACKET_AFTER_CARET) &&
|
|
2590
|
+
(lexer->eof(lexer) || lexer->lookahead == '\n')
|
|
2591
|
+
) {
|
|
2592
|
+
const TSSymbol candidate = lexer->eof(lexer)
|
|
2593
|
+
? INCOMPLETE_BRACKET_LIST_MARKER
|
|
2594
|
+
: MISSING_BRACKET_LIST_MARKER;
|
|
2595
|
+
if (valid_symbols[candidate]) {
|
|
2596
|
+
lexer->mark_end(lexer);
|
|
2597
|
+
*symbol = candidate;
|
|
2598
|
+
return true;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
if (
|
|
2603
|
+
is_regex_mode(state->mode) &&
|
|
2604
|
+
state->regex_bracket_term_state !=
|
|
2605
|
+
REGEX_BRACKET_TERM_NONE &&
|
|
2606
|
+
(lexer->eof(lexer) || lexer->lookahead == '\n')
|
|
2607
|
+
) {
|
|
2608
|
+
const TSSymbol candidate = lexer->eof(lexer) ? REGEX_INCOMPLETE_BRACKET_TERM
|
|
2609
|
+
: REGEX_MALFORMED_BRACKET_TERM;
|
|
2610
|
+
if (valid_symbols[candidate]) {
|
|
2611
|
+
lexer->mark_end(lexer);
|
|
2612
|
+
state->regex_bracket_term_state = REGEX_BRACKET_TERM_NONE;
|
|
2613
|
+
finish_compound_bracket_element(state);
|
|
2614
|
+
*symbol = candidate;
|
|
2615
|
+
return true;
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
if (
|
|
2620
|
+
is_regex_mode(state->mode) &&
|
|
2621
|
+
regex_is_inside_bracket(state) &&
|
|
2622
|
+
(lexer->eof(lexer) || lexer->lookahead == '\n')
|
|
2623
|
+
) {
|
|
2624
|
+
const TSSymbol candidate = lexer->eof(lexer)
|
|
2625
|
+
? INCOMPLETE_BRACKET_EXPRESSION_MARKER
|
|
2626
|
+
: UNCLOSED_BRACKET_EXPRESSION_MARKER;
|
|
2627
|
+
if (valid_symbols[candidate]) {
|
|
2628
|
+
lexer->mark_end(lexer);
|
|
2629
|
+
state->regex_state = REGEX_OUTSIDE_BRACKET;
|
|
2630
|
+
reset_bracket_tracking(state);
|
|
2631
|
+
*symbol = candidate;
|
|
2632
|
+
return true;
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
#if SED_REGEX_EXTENDED
|
|
2637
|
+
if (
|
|
2638
|
+
is_regex_mode(state->mode) &&
|
|
2639
|
+
state->regex_state ==
|
|
2640
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
2641
|
+
state->regex_after_alternation &&
|
|
2642
|
+
(lexer->lookahead ==
|
|
2643
|
+
state->delimiter ||
|
|
2644
|
+
lexer->lookahead ==
|
|
2645
|
+
'\n' ||
|
|
2646
|
+
lexer->eof(lexer))
|
|
2647
|
+
) {
|
|
2648
|
+
const TSSymbol candidate = lexer->eof(lexer) ? INCOMPLETE_ALTERNATIVE_MARKER
|
|
2649
|
+
: EMPTY_ALTERNATIVE_MARKER;
|
|
2650
|
+
if (valid_symbols[candidate]) {
|
|
2651
|
+
lexer->mark_end(lexer);
|
|
2652
|
+
state->regex_after_alternation = false;
|
|
2653
|
+
*symbol = candidate;
|
|
2654
|
+
return true;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
#endif
|
|
2658
|
+
|
|
2659
|
+
if (
|
|
2660
|
+
is_regex_mode(state->mode) &&
|
|
2661
|
+
state->regex_interval_state !=
|
|
2662
|
+
REGEX_INTERVAL_NONE &&
|
|
2663
|
+
(lexer->lookahead ==
|
|
2664
|
+
state->delimiter ||
|
|
2665
|
+
lexer->lookahead ==
|
|
2666
|
+
'\n' ||
|
|
2667
|
+
#if !SED_REGEX_EXTENDED
|
|
2668
|
+
(state->delimiter == '}' && lexer->lookahead == '\\') ||
|
|
2669
|
+
#endif
|
|
2670
|
+
lexer->eof(lexer))
|
|
2671
|
+
) {
|
|
2672
|
+
const TSSymbol candidate =
|
|
2673
|
+
lexer->eof(lexer) ? REGEX_INCOMPLETE_INTERVAL : REGEX_INVALID_INTERVAL;
|
|
2674
|
+
if (valid_symbols[candidate]) {
|
|
2675
|
+
lexer->mark_end(lexer);
|
|
2676
|
+
state->regex_interval_state = REGEX_INTERVAL_NONE;
|
|
2677
|
+
*symbol = candidate;
|
|
2678
|
+
return true;
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
if (
|
|
2683
|
+
is_regex_mode(state->mode) &&
|
|
2684
|
+
state->regex_state ==
|
|
2685
|
+
REGEX_OUTSIDE_BRACKET &&
|
|
2686
|
+
(lexer->lookahead == '\n' || lexer->eof(lexer))
|
|
2687
|
+
) {
|
|
2688
|
+
if (state->regex_group_depth > 0) {
|
|
2689
|
+
const TSSymbol candidate =
|
|
2690
|
+
lexer->eof(lexer) ? REGEX_INCOMPLETE_GROUP : REGEX_UNCLOSED_GROUP;
|
|
2691
|
+
if (valid_symbols[candidate]) {
|
|
2692
|
+
lexer->mark_end(lexer);
|
|
2693
|
+
state->regex_group_depth--;
|
|
2694
|
+
*symbol = candidate;
|
|
2695
|
+
return true;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
const bool delimiter_is_active = state->mode !=
|
|
2701
|
+
MODE_NONE &&
|
|
2702
|
+
state->mode !=
|
|
2703
|
+
MODE_TEXT &&
|
|
2704
|
+
lexer->lookahead ==
|
|
2705
|
+
state->delimiter &&
|
|
2706
|
+
(!is_regex_mode(state->mode) ||
|
|
2707
|
+
state->regex_state == REGEX_OUTSIDE_BRACKET);
|
|
2708
|
+
if (delimiter_is_active) {
|
|
2709
|
+
if (state->regex_group_depth > 0 && valid_symbols[REGEX_UNCLOSED_GROUP]) {
|
|
2710
|
+
state->regex_group_depth--;
|
|
2711
|
+
*symbol = REGEX_UNCLOSED_GROUP;
|
|
2712
|
+
return true;
|
|
2713
|
+
}
|
|
2714
|
+
return scan_active_mode_delimiter(lexer, state, valid_symbols, symbol);
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
switch (state->mode) {
|
|
2718
|
+
case MODE_REGEX_ADDRESS:
|
|
2719
|
+
case MODE_SUBSTITUTE_PATTERN:
|
|
2720
|
+
return scan_regex_token(lexer, state, valid_symbols, symbol);
|
|
2721
|
+
case MODE_SUBSTITUTE_REPLACEMENT:
|
|
2722
|
+
return scan_replacement_token(lexer, state, valid_symbols, symbol);
|
|
2723
|
+
case MODE_TRANSLATE_SOURCE:
|
|
2724
|
+
case MODE_TRANSLATE_DESTINATION:
|
|
2725
|
+
return scan_translate_token(lexer, state, valid_symbols, symbol);
|
|
2726
|
+
case MODE_TEXT:
|
|
2727
|
+
return false;
|
|
2728
|
+
case MODE_NONE:
|
|
2729
|
+
break;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
if (valid_symbols[LINE_WORD] && scan_to_physical_line_end(lexer, false)) {
|
|
2733
|
+
*symbol = LINE_WORD;
|
|
2734
|
+
return true;
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
if (
|
|
2738
|
+
valid_symbols[SUBSTITUTION_WFILE_ARGUMENT] &&
|
|
2739
|
+
scan_substitution_wfile_argument(lexer)
|
|
2740
|
+
) {
|
|
2741
|
+
*symbol = SUBSTITUTION_WFILE_ARGUMENT;
|
|
2742
|
+
return true;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
if (valid_symbols[FILE_ARGUMENT] && scan_file_argument(lexer)) {
|
|
2746
|
+
*symbol = FILE_ARGUMENT;
|
|
2747
|
+
return true;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
if (
|
|
2751
|
+
valid_symbols[INVALID_SUBSTITUTION_FLAG] &&
|
|
2752
|
+
!is_blank(lexer->lookahead) &&
|
|
2753
|
+
!is_digit(lexer->lookahead) &&
|
|
2754
|
+
lexer->lookahead !=
|
|
2755
|
+
'g' &&
|
|
2756
|
+
lexer->lookahead !=
|
|
2757
|
+
'i' &&
|
|
2758
|
+
lexer->lookahead !=
|
|
2759
|
+
'p' &&
|
|
2760
|
+
lexer->lookahead !=
|
|
2761
|
+
'w' &&
|
|
2762
|
+
lexer->lookahead !=
|
|
2763
|
+
';' &&
|
|
2764
|
+
lexer->lookahead !=
|
|
2765
|
+
'}' &&
|
|
2766
|
+
lexer->lookahead !=
|
|
2767
|
+
'\n' &&
|
|
2768
|
+
!lexer->eof(lexer)
|
|
2769
|
+
) {
|
|
2770
|
+
consume(lexer);
|
|
2771
|
+
*symbol = INVALID_SUBSTITUTION_FLAG;
|
|
2772
|
+
return true;
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2775
|
+
if (valid_symbols[TEXT_COMMAND_START] && lexer->lookahead == '\\') {
|
|
2776
|
+
if (scan_text_command_start(lexer, state)) {
|
|
2777
|
+
*symbol = TEXT_COMMAND_START;
|
|
2778
|
+
return true;
|
|
2779
|
+
}
|
|
2780
|
+
const TSSymbol introducer_marker = lexer->eof(lexer)
|
|
2781
|
+
? MISSING_TEXT_INTRODUCER_MARKER
|
|
2782
|
+
: NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
|
|
2783
|
+
return emit_symbol(valid_symbols, introducer_marker, symbol);
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
if (valid_symbols[DEFAULT_OUTPUT_SUPPRESSION] && lexer->lookahead == 'n') {
|
|
2787
|
+
consume(lexer);
|
|
2788
|
+
*symbol = DEFAULT_OUTPUT_SUPPRESSION;
|
|
2789
|
+
return true;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
if (valid_symbols[COMMENT_TEXT] && scan_to_physical_line_end(lexer, false)) {
|
|
2793
|
+
*symbol = COMMENT_TEXT;
|
|
2794
|
+
return true;
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
if (
|
|
2798
|
+
valid_symbols[RESERVED_UNKNOWN_FUNCTION] &&
|
|
2799
|
+
scan_reserved_unknown_function(lexer)
|
|
2800
|
+
) {
|
|
2801
|
+
*symbol = RESERVED_UNKNOWN_FUNCTION;
|
|
2802
|
+
return true;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
if (
|
|
2806
|
+
valid_symbols[REGEX_ADDRESS_START] &&
|
|
2807
|
+
lexer->lookahead ==
|
|
2808
|
+
'/' &&
|
|
2809
|
+
scan_simple_delimiter(lexer, state, MODE_REGEX_ADDRESS)
|
|
2810
|
+
) {
|
|
2811
|
+
*symbol = REGEX_ADDRESS_START;
|
|
2812
|
+
return true;
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
if (valid_symbols[ESCAPED_REGEX_ADDRESS_START]) {
|
|
2816
|
+
if (scan_simple_delimiter(lexer, state, MODE_REGEX_ADDRESS)) {
|
|
2817
|
+
*symbol = ESCAPED_REGEX_ADDRESS_START;
|
|
2818
|
+
return true;
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
|
|
2822
|
+
if (valid_symbols[SUBSTITUTE_START]) {
|
|
2823
|
+
if (scan_simple_delimiter(lexer, state, MODE_SUBSTITUTE_PATTERN)) {
|
|
2824
|
+
*symbol = SUBSTITUTE_START;
|
|
2825
|
+
return true;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
if (valid_symbols[TRANSLATE_START]) {
|
|
2830
|
+
if (scan_simple_delimiter(lexer, state, MODE_TRANSLATE_SOURCE)) {
|
|
2831
|
+
*symbol = TRANSLATE_START;
|
|
2832
|
+
return true;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
if (valid_symbols[RIGHT_BRACE] && scan_right_brace(lexer, state)) {
|
|
2837
|
+
*symbol = RIGHT_BRACE;
|
|
2838
|
+
return true;
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
if (
|
|
2842
|
+
emit_missing_marker(
|
|
2843
|
+
lexer,
|
|
2844
|
+
valid_symbols,
|
|
2845
|
+
OMITTED_FIRST_ADDRESS_MARKER,
|
|
2846
|
+
symbol
|
|
2847
|
+
)
|
|
2848
|
+
) {
|
|
2849
|
+
return true;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
if (
|
|
2853
|
+
valid_symbols[OMITTED_ADDRESS_MARKER] &&
|
|
2854
|
+
!can_start_address(lexer) &&
|
|
2855
|
+
!is_blank(lexer->lookahead)
|
|
2856
|
+
) {
|
|
2857
|
+
return emit_missing_marker(
|
|
2858
|
+
lexer,
|
|
2859
|
+
valid_symbols,
|
|
2860
|
+
OMITTED_ADDRESS_MARKER,
|
|
2861
|
+
symbol
|
|
2862
|
+
);
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
if (
|
|
2866
|
+
valid_symbols[ADDITIONAL_ADDRESS_MARKER] &&
|
|
2867
|
+
(lexer->lookahead == ',' || can_start_address(lexer))
|
|
2868
|
+
) {
|
|
2869
|
+
return emit_missing_marker(
|
|
2870
|
+
lexer,
|
|
2871
|
+
valid_symbols,
|
|
2872
|
+
ADDITIONAL_ADDRESS_MARKER,
|
|
2873
|
+
symbol
|
|
2874
|
+
);
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2877
|
+
if (
|
|
2878
|
+
valid_symbols[MISSING_ADDRESS_SEPARATOR_MARKER] && can_start_address(lexer)
|
|
2879
|
+
) {
|
|
2880
|
+
return emit_missing_marker(
|
|
2881
|
+
lexer,
|
|
2882
|
+
valid_symbols,
|
|
2883
|
+
MISSING_ADDRESS_SEPARATOR_MARKER,
|
|
2884
|
+
symbol
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
if (
|
|
2889
|
+
valid_symbols[BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER] &&
|
|
2890
|
+
lexer->lookahead == ','
|
|
2891
|
+
) {
|
|
2892
|
+
lexer->mark_end(lexer);
|
|
2893
|
+
advance(lexer);
|
|
2894
|
+
if (is_blank(lexer->lookahead)) {
|
|
2895
|
+
*symbol = BLANKS_AROUND_ADDRESS_SEPARATOR_MARKER;
|
|
2896
|
+
return true;
|
|
2897
|
+
}
|
|
2898
|
+
return false;
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
if (is_blank(lexer->lookahead)) {
|
|
2902
|
+
switch (scan_post_blank_recovery(lexer, valid_symbols, symbol)) {
|
|
2903
|
+
case POST_BLANK_RECOVERY_TOKEN:
|
|
2904
|
+
return true;
|
|
2905
|
+
case POST_BLANK_RECOVERY_FAILED:
|
|
2906
|
+
return false;
|
|
2907
|
+
case POST_BLANK_RECOVERY_SKIPPED:
|
|
2908
|
+
break;
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
if (
|
|
2913
|
+
emit_missing_marker(lexer, valid_symbols, DUPLICATE_NEGATION_MARKER, symbol)
|
|
2914
|
+
) {
|
|
2915
|
+
return true;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
if (
|
|
2919
|
+
emit_missing_marker(lexer, valid_symbols, EXCESS_ADDRESSES_MARKER, symbol)
|
|
2920
|
+
) {
|
|
2921
|
+
return true;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
if (
|
|
2925
|
+
!at_command_boundary(lexer) &&
|
|
2926
|
+
!is_blank(lexer->lookahead) &&
|
|
2927
|
+
valid_symbols[OMITTED_FILE_SEPARATOR_MARKER] &&
|
|
2928
|
+
emit_missing_marker(
|
|
2929
|
+
lexer,
|
|
2930
|
+
valid_symbols,
|
|
2931
|
+
OMITTED_FILE_SEPARATOR_MARKER,
|
|
2932
|
+
symbol
|
|
2933
|
+
)
|
|
2934
|
+
) {
|
|
2935
|
+
return true;
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
if (at_command_boundary(lexer)) {
|
|
2939
|
+
const TSSymbol first_marker = lexer->eof(lexer)
|
|
2940
|
+
? MISSING_FUNCTION_MARKER
|
|
2941
|
+
: NONCONFORMING_MISSING_FUNCTION_MARKER;
|
|
2942
|
+
for (
|
|
2943
|
+
TSSymbol offset = 0;
|
|
2944
|
+
offset <= MISSING_WFILE_MARKER - MISSING_FUNCTION_MARKER;
|
|
2945
|
+
offset++
|
|
2946
|
+
) {
|
|
2947
|
+
const TSSymbol marker = first_marker + offset;
|
|
2948
|
+
if (emit_missing_marker(lexer, valid_symbols, marker, symbol)) {
|
|
2949
|
+
return true;
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2954
|
+
const TSSymbol missing_text_introducer = lexer->eof(lexer)
|
|
2955
|
+
? MISSING_TEXT_INTRODUCER_MARKER
|
|
2956
|
+
: NONCONFORMING_MISSING_TEXT_INTRODUCER_MARKER;
|
|
2957
|
+
if (
|
|
2958
|
+
emit_missing_marker(lexer, valid_symbols, missing_text_introducer, symbol)
|
|
2959
|
+
) {
|
|
2960
|
+
return true;
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
if (valid_symbols[MISSING_CLOSING_BRACE_MARKER] && lexer->eof(lexer)) {
|
|
2964
|
+
return emit_missing_marker(
|
|
2965
|
+
lexer,
|
|
2966
|
+
valid_symbols,
|
|
2967
|
+
MISSING_CLOSING_BRACE_MARKER,
|
|
2968
|
+
symbol
|
|
2969
|
+
);
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
if (
|
|
2973
|
+
!at_command_boundary(lexer) &&
|
|
2974
|
+
!is_blank(lexer->lookahead) &&
|
|
2975
|
+
emit_missing_marker(
|
|
2976
|
+
lexer,
|
|
2977
|
+
valid_symbols,
|
|
2978
|
+
MISSING_SEPARATOR_AFTER_UNMATCHED_BRACE_MARKER,
|
|
2979
|
+
symbol
|
|
2980
|
+
)
|
|
2981
|
+
) {
|
|
2982
|
+
return true;
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
if (lexer->lookahead == '}') {
|
|
2986
|
+
if (
|
|
2987
|
+
emit_missing_marker(
|
|
2988
|
+
lexer,
|
|
2989
|
+
valid_symbols,
|
|
2990
|
+
MISSING_SEPARATOR_BEFORE_UNMATCHED_BRACE_MARKER,
|
|
2991
|
+
symbol
|
|
2992
|
+
)
|
|
2993
|
+
) {
|
|
2994
|
+
return true;
|
|
2995
|
+
}
|
|
2996
|
+
if (
|
|
2997
|
+
emit_missing_marker(
|
|
2998
|
+
lexer,
|
|
2999
|
+
valid_symbols,
|
|
3000
|
+
MISSING_COMMAND_SEPARATOR_MARKER,
|
|
3001
|
+
symbol
|
|
3002
|
+
)
|
|
3003
|
+
) {
|
|
3004
|
+
return true;
|
|
3005
|
+
}
|
|
3006
|
+
} else if (lexer->eof(lexer)) {
|
|
3007
|
+
if (
|
|
3008
|
+
emit_missing_marker(
|
|
3009
|
+
lexer,
|
|
3010
|
+
valid_symbols,
|
|
3011
|
+
INCOMPLETE_COMMAND_SEPARATOR_MARKER,
|
|
3012
|
+
symbol
|
|
3013
|
+
)
|
|
3014
|
+
) {
|
|
3015
|
+
return true;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
const TSSymbol missing_opening_delimiter = lexer->eof(lexer)
|
|
3020
|
+
? MISSING_OPENING_DELIMITER_MARKER
|
|
3021
|
+
: NONCONFORMING_MISSING_OPENING_DELIMITER_MARKER;
|
|
3022
|
+
if (
|
|
3023
|
+
delimiter_is_missing(lexer) &&
|
|
3024
|
+
emit_missing_marker(lexer, valid_symbols, missing_opening_delimiter, symbol)
|
|
3025
|
+
) {
|
|
3026
|
+
return true;
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
return false;
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
static void
|
|
3033
|
+
update_regex_position_after_symbol(ScannerState *state, TSSymbol symbol) {
|
|
3034
|
+
#if !SED_REGEX_EXTENDED
|
|
3035
|
+
if (
|
|
3036
|
+
symbol ==
|
|
3037
|
+
BRE_VERTICAL_LINE_ESCAPE_MARKER ||
|
|
3038
|
+
symbol ==
|
|
3039
|
+
BRE_QUESTION_MARK_ESCAPE_MARKER ||
|
|
3040
|
+
symbol ==
|
|
3041
|
+
BRE_PLUS_ESCAPE_MARKER ||
|
|
3042
|
+
symbol == UNMATCHED_INTERVAL_CLOSE_MARKER
|
|
3043
|
+
) {
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
#endif
|
|
3047
|
+
if (
|
|
3048
|
+
symbol ==
|
|
3049
|
+
REGEX_LEADING_DUPLICATION_MARKER ||
|
|
3050
|
+
symbol == REGEX_ADJACENT_DUPLICATION_MARKER
|
|
3051
|
+
) {
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
const bool is_regex_token =
|
|
3056
|
+
symbol >= REGEX_LITERAL && symbol <= REGEX_MALFORMED_BRACKET_TERM;
|
|
3057
|
+
if (!is_regex_token) {
|
|
3058
|
+
return;
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
if (symbol == REGEX_GROUP_OPEN) {
|
|
3062
|
+
if (state->regex_group_depth < UINT16_MAX) {
|
|
3063
|
+
state->regex_group_depth++;
|
|
3064
|
+
}
|
|
3065
|
+
set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, false);
|
|
3066
|
+
return;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
if (symbol == REGEX_GROUP_CLOSE) {
|
|
3070
|
+
if (state->regex_group_depth > 0) {
|
|
3071
|
+
state->regex_group_depth--;
|
|
3072
|
+
}
|
|
3073
|
+
set_regex_position(state, false, REGEX_DUPLICATION_NONE, false, false);
|
|
3074
|
+
return;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
#if SED_REGEX_EXTENDED
|
|
3078
|
+
if (symbol == REGEX_ALTERNATION_OPERATOR) {
|
|
3079
|
+
set_regex_position(state, true, REGEX_DUPLICATION_NONE, true, false);
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
#endif
|
|
3083
|
+
|
|
3084
|
+
if (symbol == REGEX_BEGINNING_ANCHOR || symbol == REGEX_END_ANCHOR) {
|
|
3085
|
+
set_regex_position(state, true, REGEX_DUPLICATION_NONE, false, true);
|
|
3086
|
+
return;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
bool is_duplication = symbol ==
|
|
3090
|
+
REGEX_ZERO_OR_MORE ||
|
|
3091
|
+
symbol ==
|
|
3092
|
+
REGEX_INTERVAL_CLOSE ||
|
|
3093
|
+
symbol == REGEX_INVALID_INTERVAL;
|
|
3094
|
+
#if SED_REGEX_EXTENDED
|
|
3095
|
+
is_duplication = is_duplication ||
|
|
3096
|
+
symbol ==
|
|
3097
|
+
REGEX_ONE_OR_MORE ||
|
|
3098
|
+
symbol == REGEX_ZERO_OR_ONE;
|
|
3099
|
+
#endif
|
|
3100
|
+
if (is_duplication) {
|
|
3101
|
+
set_regex_position(
|
|
3102
|
+
state,
|
|
3103
|
+
false,
|
|
3104
|
+
REGEX_AFTER_DUPLICATION_SYMBOL,
|
|
3105
|
+
false,
|
|
3106
|
+
false
|
|
3107
|
+
);
|
|
3108
|
+
return;
|
|
3109
|
+
}
|
|
3110
|
+
|
|
3111
|
+
#if SED_REGEX_EXTENDED
|
|
3112
|
+
if (symbol == REGEX_REPETITION_MODIFIER) {
|
|
3113
|
+
set_regex_position(
|
|
3114
|
+
state,
|
|
3115
|
+
false,
|
|
3116
|
+
REGEX_AFTER_REPETITION_MODIFIER,
|
|
3117
|
+
false,
|
|
3118
|
+
false
|
|
3119
|
+
);
|
|
3120
|
+
return;
|
|
3121
|
+
}
|
|
3122
|
+
#endif
|
|
3123
|
+
|
|
3124
|
+
set_regex_position(state, false, REGEX_DUPLICATION_NONE, false, false);
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
static bool
|
|
3128
|
+
sed_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) {
|
|
3129
|
+
ScannerState next = *(ScannerState *)payload;
|
|
3130
|
+
TSSymbol symbol;
|
|
3131
|
+
|
|
3132
|
+
if (!sed_scanner_scan_impl(&next, lexer, valid_symbols, &symbol)) {
|
|
3133
|
+
return false;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
update_regex_position_after_symbol(&next, symbol);
|
|
3137
|
+
*(ScannerState *)payload = next;
|
|
3138
|
+
lexer->result_symbol = symbol;
|
|
3139
|
+
return true;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
#endif
|