@konomanoasa/tree-sitter-gitattributes 0.2.0 → 0.3.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/Cargo.toml +1 -1
- package/README.md +6 -1
- package/grammar.js +22 -9
- package/package.json +6 -5
- package/src/grammar.json +48 -4
- package/src/node-types.json +15 -4
- package/src/parser.c +2428 -2298
- package/src/scanner.c +124 -132
- package/tree-sitter.json +1 -1
package/src/scanner.c
CHANGED
|
@@ -9,7 +9,6 @@ enum Token {
|
|
|
9
9
|
RULE_START,
|
|
10
10
|
MACRO_START,
|
|
11
11
|
END_OF_FILE,
|
|
12
|
-
LINE_ENDING,
|
|
13
12
|
LAYOUT,
|
|
14
13
|
SEPARATOR,
|
|
15
14
|
ATTRIBUTE_START,
|
|
@@ -66,35 +65,33 @@ enum Token {
|
|
|
66
65
|
MISSING_NAME,
|
|
67
66
|
INCOMPLETE_NAME,
|
|
68
67
|
INVALID_NAME_CHARACTER,
|
|
68
|
+
INVALID_NAME_ESCAPE,
|
|
69
69
|
ERROR_SENTINEL
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
#define NONE UINT32_MAX
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
enum { DECODE_ERROR = -1, CURSOR_END = -2, INVALID_UNIT = -3 };
|
|
75
|
+
|
|
75
76
|
typedef struct {
|
|
76
77
|
uint32_t kind, end, opening_end, closing_start;
|
|
77
78
|
} Item;
|
|
78
79
|
|
|
79
|
-
// Positions
|
|
80
|
-
// are characters or C escapes; ranges stay on the original source. Zero-width
|
|
81
|
-
// start tokens save lookahead decisions before their source is consumed.
|
|
80
|
+
// Positions are line-relative character offsets; uint32_t avoids padding.
|
|
82
81
|
typedef struct {
|
|
83
82
|
uint32_t position, leading, line_end, content_start, content_end, kind;
|
|
84
83
|
uint32_t token_end, name_start, name_end;
|
|
85
84
|
uint32_t next, next_end, prefix_end, prefix_kind;
|
|
86
85
|
uint32_t set_end, set_close_end, class_start, range_operator_end;
|
|
87
86
|
Item class, lower, upper;
|
|
88
|
-
|
|
87
|
+
uint32_t quoted, component_start, after_separator;
|
|
89
88
|
} Scanner;
|
|
90
89
|
|
|
91
90
|
typedef char scanner_fits_buffer
|
|
92
91
|
[sizeof(Scanner) <= TREE_SITTER_SERIALIZATION_BUFFER_SIZE ? 1 : -1];
|
|
93
92
|
|
|
94
|
-
// Negative c values: -1 decode failure, -2 cursor limit, -3 invalid or
|
|
95
|
-
// incomplete escape.
|
|
96
93
|
typedef struct {
|
|
97
|
-
Scanner *s;
|
|
94
|
+
const Scanner *s;
|
|
98
95
|
TSLexer *lexer;
|
|
99
96
|
uint32_t raw, limit, start, end, kind;
|
|
100
97
|
int32_t c;
|
|
@@ -138,9 +135,18 @@ static bool consume(
|
|
|
138
135
|
enum Token token,
|
|
139
136
|
uint32_t end
|
|
140
137
|
) {
|
|
141
|
-
|
|
142
|
-
|
|
138
|
+
if (token == INVALID_ENCODING) {
|
|
139
|
+
do {
|
|
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
|
+
}
|
|
143
146
|
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);
|
|
144
150
|
return emit(lexer, valid, token);
|
|
145
151
|
}
|
|
146
152
|
|
|
@@ -151,9 +157,9 @@ static bool text_run(
|
|
|
151
157
|
enum Token token,
|
|
152
158
|
uint32_t end
|
|
153
159
|
) {
|
|
154
|
-
if (lexer->lookahead ==
|
|
155
|
-
return consume(s, lexer, valid, INVALID_ENCODING,
|
|
156
|
-
while (s->position < end && lexer->lookahead !=
|
|
160
|
+
if (lexer->lookahead == DECODE_ERROR)
|
|
161
|
+
return consume(s, lexer, valid, INVALID_ENCODING, end);
|
|
162
|
+
while (s->position < end && lexer->lookahead != DECODE_ERROR)
|
|
157
163
|
advance(s, lexer);
|
|
158
164
|
lexer->mark_end(lexer);
|
|
159
165
|
return emit(lexer, valid, token);
|
|
@@ -164,42 +170,43 @@ static void raw_step(Cursor *r) {
|
|
|
164
170
|
r->raw++;
|
|
165
171
|
}
|
|
166
172
|
|
|
167
|
-
// Quoted units decode named C escapes or three octal digits starting with 0
|
|
168
|
-
// to 3.
|
|
169
173
|
static void step(Cursor *r) {
|
|
170
174
|
r->start = r->end = r->raw;
|
|
171
175
|
r->kind = 0;
|
|
172
|
-
r->c =
|
|
176
|
+
r->c = CURSOR_END;
|
|
173
177
|
if (r->raw >= r->limit)
|
|
174
178
|
return;
|
|
175
179
|
int32_t c = r->lexer->lookahead;
|
|
176
180
|
raw_step(r);
|
|
177
181
|
r->c = c;
|
|
178
|
-
if (c ==
|
|
182
|
+
if (c == DECODE_ERROR) {
|
|
179
183
|
r->kind = INVALID_ENCODING;
|
|
180
|
-
|
|
184
|
+
while (r->raw < r->limit && r->lexer->lookahead == DECODE_ERROR)
|
|
185
|
+
raw_step(r);
|
|
186
|
+
} else if (r->s->quoted && r->start < r->s->content_end && c == '\\') {
|
|
181
187
|
r->kind = QUOTED_ESCAPE;
|
|
182
188
|
c = r->lexer->lookahead;
|
|
183
189
|
if (r->raw >= r->limit) {
|
|
184
|
-
r->c =
|
|
190
|
+
r->c = INVALID_UNIT;
|
|
185
191
|
r->kind = absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE);
|
|
186
|
-
} else if (c ==
|
|
187
|
-
r->c =
|
|
192
|
+
} else if (c == DECODE_ERROR) {
|
|
193
|
+
r->c = INVALID_UNIT;
|
|
188
194
|
r->kind = ESCAPE_PREFIX;
|
|
189
195
|
} else if (c >= '0' && c <= '3') {
|
|
190
196
|
int32_t value = 0;
|
|
191
197
|
unsigned digits = 0;
|
|
192
198
|
while (digits < 3 && r->raw < r->limit) {
|
|
193
|
-
int32_t digit = r->lexer->lookahead;
|
|
199
|
+
const int32_t digit = r->lexer->lookahead;
|
|
194
200
|
if (digit < '0' || digit > '7')
|
|
195
201
|
break;
|
|
196
202
|
value = value * 8 + digit - '0';
|
|
197
203
|
raw_step(r);
|
|
198
204
|
digits++;
|
|
199
205
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
206
|
+
if (digits == 3)
|
|
207
|
+
r->c = value;
|
|
208
|
+
else {
|
|
209
|
+
r->c = INVALID_UNIT;
|
|
203
210
|
r->kind = r->raw == r->limit
|
|
204
211
|
? absent(r->lexer, ENDED_QUOTED_ESCAPE, INCOMPLETE_QUOTED_ESCAPE)
|
|
205
212
|
: ENDED_QUOTED_ESCAPE;
|
|
@@ -233,7 +240,7 @@ static void step(Cursor *r) {
|
|
|
233
240
|
r->c = c;
|
|
234
241
|
break;
|
|
235
242
|
default:
|
|
236
|
-
r->c =
|
|
243
|
+
r->c = INVALID_UNIT;
|
|
237
244
|
r->kind = INVALID_QUOTED_ESCAPE;
|
|
238
245
|
break;
|
|
239
246
|
}
|
|
@@ -242,66 +249,62 @@ static void step(Cursor *r) {
|
|
|
242
249
|
r->end = r->raw;
|
|
243
250
|
}
|
|
244
251
|
|
|
245
|
-
static Cursor cursor(Scanner *s, TSLexer *lexer, uint32_t limit) {
|
|
252
|
+
static Cursor cursor(const Scanner *s, TSLexer *lexer, uint32_t limit) {
|
|
246
253
|
Cursor r = {.s = s, .lexer = lexer, .raw = s->position, .limit = limit};
|
|
247
254
|
step(&r);
|
|
248
255
|
return r;
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
// An unclosed quote leaves the pattern content ending at the line end.
|
|
252
258
|
static bool start_line(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
253
259
|
if (lexer->eof(lexer))
|
|
254
260
|
return false;
|
|
255
|
-
|
|
256
|
-
|
|
261
|
+
memset(s, 0, sizeof(*s));
|
|
262
|
+
s->class_start = NONE;
|
|
263
|
+
s->component_start = true;
|
|
257
264
|
int32_t last = 0;
|
|
258
265
|
lexer->mark_end(lexer);
|
|
259
266
|
while (!lexer->eof(lexer) && whitespace(lexer->lookahead)) {
|
|
260
267
|
last = lexer->lookahead;
|
|
261
|
-
advance(
|
|
268
|
+
advance(s, lexer);
|
|
262
269
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
s->leading = s->position;
|
|
271
|
+
s->kind = lexer->lookahead == '#' ? COMMENT_START : RULE_START;
|
|
272
|
+
s->quoted = lexer->lookahead == '"';
|
|
273
|
+
s->content_start = s->leading + (s->quoted ? 1 : 0);
|
|
274
|
+
s->content_end = NONE;
|
|
268
275
|
bool escaped = false;
|
|
269
276
|
while (!lexer->eof(lexer) && lexer->lookahead != '\n') {
|
|
270
|
-
int32_t c = lexer->lookahead;
|
|
271
|
-
if (
|
|
272
|
-
if (
|
|
277
|
+
const int32_t c = lexer->lookahead;
|
|
278
|
+
if (s->position >= s->content_start && s->content_end == NONE) {
|
|
279
|
+
if (s->quoted) {
|
|
273
280
|
if (c == '"' && !escaped)
|
|
274
|
-
|
|
281
|
+
s->content_end = s->position;
|
|
275
282
|
escaped = c == '\\' && !escaped;
|
|
276
283
|
} else if (whitespace(c))
|
|
277
|
-
|
|
284
|
+
s->content_end = s->position;
|
|
278
285
|
}
|
|
279
286
|
last = c;
|
|
280
|
-
advance(
|
|
287
|
+
advance(s, lexer);
|
|
281
288
|
}
|
|
282
|
-
|
|
289
|
+
s->line_end = s->position;
|
|
283
290
|
if (last == '\r' && lexer->lookahead == '\n')
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
line.position = 0;
|
|
293
|
-
line.class_start = NONE;
|
|
294
|
-
line.component_start = true;
|
|
295
|
-
*s = line;
|
|
291
|
+
s->line_end--;
|
|
292
|
+
if (s->leading > s->line_end)
|
|
293
|
+
s->leading = s->line_end;
|
|
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;
|
|
298
|
+
s->position = 0;
|
|
296
299
|
return emit(lexer, valid, LINE_START);
|
|
297
300
|
}
|
|
298
301
|
|
|
299
|
-
// Compare the macro marker after decoding C escapes.
|
|
300
302
|
static bool start_content(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
301
303
|
while (s->position < s->leading)
|
|
302
304
|
advance(s, lexer);
|
|
303
305
|
lexer->mark_end(lexer);
|
|
304
306
|
if (s->kind == RULE_START) {
|
|
307
|
+
// The opening quote is lookahead; QUOTE_OPEN consumes it later.
|
|
305
308
|
if (s->quoted)
|
|
306
309
|
lexer->advance(lexer, false);
|
|
307
310
|
Cursor r = {
|
|
@@ -336,16 +339,12 @@ static void skip_escaped(Cursor *r, Cursor *last, uint32_t *candidate) {
|
|
|
336
339
|
}
|
|
337
340
|
|
|
338
341
|
// Escapes and range upper endpoints take precedence over class candidates.
|
|
339
|
-
// A candidate starts at [: and ends at the first unescaped ], preceded by a
|
|
340
|
-
// colon other than the opening one. An escaped ] cancels it; candidate units
|
|
341
|
-
// remain ordinary items. `lower` records an available lower endpoint.
|
|
342
|
-
// Success leaves the cursor after the class; failure at ] or the limit.
|
|
343
342
|
static bool next_class(Cursor *r, bool lower, uint32_t *start, Item *class) {
|
|
344
343
|
Item a = {CLASS_OPEN, 0, 0, 0};
|
|
345
344
|
uint32_t candidate = NONE;
|
|
346
345
|
Cursor last = *r;
|
|
347
|
-
while (r->c !=
|
|
348
|
-
int32_t here = r->c;
|
|
346
|
+
while (r->c != CURSOR_END) {
|
|
347
|
+
const int32_t here = r->c;
|
|
349
348
|
if (here == ']') {
|
|
350
349
|
if (candidate == NONE || last.c != ':' || last.end == a.opening_end)
|
|
351
350
|
return false;
|
|
@@ -360,14 +359,14 @@ static bool next_class(Cursor *r, bool lower, uint32_t *start, Item *class) {
|
|
|
360
359
|
step(r);
|
|
361
360
|
if (here == '\\') {
|
|
362
361
|
lower = r->c >= 0;
|
|
363
|
-
if (r->c !=
|
|
362
|
+
if (r->c != CURSOR_END)
|
|
364
363
|
skip_escaped(r, &last, &candidate);
|
|
365
364
|
continue;
|
|
366
365
|
}
|
|
367
|
-
if (here == '-' && lower && r->c !=
|
|
368
|
-
int32_t upper = r->c;
|
|
366
|
+
if (here == '-' && lower && r->c != CURSOR_END && r->c != ']') {
|
|
367
|
+
const int32_t upper = r->c;
|
|
369
368
|
skip_escaped(r, &last, &candidate);
|
|
370
|
-
if (upper == '\\' && r->c !=
|
|
369
|
+
if (upper == '\\' && r->c != CURSOR_END)
|
|
371
370
|
skip_escaped(r, &last, &candidate);
|
|
372
371
|
lower = false;
|
|
373
372
|
continue;
|
|
@@ -381,7 +380,6 @@ static bool next_class(Cursor *r, bool lower, uint32_t *start, Item *class) {
|
|
|
381
380
|
return false;
|
|
382
381
|
}
|
|
383
382
|
|
|
384
|
-
// The cursor must be after the opening bracket.
|
|
385
383
|
static void find_set(Scanner *s, Cursor *r) {
|
|
386
384
|
s->set_end = s->set_close_end = s->content_end;
|
|
387
385
|
s->class_start = NONE;
|
|
@@ -407,13 +405,13 @@ static void find_set(Scanner *s, Cursor *r) {
|
|
|
407
405
|
|
|
408
406
|
static Item item(Cursor *r) {
|
|
409
407
|
Item a = {SET_TEXT, 0, 0, 0};
|
|
410
|
-
if (r->c ==
|
|
408
|
+
if (r->c == CURSOR_END)
|
|
411
409
|
return a;
|
|
412
|
-
int32_t c = r->c;
|
|
413
|
-
uint32_t end = r->end;
|
|
410
|
+
const int32_t c = r->c;
|
|
411
|
+
const uint32_t end = r->end;
|
|
414
412
|
if (c == '[' && r->start == r->s->class_start) {
|
|
415
413
|
a = r->s->class;
|
|
416
|
-
while (r->c !=
|
|
414
|
+
while (r->c != CURSOR_END && r->start < a.end)
|
|
417
415
|
step(r);
|
|
418
416
|
return a;
|
|
419
417
|
}
|
|
@@ -421,7 +419,7 @@ static Item item(Cursor *r) {
|
|
|
421
419
|
a.kind = r->kind;
|
|
422
420
|
step(r);
|
|
423
421
|
if (c == '\\') {
|
|
424
|
-
if (r->c ==
|
|
422
|
+
if (r->c == CURSOR_END)
|
|
425
423
|
a.kind = absent(r->lexer, INVALID_ESCAPE, INCOMPLETE_ESCAPE);
|
|
426
424
|
else if (r->c < 0)
|
|
427
425
|
a.kind = ESCAPE_PREFIX;
|
|
@@ -441,20 +439,14 @@ static bool endpoint(Item a) {
|
|
|
441
439
|
(a.kind == SET_TEXT || a.kind == ESCAPE || a.kind == QUOTED_ESCAPE);
|
|
442
440
|
}
|
|
443
441
|
|
|
444
|
-
static bool
|
|
445
|
-
return c == '\\' || c == '*' || c == '?' || c == '/';
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// End literal runs before [ so the set can be decided.
|
|
449
|
-
static bool special(const Cursor *r) {
|
|
442
|
+
static bool literal_boundary(const Cursor *r) {
|
|
450
443
|
if (r->c < 0 || r->kind == QUOTED_ESCAPE)
|
|
451
444
|
return true;
|
|
452
|
-
|
|
445
|
+
const int32_t c = r->c;
|
|
446
|
+
return c == '\\' || c == '*' || c == '?' || c == '/' || c == '[';
|
|
453
447
|
}
|
|
454
448
|
|
|
455
|
-
//
|
|
456
|
-
// up to `prefix_end`, and the unit's own issue follows. A C escape prefix
|
|
457
|
-
// before an undecodable byte extends the held prefix to that byte.
|
|
449
|
+
// Keep the backslash in its owner; report the following unit's own issue.
|
|
458
450
|
static void hold_prefix(Scanner *s, Cursor *r, uint32_t prefix_end) {
|
|
459
451
|
s->next = ESCAPE_PREFIX;
|
|
460
452
|
s->prefix_end = prefix_end;
|
|
@@ -467,12 +459,12 @@ static void hold_prefix(Scanner *s, Cursor *r, uint32_t prefix_end) {
|
|
|
467
459
|
s->next_end = r->end;
|
|
468
460
|
}
|
|
469
461
|
|
|
470
|
-
//
|
|
471
|
-
// decision. Nonliteral tokens are decided here and consumed by the next call.
|
|
462
|
+
// Consume lookahead units fully so edits inside them invalidate the decision.
|
|
472
463
|
static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
473
464
|
lexer->mark_end(lexer);
|
|
474
465
|
Cursor r = cursor(s, lexer, s->content_end);
|
|
475
|
-
|
|
466
|
+
bool separator = r.c == '/';
|
|
467
|
+
const uint32_t start = s->position;
|
|
476
468
|
s->next_end = r.end;
|
|
477
469
|
if (r.c < 0) {
|
|
478
470
|
if (r.kind == ESCAPE_PREFIX)
|
|
@@ -487,13 +479,14 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
487
479
|
s->next = PATH_SEPARATOR;
|
|
488
480
|
else if (r.c == '\\') {
|
|
489
481
|
step(&r);
|
|
490
|
-
if (r.c ==
|
|
482
|
+
if (r.c == CURSOR_END)
|
|
491
483
|
s->next = absent(lexer, INVALID_ESCAPE, INCOMPLETE_ESCAPE);
|
|
492
484
|
else if (r.c < 0)
|
|
493
485
|
hold_prefix(s, &r, s->next_end);
|
|
494
486
|
else {
|
|
495
487
|
s->next = ESCAPE;
|
|
496
488
|
s->next_end = r.end;
|
|
489
|
+
separator = r.c == '/';
|
|
497
490
|
}
|
|
498
491
|
} else if (r.c == '*') {
|
|
499
492
|
unsigned count = 0;
|
|
@@ -502,9 +495,11 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
502
495
|
s->next_end = r.end;
|
|
503
496
|
step(&r);
|
|
504
497
|
}
|
|
505
|
-
bool pair = count == 2 && s->component_start;
|
|
506
|
-
bool
|
|
507
|
-
|
|
498
|
+
const bool pair = count == 2 && s->component_start;
|
|
499
|
+
const bool tail = r.c == CURSOR_END && s->after_separator;
|
|
500
|
+
if (r.c == '\\')
|
|
501
|
+
step(&r);
|
|
502
|
+
const bool slash = r.c == '/';
|
|
508
503
|
s->next = pair && (slash || tail) ? RECURSIVE_WILDCARD : WILDCARD;
|
|
509
504
|
} else if (r.kind == QUOTED_ESCAPE && r.c != '[')
|
|
510
505
|
s->next = QUOTED_ESCAPE;
|
|
@@ -516,7 +511,7 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
516
511
|
uint32_t end = r.end;
|
|
517
512
|
lexer->mark_end(lexer);
|
|
518
513
|
step(&r);
|
|
519
|
-
while (!
|
|
514
|
+
while (!literal_boundary(&r)) {
|
|
520
515
|
end = r.end;
|
|
521
516
|
lexer->mark_end(lexer);
|
|
522
517
|
step(&r);
|
|
@@ -525,13 +520,16 @@ static bool prepare_glob(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
525
520
|
s->component_start = false;
|
|
526
521
|
return emit(lexer, valid, LITERAL);
|
|
527
522
|
}
|
|
523
|
+
s->component_start = separator || s->next == NEGATIVE_PATTERN;
|
|
524
|
+
if (separator)
|
|
525
|
+
s->after_separator = true;
|
|
528
526
|
return emit(lexer, valid, GLOB_START);
|
|
529
527
|
}
|
|
530
528
|
|
|
531
529
|
static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
532
530
|
lexer->mark_end(lexer);
|
|
533
531
|
Cursor r = cursor(s, lexer, s->set_end);
|
|
534
|
-
uint32_t start = s->position;
|
|
532
|
+
const uint32_t start = s->position;
|
|
535
533
|
if (valid[SET_NEGATION] && (r.c == '!' || r.c == '^')) {
|
|
536
534
|
s->position = r.end;
|
|
537
535
|
lexer->mark_end(lexer);
|
|
@@ -543,10 +541,10 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
543
541
|
Item current = item(&r);
|
|
544
542
|
for (;;) {
|
|
545
543
|
if (endpoint(current) && r.c == '-' && r.end < s->set_end) {
|
|
546
|
-
uint32_t operator_end = r.end;
|
|
547
|
-
bool plain_operator = r.kind != QUOTED_ESCAPE;
|
|
544
|
+
const uint32_t operator_end = r.end;
|
|
545
|
+
const bool plain_operator = r.kind != QUOTED_ESCAPE;
|
|
548
546
|
step(&r);
|
|
549
|
-
Item upper = item(&r);
|
|
547
|
+
const Item upper = item(&r);
|
|
550
548
|
if (endpoint(upper)) {
|
|
551
549
|
if (here == start) {
|
|
552
550
|
s->next = RANGE_START;
|
|
@@ -558,8 +556,6 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
558
556
|
break;
|
|
559
557
|
}
|
|
560
558
|
if (current.kind == SET_TEXT) {
|
|
561
|
-
// A literal hyphen joins the text run; an escaped one stays a
|
|
562
|
-
// separate `quoted_escape`.
|
|
563
559
|
if (!plain_operator) {
|
|
564
560
|
s->next_end = current.end;
|
|
565
561
|
break;
|
|
@@ -582,7 +578,7 @@ static bool prepare_set(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
582
578
|
}
|
|
583
579
|
s->next_end = current.end;
|
|
584
580
|
here = r.start;
|
|
585
|
-
if (r.c ==
|
|
581
|
+
if (r.c == CURSOR_END)
|
|
586
582
|
break;
|
|
587
583
|
current = item(&r);
|
|
588
584
|
}
|
|
@@ -597,7 +593,6 @@ unit_token(Scanner *s, TSLexer *lexer, const bool *valid, enum Token token) {
|
|
|
597
593
|
return emit(lexer, valid, token);
|
|
598
594
|
}
|
|
599
595
|
|
|
600
|
-
// Closing a class term must find the next class in the set.
|
|
601
596
|
static bool class_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
602
597
|
if (s->position < s->class.opening_end)
|
|
603
598
|
return consume(s, lexer, valid, CLASS_OPEN, s->class.opening_end);
|
|
@@ -612,8 +607,10 @@ static bool class_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
612
607
|
s->class_start = NONE;
|
|
613
608
|
return emit(lexer, valid, COMPOUND_CLOSE);
|
|
614
609
|
}
|
|
610
|
+
if (lexer->lookahead == DECODE_ERROR)
|
|
611
|
+
return consume(s, lexer, valid, INVALID_ENCODING, s->class.closing_start);
|
|
615
612
|
Cursor r = cursor(s, lexer, s->class.closing_start);
|
|
616
|
-
enum Token token = r.kind ? (enum Token)r.kind : CLASS_NAME;
|
|
613
|
+
const enum Token token = r.kind ? (enum Token)r.kind : CLASS_NAME;
|
|
617
614
|
uint32_t end = r.end;
|
|
618
615
|
lexer->mark_end(lexer);
|
|
619
616
|
if (token == CLASS_NAME) {
|
|
@@ -629,23 +626,26 @@ static bool class_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
629
626
|
}
|
|
630
627
|
|
|
631
628
|
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);
|
|
632
631
|
Cursor r = cursor(s, lexer, s->name_end);
|
|
633
632
|
enum Token token;
|
|
634
|
-
if (r.kind == ESCAPE_PREFIX)
|
|
633
|
+
if (r.kind == ESCAPE_PREFIX)
|
|
635
634
|
s->next = INVALID_ENCODING;
|
|
636
|
-
s->next_end = r.end + 1;
|
|
637
|
-
}
|
|
638
635
|
if (r.c < 0)
|
|
639
636
|
token = (enum Token)r.kind;
|
|
640
637
|
else if (!name_character(r.c, s->position == s->name_start))
|
|
641
|
-
token =
|
|
638
|
+
token =
|
|
639
|
+
r.kind == QUOTED_ESCAPE ? INVALID_NAME_ESCAPE : INVALID_NAME_CHARACTER;
|
|
642
640
|
else
|
|
643
641
|
token = r.kind == QUOTED_ESCAPE ? QUOTED_ESCAPE : NAME_TEXT;
|
|
644
642
|
uint32_t end = r.end;
|
|
645
643
|
lexer->mark_end(lexer);
|
|
646
|
-
if (token == NAME_TEXT) {
|
|
644
|
+
if (token == NAME_TEXT || token == INVALID_NAME_CHARACTER) {
|
|
647
645
|
step(&r);
|
|
648
|
-
while (
|
|
646
|
+
while (
|
|
647
|
+
r.c >= 0 && !r.kind && name_character(r.c, false) == (token == NAME_TEXT)
|
|
648
|
+
) {
|
|
649
649
|
end = r.end;
|
|
650
650
|
lexer->mark_end(lexer);
|
|
651
651
|
step(&r);
|
|
@@ -657,19 +657,18 @@ static bool name_piece(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
657
657
|
|
|
658
658
|
static bool prepare_attribute(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
659
659
|
lexer->mark_end(lexer);
|
|
660
|
-
|
|
661
|
-
bool modified =
|
|
660
|
+
Cursor r = cursor(s, lexer, s->line_end);
|
|
661
|
+
const bool modified = r.c == '-' || r.c == '!';
|
|
662
662
|
s->name_start = s->position + (modified ? 1 : 0);
|
|
663
663
|
s->name_end = NONE;
|
|
664
|
-
while (
|
|
665
|
-
if (
|
|
666
|
-
s->name_end =
|
|
667
|
-
|
|
668
|
-
position++;
|
|
664
|
+
while (r.c != CURSOR_END && !whitespace(r.c)) {
|
|
665
|
+
if (r.c == '=' && s->name_end == NONE)
|
|
666
|
+
s->name_end = r.start;
|
|
667
|
+
step(&r);
|
|
669
668
|
}
|
|
670
|
-
s->token_end =
|
|
669
|
+
s->token_end = r.start;
|
|
671
670
|
if (s->name_end == NONE)
|
|
672
|
-
s->name_end =
|
|
671
|
+
s->name_end = r.start;
|
|
673
672
|
return emit(lexer, valid, ATTRIBUTE_START);
|
|
674
673
|
}
|
|
675
674
|
|
|
@@ -704,7 +703,8 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
704
703
|
return prepare_attribute(s, lexer, valid);
|
|
705
704
|
if (valid[ATTRIBUTE_END] && s->position == s->token_end)
|
|
706
705
|
return emit(lexer, valid, ATTRIBUTE_END);
|
|
707
|
-
bool at_name =
|
|
706
|
+
const bool at_name =
|
|
707
|
+
s->position == s->name_start && s->position < s->name_end;
|
|
708
708
|
if (valid[NAME_START] && at_name)
|
|
709
709
|
return emit(lexer, valid, NAME_START);
|
|
710
710
|
if (valid[NAME_END] && s->position == s->name_end)
|
|
@@ -726,17 +726,8 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
726
726
|
}
|
|
727
727
|
if (valid[PATTERN_END] && s->position >= s->content_end)
|
|
728
728
|
return emit(lexer, valid, PATTERN_END);
|
|
729
|
-
if (s->position >= s->line_end)
|
|
730
|
-
|
|
731
|
-
return emit(lexer, valid, END_OF_FILE);
|
|
732
|
-
if (lexer->lookahead == '\r')
|
|
733
|
-
advance(s, lexer);
|
|
734
|
-
if (lexer->lookahead != '\n')
|
|
735
|
-
return false;
|
|
736
|
-
advance(s, lexer);
|
|
737
|
-
lexer->mark_end(lexer);
|
|
738
|
-
return emit(lexer, valid, LINE_ENDING);
|
|
739
|
-
}
|
|
729
|
+
if (s->position >= s->line_end)
|
|
730
|
+
return lexer->eof(lexer) && emit(lexer, valid, END_OF_FILE);
|
|
740
731
|
if (s->kind == COMMENT_START) {
|
|
741
732
|
if (s->position == s->leading)
|
|
742
733
|
return consume(s, lexer, valid, COMMENT_MARKER, s->position + 1);
|
|
@@ -784,7 +775,7 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
784
775
|
if (s->upper.end > s->position) {
|
|
785
776
|
if (s->position == s->lower.end)
|
|
786
777
|
return consume(s, lexer, valid, RANGE_OPERATOR, s->range_operator_end);
|
|
787
|
-
Item a = s->position < s->lower.end ? s->lower : s->upper;
|
|
778
|
+
const Item a = s->position < s->lower.end ? s->lower : s->upper;
|
|
788
779
|
return consume(
|
|
789
780
|
s,
|
|
790
781
|
lexer,
|
|
@@ -793,25 +784,24 @@ static bool scan(Scanner *s, TSLexer *lexer, const bool *valid) {
|
|
|
793
784
|
a.end
|
|
794
785
|
);
|
|
795
786
|
}
|
|
796
|
-
enum Token token = (enum Token)s->next;
|
|
787
|
+
const enum Token token = (enum Token)s->next;
|
|
797
788
|
if (token == CLASS_OPEN)
|
|
798
789
|
return unit_token(s, lexer, valid, COMPOUND_OPEN);
|
|
799
790
|
if (token == ESCAPE_PREFIX) {
|
|
800
791
|
s->next = s->prefix_kind;
|
|
801
792
|
return consume(s, lexer, valid, token, s->prefix_end);
|
|
802
793
|
}
|
|
803
|
-
s->component_start = token == PATH_SEPARATOR || token == NEGATIVE_PATTERN;
|
|
804
|
-
if (token == PATH_SEPARATOR)
|
|
805
|
-
s->after_separator = true;
|
|
806
794
|
return consume(s, lexer, valid, token, s->next_end);
|
|
807
795
|
}
|
|
808
796
|
|
|
809
797
|
void *tree_sitter_gitattributes_external_scanner_create(void) {
|
|
810
798
|
return ts_calloc(1, sizeof(Scanner));
|
|
811
799
|
}
|
|
800
|
+
|
|
812
801
|
void tree_sitter_gitattributes_external_scanner_destroy(void *payload) {
|
|
813
802
|
ts_free(payload);
|
|
814
803
|
}
|
|
804
|
+
|
|
815
805
|
unsigned tree_sitter_gitattributes_external_scanner_serialize(
|
|
816
806
|
void *payload,
|
|
817
807
|
char *buffer
|
|
@@ -819,6 +809,7 @@ unsigned tree_sitter_gitattributes_external_scanner_serialize(
|
|
|
819
809
|
memcpy(buffer, payload, sizeof(Scanner));
|
|
820
810
|
return sizeof(Scanner);
|
|
821
811
|
}
|
|
812
|
+
|
|
822
813
|
void tree_sitter_gitattributes_external_scanner_deserialize(
|
|
823
814
|
void *payload,
|
|
824
815
|
const char *buffer,
|
|
@@ -828,6 +819,7 @@ void tree_sitter_gitattributes_external_scanner_deserialize(
|
|
|
828
819
|
if (length == sizeof(Scanner))
|
|
829
820
|
memcpy(payload, buffer, length);
|
|
830
821
|
}
|
|
822
|
+
|
|
831
823
|
bool tree_sitter_gitattributes_external_scanner_scan(
|
|
832
824
|
void *payload,
|
|
833
825
|
TSLexer *lexer,
|