@konomanoasa/tree-sitter-gitattributes 0.3.0 → 0.4.1
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/Cargo.toml +2 -2
- package/README.md +4 -5
- package/grammar.js +40 -40
- package/package.json +5 -5
- package/src/grammar.json +158 -108
- package/src/node-types.json +4 -0
- package/src/parser.c +2540 -2437
- package/src/scanner.c +237 -276
- package/test/bindings.test.rs +0 -13
- package/tree-sitter.json +1 -1
package/src/scanner.c
CHANGED
|
@@ -54,17 +54,18 @@ enum Token {
|
|
|
54
54
|
INCOMPLETE_SET_CLOSE,
|
|
55
55
|
INVALID_ENCODING,
|
|
56
56
|
NEGATIVE_PATTERN,
|
|
57
|
-
|
|
57
|
+
ENDED_ESCAPE,
|
|
58
58
|
INCOMPLETE_ESCAPE,
|
|
59
59
|
INVALID_QUOTED_ESCAPE,
|
|
60
60
|
ENDED_QUOTED_ESCAPE,
|
|
61
61
|
INCOMPLETE_QUOTED_ESCAPE,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
MISSING_QUOTE_CLOSE,
|
|
63
|
+
INCOMPLETE_QUOTE_CLOSE,
|
|
64
|
+
MISSING_ATTRIBUTE_SEPARATOR,
|
|
65
|
+
MISSING_ATTRIBUTE_NAME,
|
|
66
|
+
INCOMPLETE_ATTRIBUTE_NAME,
|
|
67
67
|
INVALID_NAME_CHARACTER,
|
|
68
|
+
INCOMPLETE_NAME_CHARACTER,
|
|
68
69
|
INVALID_NAME_ESCAPE,
|
|
69
70
|
ERROR_SENTINEL
|
|
70
71
|
};
|
|
@@ -74,17 +75,23 @@ enum Token {
|
|
|
74
75
|
enum { DECODE_ERROR = -1, CURSOR_END = -2, INVALID_UNIT = -3 };
|
|
75
76
|
|
|
76
77
|
typedef struct {
|
|
77
|
-
uint32_t kind, end
|
|
78
|
+
uint32_t kind, end;
|
|
78
79
|
} Item;
|
|
79
80
|
|
|
80
|
-
//
|
|
81
|
+
// Class bounds include brackets; inner bounds exclude both colons.
|
|
81
82
|
typedef struct {
|
|
82
|
-
uint32_t
|
|
83
|
+
uint32_t start, opening_end, closing_start, end;
|
|
84
|
+
} Class;
|
|
85
|
+
|
|
86
|
+
// Positions are line-relative character offsets.
|
|
87
|
+
typedef struct {
|
|
88
|
+
uint32_t position, leading, line_end, content_end;
|
|
83
89
|
uint32_t token_end, name_start, name_end;
|
|
84
|
-
uint32_t
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
uint32_t next_end, prefix_end, set_end, set_close_end;
|
|
91
|
+
Class class;
|
|
92
|
+
uint32_t lower_end, range_operator_end, upper_end;
|
|
93
|
+
uint8_t kind, next, prefix_kind, lower_kind, upper_kind;
|
|
94
|
+
uint8_t quoted, component_start, after_separator;
|
|
88
95
|
} Scanner;
|
|
89
96
|
|
|
90
97
|
typedef char scanner_fits_buffer
|
|
@@ -98,7 +105,7 @@ typedef struct {
|
|
|
98
105
|
} Cursor;
|
|
99
106
|
|
|
100
107
|
static bool whitespace(int32_t c) {
|
|
101
|
-
return c == ' ' || c == '\t' || c == '\
|
|
108
|
+
return c == ' ' || c == '\t' || c == '\r';
|
|
102
109
|
}
|
|
103
110
|
|
|
104
111
|
static bool alphanumeric(int32_t c) {
|
|
@@ -117,8 +124,7 @@ static void advance(Scanner *s, TSLexer *lexer) {
|
|
|
117
124
|
}
|
|
118
125
|
|
|
119
126
|
static bool emit(TSLexer *lexer, const bool *valid, enum Token token) {
|
|
120
|
-
if (!valid[token])
|
|
121
|
-
return false;
|
|
127
|
+
if (!valid[token]) return false;
|
|
122
128
|
lexer->result_symbol = token;
|
|
123
129
|
return true;
|
|
124
130
|
}
|
|
@@ -128,6 +134,15 @@ absent(TSLexer *lexer, enum Token missing, enum Token incomplete) {
|
|
|
128
134
|
return lexer->eof(lexer) ? incomplete : missing;
|
|
129
135
|
}
|
|
130
136
|
|
|
137
|
+
// Include the next decoded character so edits invalidate the run.
|
|
138
|
+
static bool invalid_run(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
139
|
+
do advance(s, lexer);
|
|
140
|
+
while (!lexer->eof(lexer) && lexer->lookahead == DECODE_ERROR);
|
|
141
|
+
lexer->mark_end(lexer);
|
|
142
|
+
if (!lexer->eof(lexer)) lexer->advance(lexer, false);
|
|
143
|
+
return emit(lexer, valid, INVALID_ENCODING);
|
|
144
|
+
}
|
|
145
|
+
|
|
131
146
|
static bool consume(
|
|
132
147
|
Scanner *s,
|
|
133
148
|
TSLexer *lexer,
|
|
@@ -135,18 +150,9 @@ static bool consume(
|
|
|
135
150
|
enum Token token,
|
|
136
151
|
uint32_t end
|
|
137
152
|
) {
|
|
138
|
-
if (token == INVALID_ENCODING)
|
|
139
|
-
|
|
140
|
-
advance(s, lexer);
|
|
141
|
-
} while (!lexer->eof(lexer) && lexer->lookahead == DECODE_ERROR);
|
|
142
|
-
} else {
|
|
143
|
-
while (s->position < end)
|
|
144
|
-
advance(s, lexer);
|
|
145
|
-
}
|
|
153
|
+
if (token == INVALID_ENCODING) return invalid_run(s, lexer, valid);
|
|
154
|
+
while (s->position < end) advance(s, lexer);
|
|
146
155
|
lexer->mark_end(lexer);
|
|
147
|
-
// Include the next decoded character so edits invalidate this run.
|
|
148
|
-
if (token == INVALID_ENCODING && !lexer->eof(lexer))
|
|
149
|
-
lexer->advance(lexer, false);
|
|
150
156
|
return emit(lexer, valid, token);
|
|
151
157
|
}
|
|
152
158
|
|
|
@@ -157,8 +163,7 @@ static bool text_run(
|
|
|
157
163
|
enum Token token,
|
|
158
164
|
uint32_t end
|
|
159
165
|
) {
|
|
160
|
-
if (lexer->lookahead == DECODE_ERROR)
|
|
161
|
-
return consume(s, lexer, valid, INVALID_ENCODING, end);
|
|
166
|
+
if (lexer->lookahead == DECODE_ERROR) return invalid_run(s, lexer, valid);
|
|
162
167
|
while (s->position < end && lexer->lookahead != DECODE_ERROR)
|
|
163
168
|
advance(s, lexer);
|
|
164
169
|
lexer->mark_end(lexer);
|
|
@@ -170,85 +175,85 @@ static void raw_step(Cursor *r) {
|
|
|
170
175
|
r->raw++;
|
|
171
176
|
}
|
|
172
177
|
|
|
178
|
+
static int32_t simple_escape(int32_t c) {
|
|
179
|
+
switch (c) {
|
|
180
|
+
case 'a':
|
|
181
|
+
return '\a';
|
|
182
|
+
case 'b':
|
|
183
|
+
return '\b';
|
|
184
|
+
case 't':
|
|
185
|
+
return '\t';
|
|
186
|
+
case 'n':
|
|
187
|
+
return '\n';
|
|
188
|
+
case 'v':
|
|
189
|
+
return '\v';
|
|
190
|
+
case 'f':
|
|
191
|
+
return '\f';
|
|
192
|
+
case 'r':
|
|
193
|
+
return '\r';
|
|
194
|
+
case '\\':
|
|
195
|
+
case '"':
|
|
196
|
+
return c;
|
|
197
|
+
default:
|
|
198
|
+
return INVALID_UNIT;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Backslash already consumed.
|
|
203
|
+
static void quoted_escape(Cursor *r) {
|
|
204
|
+
const int32_t c = r->lexer->lookahead;
|
|
205
|
+
r->kind = QUOTED_ESCAPE;
|
|
206
|
+
if (r->raw >= r->limit) {
|
|
207
|
+
r->c = INVALID_UNIT;
|
|
208
|
+
r->kind = absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE);
|
|
209
|
+
} else if (c == DECODE_ERROR) {
|
|
210
|
+
r->c = INVALID_UNIT;
|
|
211
|
+
r->kind = ESCAPE_PREFIX;
|
|
212
|
+
} else if (c >= '0' && c <= '3') {
|
|
213
|
+
int32_t value = 0;
|
|
214
|
+
unsigned digits = 0;
|
|
215
|
+
while (digits < 3 && r->raw < r->limit) {
|
|
216
|
+
const int32_t digit = r->lexer->lookahead;
|
|
217
|
+
if (digit < '0' || digit > '7') break;
|
|
218
|
+
value = value * 8 + digit - '0';
|
|
219
|
+
raw_step(r);
|
|
220
|
+
digits++;
|
|
221
|
+
}
|
|
222
|
+
if (digits == 3) r->c = value;
|
|
223
|
+
else {
|
|
224
|
+
r->c = INVALID_UNIT;
|
|
225
|
+
r->kind = r->raw == r->limit
|
|
226
|
+
? absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE)
|
|
227
|
+
: ENDED_QUOTED_ESCAPE;
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
raw_step(r);
|
|
231
|
+
r->c = simple_escape(c);
|
|
232
|
+
if (r->c == INVALID_UNIT) r->kind = INVALID_QUOTED_ESCAPE;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
173
236
|
static void step(Cursor *r) {
|
|
174
237
|
r->start = r->end = r->raw;
|
|
175
238
|
r->kind = 0;
|
|
176
239
|
r->c = CURSOR_END;
|
|
177
|
-
if (r->raw >= r->limit)
|
|
178
|
-
|
|
179
|
-
int32_t c = r->lexer->lookahead;
|
|
240
|
+
if (r->raw >= r->limit) return;
|
|
241
|
+
const int32_t c = r->lexer->lookahead;
|
|
180
242
|
raw_step(r);
|
|
181
243
|
r->c = c;
|
|
182
244
|
if (c == DECODE_ERROR) {
|
|
183
245
|
r->kind = INVALID_ENCODING;
|
|
184
246
|
while (r->raw < r->limit && r->lexer->lookahead == DECODE_ERROR)
|
|
185
247
|
raw_step(r);
|
|
186
|
-
} else if (r->s->quoted && r->start < r->s->content_end && c == '\\')
|
|
187
|
-
r
|
|
188
|
-
c = r->lexer->lookahead;
|
|
189
|
-
if (r->raw >= r->limit) {
|
|
190
|
-
r->c = INVALID_UNIT;
|
|
191
|
-
r->kind = absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE);
|
|
192
|
-
} else if (c == DECODE_ERROR) {
|
|
193
|
-
r->c = INVALID_UNIT;
|
|
194
|
-
r->kind = ESCAPE_PREFIX;
|
|
195
|
-
} else if (c >= '0' && c <= '3') {
|
|
196
|
-
int32_t value = 0;
|
|
197
|
-
unsigned digits = 0;
|
|
198
|
-
while (digits < 3 && r->raw < r->limit) {
|
|
199
|
-
const int32_t digit = r->lexer->lookahead;
|
|
200
|
-
if (digit < '0' || digit > '7')
|
|
201
|
-
break;
|
|
202
|
-
value = value * 8 + digit - '0';
|
|
203
|
-
raw_step(r);
|
|
204
|
-
digits++;
|
|
205
|
-
}
|
|
206
|
-
if (digits == 3)
|
|
207
|
-
r->c = value;
|
|
208
|
-
else {
|
|
209
|
-
r->c = INVALID_UNIT;
|
|
210
|
-
r->kind = r->raw == r->limit
|
|
211
|
-
? absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE)
|
|
212
|
-
: ENDED_QUOTED_ESCAPE;
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
raw_step(r);
|
|
216
|
-
switch (c) {
|
|
217
|
-
case 'a':
|
|
218
|
-
r->c = '\a';
|
|
219
|
-
break;
|
|
220
|
-
case 'b':
|
|
221
|
-
r->c = '\b';
|
|
222
|
-
break;
|
|
223
|
-
case 't':
|
|
224
|
-
r->c = '\t';
|
|
225
|
-
break;
|
|
226
|
-
case 'n':
|
|
227
|
-
r->c = '\n';
|
|
228
|
-
break;
|
|
229
|
-
case 'v':
|
|
230
|
-
r->c = '\v';
|
|
231
|
-
break;
|
|
232
|
-
case 'f':
|
|
233
|
-
r->c = '\f';
|
|
234
|
-
break;
|
|
235
|
-
case 'r':
|
|
236
|
-
r->c = '\r';
|
|
237
|
-
break;
|
|
238
|
-
case '\\':
|
|
239
|
-
case '"':
|
|
240
|
-
r->c = c;
|
|
241
|
-
break;
|
|
242
|
-
default:
|
|
243
|
-
r->c = INVALID_UNIT;
|
|
244
|
-
r->kind = INVALID_QUOTED_ESCAPE;
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
248
|
+
} else if (r->s->quoted && r->start < r->s->content_end && c == '\\')
|
|
249
|
+
quoted_escape(r);
|
|
249
250
|
r->end = r->raw;
|
|
250
251
|
}
|
|
251
252
|
|
|
253
|
+
static uint32_t content_start(const Scanner *s) {
|
|
254
|
+
return s->leading + s->quoted;
|
|
255
|
+
}
|
|
256
|
+
|
|
252
257
|
static Cursor cursor(const Scanner *s, TSLexer *lexer, uint32_t limit) {
|
|
253
258
|
Cursor r = {.s = s, .lexer = lexer, .raw = s->position, .limit = limit};
|
|
254
259
|
step(&r);
|
|
@@ -256,10 +261,9 @@ static Cursor cursor(const Scanner *s, TSLexer *lexer, uint32_t limit) {
|
|
|
256
261
|
}
|
|
257
262
|
|
|
258
263
|
static bool start_line(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
259
|
-
if (lexer->eof(lexer))
|
|
260
|
-
return false;
|
|
264
|
+
if (lexer->eof(lexer)) return false;
|
|
261
265
|
memset(s, 0, sizeof(*s));
|
|
262
|
-
s->
|
|
266
|
+
s->class.start = NONE;
|
|
263
267
|
s->component_start = true;
|
|
264
268
|
int32_t last = 0;
|
|
265
269
|
lexer->mark_end(lexer);
|
|
@@ -270,47 +274,39 @@ static bool start_line(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
270
274
|
s->leading = s->position;
|
|
271
275
|
s->kind = lexer->lookahead == '#' ? COMMENT_START : RULE_START;
|
|
272
276
|
s->quoted = lexer->lookahead == '"';
|
|
273
|
-
|
|
277
|
+
const uint32_t start = content_start(s);
|
|
274
278
|
s->content_end = NONE;
|
|
275
279
|
bool escaped = false;
|
|
276
280
|
while (!lexer->eof(lexer) && lexer->lookahead != '\n') {
|
|
277
281
|
const int32_t c = lexer->lookahead;
|
|
278
|
-
if (s->position >=
|
|
282
|
+
if (s->position >= start && s->content_end == NONE) {
|
|
279
283
|
if (s->quoted) {
|
|
280
|
-
if (c == '"' && !escaped)
|
|
281
|
-
s->content_end = s->position;
|
|
284
|
+
if (c == '"' && !escaped) s->content_end = s->position;
|
|
282
285
|
escaped = c == '\\' && !escaped;
|
|
283
|
-
} else if (whitespace(c))
|
|
284
|
-
s->content_end = s->position;
|
|
286
|
+
} else if (whitespace(c)) s->content_end = s->position;
|
|
285
287
|
}
|
|
286
288
|
last = c;
|
|
287
289
|
advance(s, lexer);
|
|
288
290
|
}
|
|
289
291
|
s->line_end = s->position;
|
|
290
|
-
if (last == '\r' && lexer->lookahead == '\n')
|
|
291
|
-
|
|
292
|
-
if (s->
|
|
293
|
-
|
|
294
|
-
if (s->content_end == NONE || s->content_end > s->line_end)
|
|
295
|
-
s->content_end = s->line_end;
|
|
296
|
-
if (s->leading >= s->line_end)
|
|
297
|
-
s->kind = BLANK_START;
|
|
292
|
+
if (last == '\r' && lexer->lookahead == '\n') s->line_end--;
|
|
293
|
+
if (s->leading > s->line_end) s->leading = s->line_end;
|
|
294
|
+
if (s->content_end == NONE) s->content_end = s->line_end;
|
|
295
|
+
if (s->leading >= s->line_end) s->kind = BLANK_START;
|
|
298
296
|
s->position = 0;
|
|
299
297
|
return emit(lexer, valid, LINE_START);
|
|
300
298
|
}
|
|
301
299
|
|
|
302
300
|
static bool start_content(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
303
|
-
while (s->position < s->leading)
|
|
304
|
-
advance(s, lexer);
|
|
301
|
+
while (s->position < s->leading) advance(s, lexer);
|
|
305
302
|
lexer->mark_end(lexer);
|
|
306
303
|
if (s->kind == RULE_START) {
|
|
307
|
-
//
|
|
308
|
-
if (s->quoted)
|
|
309
|
-
lexer->advance(lexer, false);
|
|
304
|
+
// QUOTE_OPEN consumes this lookahead quote later.
|
|
305
|
+
if (s->quoted) lexer->advance(lexer, false);
|
|
310
306
|
Cursor r = {
|
|
311
307
|
.s = s,
|
|
312
308
|
.lexer = lexer,
|
|
313
|
-
.raw = s
|
|
309
|
+
.raw = content_start(s),
|
|
314
310
|
.limit = s->content_end
|
|
315
311
|
};
|
|
316
312
|
static const char marker[] = "[attr]";
|
|
@@ -333,25 +329,21 @@ static bool start_content(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
333
329
|
|
|
334
330
|
static void skip_escaped(Cursor *r, Cursor *last, uint32_t *candidate) {
|
|
335
331
|
*last = *r;
|
|
336
|
-
if (r->c == ']')
|
|
337
|
-
*candidate = NONE;
|
|
332
|
+
if (r->c == ']') *candidate = NONE;
|
|
338
333
|
step(r);
|
|
339
334
|
}
|
|
340
335
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
Item a = {CLASS_OPEN, 0, 0, 0};
|
|
344
|
-
uint32_t candidate = NONE;
|
|
336
|
+
static bool next_class(Cursor *r, bool lower, Class *class) {
|
|
337
|
+
Class a = {NONE, 0, 0, 0};
|
|
345
338
|
Cursor last = *r;
|
|
346
339
|
while (r->c != CURSOR_END) {
|
|
347
340
|
const int32_t here = r->c;
|
|
348
341
|
if (here == ']') {
|
|
349
|
-
if (
|
|
342
|
+
if (a.start == NONE || last.c != ':' || last.end == a.opening_end)
|
|
350
343
|
return false;
|
|
351
344
|
a.closing_start = last.start;
|
|
352
345
|
a.end = r->end;
|
|
353
346
|
step(r);
|
|
354
|
-
*start = candidate;
|
|
355
347
|
*class = a;
|
|
356
348
|
return true;
|
|
357
349
|
}
|
|
@@ -359,21 +351,19 @@ static bool next_class(Cursor *r, bool lower, uint32_t *start, Item *class) {
|
|
|
359
351
|
step(r);
|
|
360
352
|
if (here == '\\') {
|
|
361
353
|
lower = r->c >= 0;
|
|
362
|
-
if (r->c != CURSOR_END)
|
|
363
|
-
skip_escaped(r, &last, &candidate);
|
|
354
|
+
if (r->c != CURSOR_END) skip_escaped(r, &last, &a.start);
|
|
364
355
|
continue;
|
|
365
356
|
}
|
|
366
357
|
if (here == '-' && lower && r->c != CURSOR_END && r->c != ']') {
|
|
367
358
|
const int32_t upper = r->c;
|
|
368
|
-
skip_escaped(r, &last, &
|
|
369
|
-
if (upper == '\\' && r->c != CURSOR_END)
|
|
370
|
-
skip_escaped(r, &last, &candidate);
|
|
359
|
+
skip_escaped(r, &last, &a.start);
|
|
360
|
+
if (upper == '\\' && r->c != CURSOR_END) skip_escaped(r, &last, &a.start);
|
|
371
361
|
lower = false;
|
|
372
362
|
continue;
|
|
373
363
|
}
|
|
374
364
|
lower = here >= 0;
|
|
375
|
-
if (
|
|
376
|
-
|
|
365
|
+
if (a.start == NONE && here == '[' && r->c == ':') {
|
|
366
|
+
a.start = last.start;
|
|
377
367
|
a.opening_end = r->end;
|
|
378
368
|
}
|
|
379
369
|
}
|
|
@@ -382,20 +372,14 @@ static bool next_class(Cursor *r, bool lower, uint32_t *start, Item *class) {
|
|
|
382
372
|
|
|
383
373
|
static void find_set(Scanner *s, Cursor *r) {
|
|
384
374
|
s->set_end = s->set_close_end = s->content_end;
|
|
385
|
-
s->
|
|
386
|
-
if (r->c == '!' || r->c == '^')
|
|
387
|
-
step(r);
|
|
375
|
+
s->class.start = NONE;
|
|
376
|
+
if (r->c == '!' || r->c == '^') step(r);
|
|
388
377
|
bool lower = r->c == ']';
|
|
389
|
-
if (lower)
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
uint32_t class_start;
|
|
393
|
-
while (next_class(r, lower, &class_start, &class)) {
|
|
378
|
+
if (lower) step(r);
|
|
379
|
+
Class class;
|
|
380
|
+
while (next_class(r, lower, &class)) {
|
|
394
381
|
lower = false;
|
|
395
|
-
if (s->
|
|
396
|
-
s->class_start = class_start;
|
|
397
|
-
s->class = class;
|
|
398
|
-
}
|
|
382
|
+
if (s->class.start == NONE) s->class = class;
|
|
399
383
|
}
|
|
400
384
|
if (r->c == ']') {
|
|
401
385
|
s->set_end = r->start;
|
|
@@ -404,25 +388,20 @@ static void find_set(Scanner *s, Cursor *r) {
|
|
|
404
388
|
}
|
|
405
389
|
|
|
406
390
|
static Item item(Cursor *r) {
|
|
407
|
-
Item a = {SET_TEXT, 0
|
|
408
|
-
if (r->c == CURSOR_END)
|
|
409
|
-
return a;
|
|
391
|
+
Item a = {SET_TEXT, 0};
|
|
410
392
|
const int32_t c = r->c;
|
|
411
393
|
const uint32_t end = r->end;
|
|
412
|
-
if (c == '[' && r->start == r->s->
|
|
413
|
-
a = r->s->class;
|
|
414
|
-
while (r->c != CURSOR_END && r->start < a.end)
|
|
415
|
-
step(r);
|
|
394
|
+
if (c == '[' && r->start == r->s->class.start) {
|
|
395
|
+
a = (Item){CLASS_OPEN, r->s->class.end};
|
|
396
|
+
while (r->c != CURSOR_END && r->start < a.end) step(r);
|
|
416
397
|
return a;
|
|
417
398
|
}
|
|
418
|
-
if (r->kind)
|
|
419
|
-
a.kind = r->kind;
|
|
399
|
+
if (r->kind) a.kind = r->kind;
|
|
420
400
|
step(r);
|
|
421
401
|
if (c == '\\') {
|
|
422
402
|
if (r->c == CURSOR_END)
|
|
423
|
-
a.kind = absent(r->lexer,
|
|
424
|
-
else if (r->c < 0)
|
|
425
|
-
a.kind = ESCAPE_PREFIX;
|
|
403
|
+
a.kind = absent(r->lexer, ENDED_ESCAPE, INCOMPLETE_ESCAPE);
|
|
404
|
+
else if (r->c < 0) a.kind = ESCAPE_PREFIX;
|
|
426
405
|
else {
|
|
427
406
|
a.kind = ESCAPE;
|
|
428
407
|
a.end = r->end;
|
|
@@ -435,18 +414,15 @@ static Item item(Cursor *r) {
|
|
|
435
414
|
}
|
|
436
415
|
|
|
437
416
|
static bool endpoint(Item a) {
|
|
438
|
-
return a.
|
|
439
|
-
(a.kind == SET_TEXT || a.kind == ESCAPE || a.kind == QUOTED_ESCAPE);
|
|
417
|
+
return a.kind == SET_TEXT || a.kind == ESCAPE || a.kind == QUOTED_ESCAPE;
|
|
440
418
|
}
|
|
441
419
|
|
|
442
420
|
static bool literal_boundary(const Cursor *r) {
|
|
443
|
-
if (r->c < 0 || r->kind == QUOTED_ESCAPE)
|
|
444
|
-
return true;
|
|
421
|
+
if (r->c < 0 || r->kind == QUOTED_ESCAPE) return true;
|
|
445
422
|
const int32_t c = r->c;
|
|
446
423
|
return c == '\\' || c == '*' || c == '?' || c == '/' || c == '[';
|
|
447
424
|
}
|
|
448
425
|
|
|
449
|
-
// Keep the backslash in its owner; report the following unit's own issue.
|
|
450
426
|
static void hold_prefix(Scanner *s, Cursor *r, uint32_t prefix_end) {
|
|
451
427
|
s->next = ESCAPE_PREFIX;
|
|
452
428
|
s->prefix_end = prefix_end;
|
|
@@ -461,28 +437,22 @@ static void hold_prefix(Scanner *s, Cursor *r, uint32_t prefix_end) {
|
|
|
461
437
|
|
|
462
438
|
// Consume lookahead units fully so edits inside them invalidate the decision.
|
|
463
439
|
static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
464
|
-
lexer->mark_end(lexer);
|
|
465
440
|
Cursor r = cursor(s, lexer, s->content_end);
|
|
466
441
|
bool separator = r.c == '/';
|
|
467
442
|
const uint32_t start = s->position;
|
|
468
443
|
s->next_end = r.end;
|
|
469
444
|
if (r.c < 0) {
|
|
470
|
-
if (r.kind == ESCAPE_PREFIX)
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
s->next = r.kind;
|
|
474
|
-
} else if (r.c == '!' && start == s->content_start)
|
|
445
|
+
if (r.kind == ESCAPE_PREFIX) hold_prefix(s, &r, r.end);
|
|
446
|
+
else s->next = r.kind;
|
|
447
|
+
} else if (r.c == '!' && start == content_start(s))
|
|
475
448
|
s->next = NEGATIVE_PATTERN;
|
|
476
|
-
else if (r.c == '?')
|
|
477
|
-
|
|
478
|
-
else if (r.c == '/')
|
|
479
|
-
s->next = PATH_SEPARATOR;
|
|
449
|
+
else if (r.c == '?') s->next = SINGLE_CHARACTER;
|
|
450
|
+
else if (r.c == '/') s->next = PATH_SEPARATOR;
|
|
480
451
|
else if (r.c == '\\') {
|
|
481
452
|
step(&r);
|
|
482
453
|
if (r.c == CURSOR_END)
|
|
483
|
-
s->next = absent(lexer,
|
|
484
|
-
else if (r.c < 0)
|
|
485
|
-
hold_prefix(s, &r, s->next_end);
|
|
454
|
+
s->next = absent(lexer, ENDED_ESCAPE, INCOMPLETE_ESCAPE);
|
|
455
|
+
else if (r.c < 0) hold_prefix(s, &r, s->next_end);
|
|
486
456
|
else {
|
|
487
457
|
s->next = ESCAPE;
|
|
488
458
|
s->next_end = r.end;
|
|
@@ -497,12 +467,10 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
497
467
|
}
|
|
498
468
|
const bool pair = count == 2 && s->component_start;
|
|
499
469
|
const bool tail = r.c == CURSOR_END && s->after_separator;
|
|
500
|
-
if (r.c == '\\')
|
|
501
|
-
step(&r);
|
|
470
|
+
if (r.c == '\\') step(&r);
|
|
502
471
|
const bool slash = r.c == '/';
|
|
503
472
|
s->next = pair && (slash || tail) ? RECURSIVE_WILDCARD : WILDCARD;
|
|
504
|
-
} else if (r.kind == QUOTED_ESCAPE && r.c != '[')
|
|
505
|
-
s->next = QUOTED_ESCAPE;
|
|
473
|
+
} else if (r.kind == QUOTED_ESCAPE && r.c != '[') s->next = QUOTED_ESCAPE;
|
|
506
474
|
else if (r.c == '[') {
|
|
507
475
|
s->next = SET_OPEN;
|
|
508
476
|
step(&r);
|
|
@@ -521,13 +489,11 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
521
489
|
return emit(lexer, valid, LITERAL);
|
|
522
490
|
}
|
|
523
491
|
s->component_start = separator || s->next == NEGATIVE_PATTERN;
|
|
524
|
-
if (separator)
|
|
525
|
-
s->after_separator = true;
|
|
492
|
+
if (separator) s->after_separator = true;
|
|
526
493
|
return emit(lexer, valid, GLOB_START);
|
|
527
494
|
}
|
|
528
495
|
|
|
529
496
|
static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
530
|
-
lexer->mark_end(lexer);
|
|
531
497
|
Cursor r = cursor(s, lexer, s->set_end);
|
|
532
498
|
const uint32_t start = s->position;
|
|
533
499
|
if (valid[SET_NEGATION] && (r.c == '!' || r.c == '^')) {
|
|
@@ -537,7 +503,6 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
537
503
|
}
|
|
538
504
|
s->next = SET_TEXT;
|
|
539
505
|
s->next_end = start;
|
|
540
|
-
uint32_t here = start;
|
|
541
506
|
Item current = item(&r);
|
|
542
507
|
for (;;) {
|
|
543
508
|
if (endpoint(current) && r.c == '-' && r.end < s->set_end) {
|
|
@@ -546,13 +511,14 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
546
511
|
step(&r);
|
|
547
512
|
const Item upper = item(&r);
|
|
548
513
|
if (endpoint(upper)) {
|
|
549
|
-
if (
|
|
514
|
+
if (s->next_end == start) {
|
|
550
515
|
s->next = RANGE_START;
|
|
551
|
-
s->
|
|
552
|
-
s->
|
|
516
|
+
s->lower_kind = current.kind;
|
|
517
|
+
s->lower_end = current.end;
|
|
553
518
|
s->range_operator_end = operator_end;
|
|
554
|
-
|
|
555
|
-
s->
|
|
519
|
+
s->upper_kind = upper.kind;
|
|
520
|
+
s->upper_end = upper.end;
|
|
521
|
+
}
|
|
556
522
|
break;
|
|
557
523
|
}
|
|
558
524
|
if (current.kind == SET_TEXT) {
|
|
@@ -561,32 +527,31 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
561
527
|
break;
|
|
562
528
|
}
|
|
563
529
|
s->next_end = operator_end;
|
|
564
|
-
here = operator_end;
|
|
565
530
|
current = upper;
|
|
566
531
|
continue;
|
|
567
532
|
}
|
|
568
533
|
}
|
|
569
534
|
if (current.kind != SET_TEXT) {
|
|
570
|
-
if (
|
|
535
|
+
if (s->next_end == start) {
|
|
571
536
|
s->next = current.kind;
|
|
572
537
|
s->next_end = current.end;
|
|
573
|
-
if (current.kind == ESCAPE_PREFIX)
|
|
574
|
-
|
|
575
|
-
} else
|
|
576
|
-
s->next_end = here;
|
|
538
|
+
if (current.kind == ESCAPE_PREFIX) hold_prefix(s, &r, current.end);
|
|
539
|
+
}
|
|
577
540
|
break;
|
|
578
541
|
}
|
|
579
542
|
s->next_end = current.end;
|
|
580
|
-
|
|
581
|
-
if (r.c == CURSOR_END)
|
|
582
|
-
break;
|
|
543
|
+
if (r.c == CURSOR_END) break;
|
|
583
544
|
current = item(&r);
|
|
584
545
|
}
|
|
585
546
|
return emit(lexer, valid, SET_ITEM_START);
|
|
586
547
|
}
|
|
587
548
|
|
|
588
|
-
static bool
|
|
589
|
-
|
|
549
|
+
static bool class_delimiter(
|
|
550
|
+
Scanner *s,
|
|
551
|
+
TSLexer *lexer,
|
|
552
|
+
const bool *valid,
|
|
553
|
+
enum Token token
|
|
554
|
+
) {
|
|
590
555
|
Cursor r = cursor(s, lexer, s->class.end);
|
|
591
556
|
s->position = r.end;
|
|
592
557
|
lexer->mark_end(lexer);
|
|
@@ -597,18 +562,15 @@ static bool class_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
597
562
|
if (s->position < s->class.opening_end)
|
|
598
563
|
return consume(s, lexer, valid, CLASS_OPEN, s->class.opening_end);
|
|
599
564
|
if (s->position == s->class.closing_start)
|
|
600
|
-
return
|
|
565
|
+
return class_delimiter(s, lexer, valid, CLASS_CLOSE);
|
|
601
566
|
if (s->position > s->class.closing_start) {
|
|
602
|
-
while (s->position < s->class.end)
|
|
603
|
-
advance(s, lexer);
|
|
567
|
+
while (s->position < s->class.end) advance(s, lexer);
|
|
604
568
|
lexer->mark_end(lexer);
|
|
605
569
|
Cursor r = cursor(s, lexer, s->set_end);
|
|
606
|
-
if (!next_class(&r, false, &s->
|
|
607
|
-
s->class_start = NONE;
|
|
570
|
+
if (!next_class(&r, false, &s->class)) s->class.start = NONE;
|
|
608
571
|
return emit(lexer, valid, COMPOUND_CLOSE);
|
|
609
572
|
}
|
|
610
|
-
if (lexer->lookahead == DECODE_ERROR)
|
|
611
|
-
return consume(s, lexer, valid, INVALID_ENCODING, s->class.closing_start);
|
|
573
|
+
if (lexer->lookahead == DECODE_ERROR) return invalid_run(s, lexer, valid);
|
|
612
574
|
Cursor r = cursor(s, lexer, s->class.closing_start);
|
|
613
575
|
const enum Token token = r.kind ? (enum Token)r.kind : CLASS_NAME;
|
|
614
576
|
uint32_t end = r.end;
|
|
@@ -625,27 +587,40 @@ static bool class_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
625
587
|
return emit(lexer, valid, token);
|
|
626
588
|
}
|
|
627
589
|
|
|
590
|
+
static bool range_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
591
|
+
if (s->position == s->lower_end)
|
|
592
|
+
return consume(s, lexer, valid, RANGE_OPERATOR, s->range_operator_end);
|
|
593
|
+
const bool lower = s->position < s->lower_end;
|
|
594
|
+
const enum Token kind = (enum Token)(lower ? s->lower_kind : s->upper_kind);
|
|
595
|
+
return consume(
|
|
596
|
+
s,
|
|
597
|
+
lexer,
|
|
598
|
+
valid,
|
|
599
|
+
kind == SET_TEXT ? RANGE_CHARACTER : kind,
|
|
600
|
+
lower ? s->lower_end : s->upper_end
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
static enum Token name_token(const Cursor *r, bool first) {
|
|
605
|
+
if (r->c < 0) return (enum Token)r->kind;
|
|
606
|
+
if (!r->kind && r->c == '\r' && r->lexer->eof(r->lexer))
|
|
607
|
+
return INCOMPLETE_NAME_CHARACTER;
|
|
608
|
+
if (!name_character(r->c, first))
|
|
609
|
+
return r->kind == QUOTED_ESCAPE ? INVALID_NAME_ESCAPE
|
|
610
|
+
: INVALID_NAME_CHARACTER;
|
|
611
|
+
return r->kind == QUOTED_ESCAPE ? QUOTED_ESCAPE : NAME_TEXT;
|
|
612
|
+
}
|
|
613
|
+
|
|
628
614
|
static bool name_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
629
|
-
if (lexer->lookahead == DECODE_ERROR)
|
|
630
|
-
return consume(s, lexer, valid, INVALID_ENCODING, s->name_end);
|
|
615
|
+
if (lexer->lookahead == DECODE_ERROR) return invalid_run(s, lexer, valid);
|
|
631
616
|
Cursor r = cursor(s, lexer, s->name_end);
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
s->next = INVALID_ENCODING;
|
|
635
|
-
if (r.c < 0)
|
|
636
|
-
token = (enum Token)r.kind;
|
|
637
|
-
else if (!name_character(r.c, s->position == s->name_start))
|
|
638
|
-
token =
|
|
639
|
-
r.kind == QUOTED_ESCAPE ? INVALID_NAME_ESCAPE : INVALID_NAME_CHARACTER;
|
|
640
|
-
else
|
|
641
|
-
token = r.kind == QUOTED_ESCAPE ? QUOTED_ESCAPE : NAME_TEXT;
|
|
617
|
+
if (r.kind == ESCAPE_PREFIX) s->next = INVALID_ENCODING;
|
|
618
|
+
const enum Token token = name_token(&r, s->position == s->name_start);
|
|
642
619
|
uint32_t end = r.end;
|
|
643
620
|
lexer->mark_end(lexer);
|
|
644
621
|
if (token == NAME_TEXT || token == INVALID_NAME_CHARACTER) {
|
|
645
622
|
step(&r);
|
|
646
|
-
while (
|
|
647
|
-
r.c >= 0 && !r.kind && name_character(r.c, false) == (token == NAME_TEXT)
|
|
648
|
-
) {
|
|
623
|
+
while (name_token(&r, false) == token) {
|
|
649
624
|
end = r.end;
|
|
650
625
|
lexer->mark_end(lexer);
|
|
651
626
|
step(&r);
|
|
@@ -656,27 +631,22 @@ static bool name_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
656
631
|
}
|
|
657
632
|
|
|
658
633
|
static bool prepare_attribute(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
659
|
-
lexer->mark_end(lexer);
|
|
660
634
|
Cursor r = cursor(s, lexer, s->line_end);
|
|
661
635
|
const bool modified = r.c == '-' || r.c == '!';
|
|
662
636
|
s->name_start = s->position + (modified ? 1 : 0);
|
|
663
637
|
s->name_end = NONE;
|
|
664
638
|
while (r.c != CURSOR_END && !whitespace(r.c)) {
|
|
665
|
-
if (r.c == '=' && s->name_end == NONE)
|
|
666
|
-
s->name_end = r.start;
|
|
639
|
+
if (r.c == '=' && s->name_end == NONE) s->name_end = r.start;
|
|
667
640
|
step(&r);
|
|
668
641
|
}
|
|
669
642
|
s->token_end = r.start;
|
|
670
|
-
if (s->name_end == NONE)
|
|
671
|
-
s->name_end = r.start;
|
|
643
|
+
if (s->name_end == NONE) s->name_end = r.start;
|
|
672
644
|
return emit(lexer, valid, ATTRIBUTE_START);
|
|
673
645
|
}
|
|
674
646
|
|
|
675
647
|
static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
676
|
-
if (valid[ERROR_SENTINEL])
|
|
677
|
-
|
|
678
|
-
if (valid[LINE_START])
|
|
679
|
-
return start_line(s, lexer, valid);
|
|
648
|
+
if (valid[ERROR_SENTINEL]) return false;
|
|
649
|
+
if (valid[LINE_START]) return start_line(s, lexer, valid);
|
|
680
650
|
if (
|
|
681
651
|
valid[BLANK_START] ||
|
|
682
652
|
valid[COMMENT_START] ||
|
|
@@ -699,30 +669,52 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
699
669
|
absent(lexer, MISSING_SET_CLOSE, INCOMPLETE_SET_CLOSE)
|
|
700
670
|
);
|
|
701
671
|
}
|
|
702
|
-
if (valid[ATTRIBUTE_START])
|
|
703
|
-
return prepare_attribute(s, lexer, valid);
|
|
672
|
+
if (valid[ATTRIBUTE_START]) return prepare_attribute(s, lexer, valid);
|
|
704
673
|
if (valid[ATTRIBUTE_END] && s->position == s->token_end)
|
|
705
674
|
return emit(lexer, valid, ATTRIBUTE_END);
|
|
706
675
|
const bool at_name =
|
|
707
676
|
s->position == s->name_start && s->position < s->name_end;
|
|
708
|
-
if (valid[NAME_START] && at_name)
|
|
709
|
-
return emit(lexer, valid, NAME_START);
|
|
677
|
+
if (valid[NAME_START] && at_name) return emit(lexer, valid, NAME_START);
|
|
710
678
|
if (valid[NAME_END] && s->position == s->name_end)
|
|
711
679
|
return emit(lexer, valid, NAME_END);
|
|
712
680
|
if (valid[VALUE_START] && s->position < s->token_end)
|
|
713
681
|
return emit(lexer, valid, VALUE_START);
|
|
714
682
|
if (valid[VALUE_END] && s->position == s->token_end)
|
|
715
683
|
return emit(lexer, valid, VALUE_END);
|
|
716
|
-
if (valid[
|
|
717
|
-
return emit(
|
|
684
|
+
if (valid[MISSING_ATTRIBUTE_NAME] && s->position == s->name_end)
|
|
685
|
+
return emit(
|
|
686
|
+
lexer,
|
|
687
|
+
valid,
|
|
688
|
+
absent(lexer, MISSING_ATTRIBUTE_NAME, INCOMPLETE_ATTRIBUTE_NAME)
|
|
689
|
+
);
|
|
690
|
+
if (
|
|
691
|
+
(valid[UNSET_MARKER] || valid[UNSPECIFIED_MARKER]) &&
|
|
692
|
+
s->position < s->name_start
|
|
693
|
+
)
|
|
694
|
+
return consume(
|
|
695
|
+
s,
|
|
696
|
+
lexer,
|
|
697
|
+
valid,
|
|
698
|
+
lexer->lookahead == '-' ? UNSET_MARKER : UNSPECIFIED_MARKER,
|
|
699
|
+
s->position + 1
|
|
700
|
+
);
|
|
701
|
+
if (valid[NAME_TEXT]) return name_piece(s, lexer, valid);
|
|
702
|
+
if (valid[VALUE_TEXT])
|
|
703
|
+
return text_run(s, lexer, valid, VALUE_TEXT, s->token_end);
|
|
704
|
+
if (valid[ASSIGNMENT_OPERATOR] && lexer->lookahead == '=')
|
|
705
|
+
return consume(s, lexer, valid, ASSIGNMENT_OPERATOR, s->position + 1);
|
|
718
706
|
if (
|
|
719
|
-
(valid[QUOTE_CLOSE] || valid[
|
|
707
|
+
(valid[QUOTE_CLOSE] || valid[MISSING_QUOTE_CLOSE]) &&
|
|
720
708
|
s->quoted &&
|
|
721
709
|
s->position == s->content_end
|
|
722
710
|
) {
|
|
723
711
|
if (s->content_end < s->line_end)
|
|
724
712
|
return consume(s, lexer, valid, QUOTE_CLOSE, s->position + 1);
|
|
725
|
-
return emit(
|
|
713
|
+
return emit(
|
|
714
|
+
lexer,
|
|
715
|
+
valid,
|
|
716
|
+
absent(lexer, MISSING_QUOTE_CLOSE, INCOMPLETE_QUOTE_CLOSE)
|
|
717
|
+
);
|
|
726
718
|
}
|
|
727
719
|
if (valid[PATTERN_END] && s->position >= s->content_end)
|
|
728
720
|
return emit(lexer, valid, PATTERN_END);
|
|
@@ -737,56 +729,27 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
737
729
|
return consume(s, lexer, valid, QUOTE_OPEN, s->position + 1);
|
|
738
730
|
if (valid[MACRO_MARKER])
|
|
739
731
|
return consume(s, lexer, valid, MACRO_MARKER, s->name_start);
|
|
740
|
-
if (
|
|
741
|
-
(valid[UNSET_MARKER] || valid[UNSPECIFIED_MARKER]) &&
|
|
742
|
-
s->position < s->name_start
|
|
743
|
-
)
|
|
744
|
-
return consume(
|
|
745
|
-
s,
|
|
746
|
-
lexer,
|
|
747
|
-
valid,
|
|
748
|
-
lexer->lookahead == '-' ? UNSET_MARKER : UNSPECIFIED_MARKER,
|
|
749
|
-
s->position + 1
|
|
750
|
-
);
|
|
751
|
-
if (valid[NAME_TEXT])
|
|
752
|
-
return name_piece(s, lexer, valid);
|
|
753
|
-
if (valid[VALUE_TEXT])
|
|
754
|
-
return text_run(s, lexer, valid, VALUE_TEXT, s->token_end);
|
|
755
|
-
if (valid[ASSIGNMENT_OPERATOR] && lexer->lookahead == '=')
|
|
756
|
-
return consume(s, lexer, valid, ASSIGNMENT_OPERATOR, s->position + 1);
|
|
757
732
|
if (valid[SEPARATOR] || valid[LAYOUT]) {
|
|
758
733
|
if (!whitespace(lexer->lookahead))
|
|
759
|
-
return emit(lexer, valid,
|
|
734
|
+
return emit(lexer, valid, MISSING_ATTRIBUTE_SEPARATOR);
|
|
760
735
|
while (s->position < s->line_end && whitespace(lexer->lookahead))
|
|
761
736
|
advance(s, lexer);
|
|
762
737
|
lexer->mark_end(lexer);
|
|
763
738
|
return emit(lexer, valid, s->position < s->line_end ? SEPARATOR : LAYOUT);
|
|
764
739
|
}
|
|
765
|
-
if (valid[GLOB_START])
|
|
766
|
-
return prepare_glob(s, lexer, valid);
|
|
740
|
+
if (valid[GLOB_START]) return prepare_glob(s, lexer, valid);
|
|
767
741
|
if (valid[SET_ITEM_START] || valid[SET_NEGATION])
|
|
768
742
|
return prepare_set(s, lexer, valid);
|
|
769
|
-
if (s->
|
|
743
|
+
if (s->class.start < s->position && s->position < s->class.end)
|
|
770
744
|
return class_piece(s, lexer, valid);
|
|
771
745
|
if (s->next == RANGE_START) {
|
|
772
746
|
s->next = RANGE_CHARACTER;
|
|
773
747
|
return emit(lexer, valid, RANGE_START);
|
|
774
748
|
}
|
|
775
|
-
if (s->
|
|
776
|
-
if (s->position == s->lower.end)
|
|
777
|
-
return consume(s, lexer, valid, RANGE_OPERATOR, s->range_operator_end);
|
|
778
|
-
const Item a = s->position < s->lower.end ? s->lower : s->upper;
|
|
779
|
-
return consume(
|
|
780
|
-
s,
|
|
781
|
-
lexer,
|
|
782
|
-
valid,
|
|
783
|
-
a.kind == SET_TEXT ? RANGE_CHARACTER : (enum Token)a.kind,
|
|
784
|
-
a.end
|
|
785
|
-
);
|
|
786
|
-
}
|
|
749
|
+
if (s->upper_end > s->position) return range_piece(s, lexer, valid);
|
|
787
750
|
const enum Token token = (enum Token)s->next;
|
|
788
751
|
if (token == CLASS_OPEN)
|
|
789
|
-
return
|
|
752
|
+
return class_delimiter(s, lexer, valid, COMPOUND_OPEN);
|
|
790
753
|
if (token == ESCAPE_PREFIX) {
|
|
791
754
|
s->next = s->prefix_kind;
|
|
792
755
|
return consume(s, lexer, valid, token, s->prefix_end);
|
|
@@ -816,8 +779,7 @@ void tree_sitter_gitattributes_external_scanner_deserialize(
|
|
|
816
779
|
unsigned length
|
|
817
780
|
) {
|
|
818
781
|
memset(payload, 0, sizeof(Scanner));
|
|
819
|
-
if (length == sizeof(Scanner))
|
|
820
|
-
memcpy(payload, buffer, length);
|
|
782
|
+
if (length == sizeof(Scanner)) memcpy(payload, buffer, length);
|
|
821
783
|
}
|
|
822
784
|
|
|
823
785
|
bool tree_sitter_gitattributes_external_scanner_scan(
|
|
@@ -826,8 +788,7 @@ bool tree_sitter_gitattributes_external_scanner_scan(
|
|
|
826
788
|
const bool *valid
|
|
827
789
|
) {
|
|
828
790
|
Scanner next = *(Scanner *)payload;
|
|
829
|
-
if (!scan(&next, lexer, valid))
|
|
830
|
-
return false;
|
|
791
|
+
if (!scan(&next, lexer, valid)) return false;
|
|
831
792
|
*(Scanner *)payload = next;
|
|
832
793
|
return true;
|
|
833
794
|
}
|