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