@konomanoasa/tree-sitter-yaml 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +36 -0
- package/LICENSE +21 -0
- package/README.md +39 -0
- package/bindings/rust/build.rs +23 -0
- package/bindings/rust/lib.rs +12 -0
- package/grammar.js +820 -0
- package/package.json +45 -0
- package/queries/highlights.scm +89 -0
- package/src/grammar.json +6888 -0
- package/src/node-types.json +2561 -0
- package/src/parser.c +119335 -0
- package/src/scanner.c +2655 -0
- package/src/tree_sitter/alloc.h +54 -0
- package/src/tree_sitter/array.h +336 -0
- package/src/tree_sitter/parser.h +286 -0
- package/test/bindings.test.rs +562 -0
- package/tree-sitter.json +30 -0
package/src/scanner.c
ADDED
|
@@ -0,0 +1,2655 @@
|
|
|
1
|
+
#include "tree_sitter/alloc.h"
|
|
2
|
+
#include "tree_sitter/parser.h"
|
|
3
|
+
#include <stdint.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
enum Token {
|
|
7
|
+
LINE_BREAK,
|
|
8
|
+
END_OF_FILE,
|
|
9
|
+
DOCUMENT_OPEN,
|
|
10
|
+
DOCUMENT_CLOSE,
|
|
11
|
+
DOCUMENT_START,
|
|
12
|
+
DOCUMENT_END,
|
|
13
|
+
BYTE_ORDER_MARK,
|
|
14
|
+
INDENT,
|
|
15
|
+
DEDENT,
|
|
16
|
+
OUTDENT,
|
|
17
|
+
RESTORE_INDENT,
|
|
18
|
+
MAPPING_START,
|
|
19
|
+
MAPPING_END,
|
|
20
|
+
PAIR_START,
|
|
21
|
+
SEQUENCE_START,
|
|
22
|
+
SEQUENCE_END,
|
|
23
|
+
ENTRY_START,
|
|
24
|
+
VALUE_START,
|
|
25
|
+
SEQUENCE_VALUE_START,
|
|
26
|
+
EMPTY_BLOCK_NODE,
|
|
27
|
+
EXPLICIT_VALUE_START,
|
|
28
|
+
INVALID_COMPACT_START,
|
|
29
|
+
SEQUENCE_INDICATOR,
|
|
30
|
+
VALUE_INDICATOR,
|
|
31
|
+
KEY_INDICATOR,
|
|
32
|
+
SINGLE_START,
|
|
33
|
+
DOUBLE_START,
|
|
34
|
+
FLOW_SEQUENCE_START,
|
|
35
|
+
FLOW_MAPPING_START,
|
|
36
|
+
FLOW_MAP_PAIR_START,
|
|
37
|
+
FLOW_SEQ_PAIR_START,
|
|
38
|
+
IMPLICIT_KEY_START,
|
|
39
|
+
KEY_END,
|
|
40
|
+
INVALID_KEY_END,
|
|
41
|
+
FLOW_NODE_END,
|
|
42
|
+
PLAIN_START,
|
|
43
|
+
PLAIN_END,
|
|
44
|
+
PLAIN_CONTINUE,
|
|
45
|
+
SCALAR_TEXT,
|
|
46
|
+
SINGLE_OPEN,
|
|
47
|
+
DOUBLE_OPEN,
|
|
48
|
+
QUOTE_CLOSE,
|
|
49
|
+
QUOTED_ESCAPE,
|
|
50
|
+
ESCAPED_QUOTE,
|
|
51
|
+
SCALAR_LINE_BREAK,
|
|
52
|
+
SCALAR_LINE_PREFIX,
|
|
53
|
+
SCALAR_LINE_SUFFIX,
|
|
54
|
+
ESCAPE_INDICATOR,
|
|
55
|
+
FLOW_SEQUENCE_OPEN,
|
|
56
|
+
FLOW_SEQUENCE_CLOSE,
|
|
57
|
+
FLOW_MAPPING_OPEN,
|
|
58
|
+
FLOW_MAPPING_CLOSE,
|
|
59
|
+
FLOW_SEPARATOR,
|
|
60
|
+
COMMENT_START,
|
|
61
|
+
COMMENT_MARKER,
|
|
62
|
+
COMMENT_TEXT,
|
|
63
|
+
COMMENT_END,
|
|
64
|
+
LINE_PREFIX_START,
|
|
65
|
+
LINE_PREFIX_END,
|
|
66
|
+
INDENTATION,
|
|
67
|
+
SEPARATION,
|
|
68
|
+
LINE_CONTEXT,
|
|
69
|
+
LITERAL_START,
|
|
70
|
+
FOLDED_START,
|
|
71
|
+
LITERAL_INDICATOR,
|
|
72
|
+
FOLDED_INDICATOR,
|
|
73
|
+
INDENTATION_INDICATOR,
|
|
74
|
+
CHOMPING_INDICATOR,
|
|
75
|
+
BLOCK_HEADER_BREAK,
|
|
76
|
+
BLOCK_HEADER_END,
|
|
77
|
+
BLOCK_BODY_START,
|
|
78
|
+
BLOCK_SCALAR_END,
|
|
79
|
+
BLOCK_TEXT_LINE_START,
|
|
80
|
+
BLOCK_SPACED_LINE_START,
|
|
81
|
+
BLOCK_EMPTY_LINE_START,
|
|
82
|
+
BLOCK_LINE_END,
|
|
83
|
+
BOUNDARY_CHECK,
|
|
84
|
+
DOCUMENT_CONTENT_END,
|
|
85
|
+
DOCUMENT_COMPACT_START,
|
|
86
|
+
UNEXPECTED_CONTENT_START,
|
|
87
|
+
PROPERTIES_START,
|
|
88
|
+
PROPERTIES_END,
|
|
89
|
+
PROPERTY_CONTENT_START,
|
|
90
|
+
BLOCK_PROPERTY_CONTENT_START,
|
|
91
|
+
BLOCK_KEY_CONTENT_START,
|
|
92
|
+
DUPLICATE_ANCHOR_START,
|
|
93
|
+
DUPLICATE_TAG_START,
|
|
94
|
+
PROPERTY_ALIAS_START,
|
|
95
|
+
PROPERTY_COMPACT_START,
|
|
96
|
+
ANCHOR_INDICATOR,
|
|
97
|
+
ALIAS_START,
|
|
98
|
+
ALIAS_INDICATOR,
|
|
99
|
+
ANCHOR_NAME,
|
|
100
|
+
ALIAS_NAME,
|
|
101
|
+
NAME_END,
|
|
102
|
+
VERBATIM_TAG_START,
|
|
103
|
+
VERBATIM_TAG_OPEN,
|
|
104
|
+
VERBATIM_TAG_CLOSE,
|
|
105
|
+
SHORTHAND_TAG_START,
|
|
106
|
+
NON_SPECIFIC_TAG,
|
|
107
|
+
TAG_HANDLE_START,
|
|
108
|
+
PRIMARY_TAG_HANDLE,
|
|
109
|
+
SECONDARY_TAG_HANDLE,
|
|
110
|
+
TAG_HANDLE_OPEN,
|
|
111
|
+
TAG_HANDLE_NAME,
|
|
112
|
+
TAG_HANDLE_CLOSE,
|
|
113
|
+
TAG_SUFFIX_START,
|
|
114
|
+
TAG_END,
|
|
115
|
+
TAG_URI_START,
|
|
116
|
+
TAG_URI_END,
|
|
117
|
+
URI_TEXT,
|
|
118
|
+
TAG_SUFFIX_TEXT,
|
|
119
|
+
URI_ESCAPE,
|
|
120
|
+
YAML_DIRECTIVE_START,
|
|
121
|
+
TAG_DIRECTIVE_START,
|
|
122
|
+
RESERVED_DIRECTIVE_START,
|
|
123
|
+
DIRECTIVE_INDICATOR,
|
|
124
|
+
DIRECTIVE_NAME,
|
|
125
|
+
DIRECTIVE_NAME_END,
|
|
126
|
+
DIRECTIVE_END,
|
|
127
|
+
YAML_VERSION,
|
|
128
|
+
TAG_PREFIX_START,
|
|
129
|
+
TAG_PREFIX_END,
|
|
130
|
+
DIRECTIVE_PARAMETER,
|
|
131
|
+
INVALID_ENCODING,
|
|
132
|
+
INVALID_CHARACTER,
|
|
133
|
+
INVALID_ESCAPE,
|
|
134
|
+
INCOMPLETE_ESCAPE,
|
|
135
|
+
INVALID_LINE_CONTINUATION,
|
|
136
|
+
INVALID_SCALAR_START,
|
|
137
|
+
MISSING_FLOW_SEPARATOR,
|
|
138
|
+
UNEXPECTED_FLOW_SEPARATOR,
|
|
139
|
+
INVALID_INDENTATION,
|
|
140
|
+
MISSING_INDENTATION,
|
|
141
|
+
MISSING_SEPARATION,
|
|
142
|
+
INVALID_BLOCK_HEADER,
|
|
143
|
+
INVALID_TAG_HANDLE,
|
|
144
|
+
INVALID_TAG_CHARACTER,
|
|
145
|
+
INVALID_URI_ESCAPE,
|
|
146
|
+
INCOMPLETE_URI_ESCAPE,
|
|
147
|
+
INVALID_YAML_VERSION,
|
|
148
|
+
UNFINISHED_YAML_VERSION,
|
|
149
|
+
UNEXPECTED_DIRECTIVE_PARAMETER,
|
|
150
|
+
UNEXPECTED_DOCUMENT_END_CONTENT,
|
|
151
|
+
INVALID_HEADER_INDENTATION,
|
|
152
|
+
INVALID_HEADER_CHOMPING,
|
|
153
|
+
MISSING_DOCUMENT_END,
|
|
154
|
+
MISSING_QUOTE_CLOSE,
|
|
155
|
+
INCOMPLETE_QUOTE_CLOSE,
|
|
156
|
+
MISSING_FLOW_SEQUENCE_CLOSE,
|
|
157
|
+
INCOMPLETE_FLOW_SEQUENCE_CLOSE,
|
|
158
|
+
MISSING_FLOW_MAPPING_CLOSE,
|
|
159
|
+
INCOMPLETE_FLOW_MAPPING_CLOSE,
|
|
160
|
+
MISSING_VALUE_INDICATOR,
|
|
161
|
+
INCOMPLETE_VALUE_INDICATOR,
|
|
162
|
+
MISSING_ANCHOR_NAME,
|
|
163
|
+
INCOMPLETE_ANCHOR_NAME,
|
|
164
|
+
MISSING_ALIAS_NAME,
|
|
165
|
+
INCOMPLETE_ALIAS_NAME,
|
|
166
|
+
MISSING_TAG_URI,
|
|
167
|
+
INCOMPLETE_TAG_URI,
|
|
168
|
+
MISSING_TAG_SUFFIX,
|
|
169
|
+
INCOMPLETE_TAG_SUFFIX,
|
|
170
|
+
MISSING_VERBATIM_TAG_CLOSE,
|
|
171
|
+
INCOMPLETE_VERBATIM_TAG_CLOSE,
|
|
172
|
+
MISSING_DIRECTIVE_NAME,
|
|
173
|
+
INCOMPLETE_DIRECTIVE_NAME,
|
|
174
|
+
MISSING_YAML_VERSION,
|
|
175
|
+
INCOMPLETE_YAML_VERSION,
|
|
176
|
+
MISSING_TAG_HANDLE,
|
|
177
|
+
INCOMPLETE_TAG_HANDLE,
|
|
178
|
+
MISSING_TAG_HANDLE_CLOSE,
|
|
179
|
+
INCOMPLETE_TAG_HANDLE_CLOSE,
|
|
180
|
+
MISSING_TAG_PREFIX,
|
|
181
|
+
INCOMPLETE_TAG_PREFIX,
|
|
182
|
+
MISSING_DOCUMENT_START,
|
|
183
|
+
INCOMPLETE_DOCUMENT_START,
|
|
184
|
+
ERROR_SENTINEL
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
enum Mode {
|
|
188
|
+
NORMAL,
|
|
189
|
+
PLAIN,
|
|
190
|
+
SINGLE,
|
|
191
|
+
DOUBLE,
|
|
192
|
+
COMMENT,
|
|
193
|
+
PREFIX,
|
|
194
|
+
COMPACT_PREFIX,
|
|
195
|
+
COMMENT_BEGIN,
|
|
196
|
+
BLOCK_HEADER,
|
|
197
|
+
BLOCK_HEADER_DONE,
|
|
198
|
+
BLOCK_DETECT,
|
|
199
|
+
BLOCK_BODY,
|
|
200
|
+
BLOCK_LINE,
|
|
201
|
+
BLOCK_LINE_DONE,
|
|
202
|
+
ANCHOR_BODY,
|
|
203
|
+
ALIAS_BODY,
|
|
204
|
+
HANDLE_SELECT,
|
|
205
|
+
HANDLE_BODY,
|
|
206
|
+
SUFFIX_BEGIN,
|
|
207
|
+
SUFFIX_BODY,
|
|
208
|
+
URI_BEGIN,
|
|
209
|
+
URI_BODY,
|
|
210
|
+
VERBATIM_CLOSE,
|
|
211
|
+
PREFIX_BODY,
|
|
212
|
+
DIRECTIVE_NAME_BODY,
|
|
213
|
+
DIRECTIVE_VERSION,
|
|
214
|
+
DIRECTIVE_HANDLE,
|
|
215
|
+
DIRECTIVE_PREFIX,
|
|
216
|
+
DIRECTIVE_PARAMETERS
|
|
217
|
+
};
|
|
218
|
+
enum HeaderFlag {
|
|
219
|
+
HEADER_INDENTATION = 1,
|
|
220
|
+
HEADER_CHOMPING = 2,
|
|
221
|
+
HEADER_SEPARATION = 4
|
|
222
|
+
};
|
|
223
|
+
enum PropertyFlag {
|
|
224
|
+
PROPERTY_ANCHOR = 1,
|
|
225
|
+
PROPERTY_TAG = 2,
|
|
226
|
+
PROPERTY_COLON_CONTENT = 4
|
|
227
|
+
};
|
|
228
|
+
enum HandleForm { PRIMARY_HANDLE = 1, SECONDARY_HANDLE, NAMED_HANDLE };
|
|
229
|
+
enum DirectiveKind { YAML_DIRECTIVE = 1, TAG_DIRECTIVE, RESERVED_DIRECTIVE };
|
|
230
|
+
/* Line starts that end the open constructs of a document. */
|
|
231
|
+
enum Boundary {
|
|
232
|
+
NO_BOUNDARY,
|
|
233
|
+
DOCUMENT_START_LINE,
|
|
234
|
+
DOCUMENT_END_LINE,
|
|
235
|
+
DIRECTIVE_LINE,
|
|
236
|
+
STREAM_BOM
|
|
237
|
+
};
|
|
238
|
+
#define SCANNER_FIELDS(F) \
|
|
239
|
+
F(int64_t, indent, 8, 1) \
|
|
240
|
+
F(uint32_t, flow, 4, 0) \
|
|
241
|
+
F(uint8_t, mode, 1, 0) \
|
|
242
|
+
F(bool, line, 1, 0) \
|
|
243
|
+
F(bool, document, 1, 0) \
|
|
244
|
+
F(uint32_t, column, 4, 0) \
|
|
245
|
+
F(bool, prefix, 1, 0) \
|
|
246
|
+
F(bool, first, 1, 0) \
|
|
247
|
+
F(bool, json, 1, 0) \
|
|
248
|
+
F(bool, continuation, 1, 0) \
|
|
249
|
+
F(bool, quote_line_empty, 1, 0) \
|
|
250
|
+
F(uint32_t, line_indent, 4, 0) \
|
|
251
|
+
F(bool, tab_invalid, 1, 0) \
|
|
252
|
+
F(bool, prefix_tab, 1, 0) \
|
|
253
|
+
F(bool, indent_checked, 1, 0) \
|
|
254
|
+
F(bool, line_prefixed, 1, 0) \
|
|
255
|
+
F(bool, scalar_indent, 1, 0) \
|
|
256
|
+
F(int32_t, line_head, 4, 0) \
|
|
257
|
+
F(bool, line_context, 1, 0) \
|
|
258
|
+
F(bool, layout_only, 1, 0) \
|
|
259
|
+
F(bool, line_mapping_key, 1, 0) \
|
|
260
|
+
F(bool, prefix_invalid, 1, 0) \
|
|
261
|
+
F(bool, separated, 1, 0) \
|
|
262
|
+
F(bool, key_done, 1, 0) \
|
|
263
|
+
F(int64_t, block_indent, 8, 1) \
|
|
264
|
+
F(uint8_t, header_flags, 1, 0) \
|
|
265
|
+
F(uint8_t, return_mode, 1, 0) \
|
|
266
|
+
F(bool, block_leading, 1, 0) \
|
|
267
|
+
F(bool, block_empty, 1, 0) \
|
|
268
|
+
F(bool, block_prefix, 1, 0) \
|
|
269
|
+
F(uint8_t, boundary, 1, 0) \
|
|
270
|
+
F(bool, boundary_checked, 1, 0) \
|
|
271
|
+
F(bool, document_started, 1, 0) \
|
|
272
|
+
F(bool, document_content, 1, 0) \
|
|
273
|
+
F(bool, after_document_end, 1, 0) \
|
|
274
|
+
F(bool, block_out, 1, 0) \
|
|
275
|
+
F(uint8_t, property_flags, 1, 0) \
|
|
276
|
+
F(uint8_t, handle_form, 1, 0) \
|
|
277
|
+
F(bool, properties_ready, 1, 0) \
|
|
278
|
+
F(bool, duplicate_pending, 1, 0) \
|
|
279
|
+
F(bool, property_separation_notified, 1, 0) \
|
|
280
|
+
F(uint8_t, directive_kind, 1, 0) \
|
|
281
|
+
F(bool, directive_handle, 1, 0) \
|
|
282
|
+
F(bool, value_separation, 1, 0) \
|
|
283
|
+
F(uint32_t, scalar_spaces, 4, 0) \
|
|
284
|
+
F(bool, scalar_tab, 1, 0) \
|
|
285
|
+
F(bool, explicit_document_required, 1, 0) \
|
|
286
|
+
F(uint8_t, block_kind, 1, 0)
|
|
287
|
+
|
|
288
|
+
#define FIELD_BYTES(type, name, width, bias) +width
|
|
289
|
+
enum {
|
|
290
|
+
IMPLICIT_KEY_LIMIT = 1024,
|
|
291
|
+
IMPLICIT_KEY_WORDS = IMPLICIT_KEY_LIMIT / 64 + 1,
|
|
292
|
+
SCANNER_STATE_BYTES = 0 SCANNER_FIELDS(FIELD_BYTES),
|
|
293
|
+
SCANNER_KEY_BYTES = IMPLICIT_KEY_LIMIT / 8 + 1
|
|
294
|
+
};
|
|
295
|
+
#undef FIELD_BYTES
|
|
296
|
+
|
|
297
|
+
#define DECLARE_FIELD(type, name, width, bias) type name;
|
|
298
|
+
typedef struct {
|
|
299
|
+
SCANNER_FIELDS(DECLARE_FIELD)
|
|
300
|
+
uint64_t implicit_keys[IMPLICIT_KEY_WORDS];
|
|
301
|
+
} Scanner;
|
|
302
|
+
#undef DECLARE_FIELD
|
|
303
|
+
|
|
304
|
+
typedef struct {
|
|
305
|
+
TSLexer lexer;
|
|
306
|
+
TSLexer *source;
|
|
307
|
+
uint32_t column, marked_column;
|
|
308
|
+
uint64_t characters;
|
|
309
|
+
uint64_t marked_characters;
|
|
310
|
+
bool broken, marked_broken;
|
|
311
|
+
bool separated, marked_separation;
|
|
312
|
+
} Cursor;
|
|
313
|
+
|
|
314
|
+
static bool blank(int32_t c) {
|
|
315
|
+
return c == ' ' || c == '\t';
|
|
316
|
+
}
|
|
317
|
+
static bool newline(int32_t c) {
|
|
318
|
+
return c == '\n' || c == '\r';
|
|
319
|
+
}
|
|
320
|
+
static bool space(int32_t c) {
|
|
321
|
+
return blank(c) || newline(c);
|
|
322
|
+
}
|
|
323
|
+
static bool flow_indicator(int32_t c) {
|
|
324
|
+
return c == ',' || c == '[' || c == ']' || c == '{' || c == '}';
|
|
325
|
+
}
|
|
326
|
+
static bool flow_entry_end(int32_t c) {
|
|
327
|
+
return c == ',' || c == ']' || c == '}';
|
|
328
|
+
}
|
|
329
|
+
static bool colon_boundary(TSLexer *l, bool flow) {
|
|
330
|
+
return l->eof(l) ||
|
|
331
|
+
space(l->lookahead) ||
|
|
332
|
+
(flow && flow_indicator(l->lookahead));
|
|
333
|
+
}
|
|
334
|
+
static bool invalid_encoding(int32_t c) {
|
|
335
|
+
return c < 0 || c > 0x10ffff || (c >= 0xd800 && c <= 0xdfff);
|
|
336
|
+
}
|
|
337
|
+
static bool invalid_quoted(int32_t c) {
|
|
338
|
+
return invalid_encoding(c) ||
|
|
339
|
+
(c < 0x20 && c != '\t' && c != '\n' && c != '\r');
|
|
340
|
+
}
|
|
341
|
+
static bool invalid_unquoted(int32_t c) {
|
|
342
|
+
return invalid_quoted(c) ||
|
|
343
|
+
(c >= 0x7f && c <= 0x9f && c != 0x85) ||
|
|
344
|
+
c ==
|
|
345
|
+
0xfeff ||
|
|
346
|
+
c ==
|
|
347
|
+
0xfffe ||
|
|
348
|
+
c == 0xffff;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static bool
|
|
352
|
+
block_value_follows(const Scanner *s, const TSLexer *l, const bool *valid) {
|
|
353
|
+
if (l->eof(l))
|
|
354
|
+
return false;
|
|
355
|
+
if (
|
|
356
|
+
valid[EXPLICIT_VALUE_START] &&
|
|
357
|
+
s->line &&
|
|
358
|
+
s->line_indent ==
|
|
359
|
+
s->indent &&
|
|
360
|
+
s->line_head == ':'
|
|
361
|
+
)
|
|
362
|
+
return true;
|
|
363
|
+
return (valid[VALUE_START] || valid[SEQUENCE_VALUE_START]) &&
|
|
364
|
+
(!s->line ||
|
|
365
|
+
s->line_indent >
|
|
366
|
+
s->indent ||
|
|
367
|
+
(valid[VALUE_START] &&
|
|
368
|
+
s->line_indent ==
|
|
369
|
+
s->indent &&
|
|
370
|
+
s->line_head == '-'));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
static bool property_line_follows(const Scanner *s) {
|
|
374
|
+
return s->flow ||
|
|
375
|
+
!s->line ||
|
|
376
|
+
s->line_indent >
|
|
377
|
+
s->indent ||
|
|
378
|
+
(s->block_out && s->line_indent == s->indent && s->line_head == '-');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static void cursor_advance(TSLexer *lexer, bool skip) {
|
|
382
|
+
Cursor *cursor = (Cursor *)lexer;
|
|
383
|
+
cursor->characters++;
|
|
384
|
+
cursor->separated = space(lexer->lookahead);
|
|
385
|
+
cursor->broken |= newline(lexer->lookahead);
|
|
386
|
+
cursor->column = newline(lexer->lookahead) ? 0 : cursor->column + 1;
|
|
387
|
+
cursor->source->advance(cursor->source, skip);
|
|
388
|
+
lexer->lookahead = cursor->source->lookahead;
|
|
389
|
+
}
|
|
390
|
+
static void cursor_mark(TSLexer *lexer) {
|
|
391
|
+
Cursor *cursor = (Cursor *)lexer;
|
|
392
|
+
cursor->marked_column = cursor->column;
|
|
393
|
+
cursor->marked_characters = cursor->characters;
|
|
394
|
+
cursor->marked_broken = cursor->broken;
|
|
395
|
+
cursor->marked_separation = cursor->separated;
|
|
396
|
+
cursor->source->mark_end(cursor->source);
|
|
397
|
+
}
|
|
398
|
+
static uint32_t cursor_column(TSLexer *lexer) {
|
|
399
|
+
return ((Cursor *)lexer)->column;
|
|
400
|
+
}
|
|
401
|
+
static bool cursor_eof(const TSLexer *lexer) {
|
|
402
|
+
const Cursor *cursor = (const Cursor *)lexer;
|
|
403
|
+
return cursor->source->eof(cursor->source);
|
|
404
|
+
}
|
|
405
|
+
static uint64_t cursor_characters(const TSLexer *lexer) {
|
|
406
|
+
return ((const Cursor *)lexer)->characters;
|
|
407
|
+
}
|
|
408
|
+
static bool cursor_broken(const TSLexer *lexer) {
|
|
409
|
+
return ((const Cursor *)lexer)->broken;
|
|
410
|
+
}
|
|
411
|
+
static void cursor_start_line(TSLexer *lexer) {
|
|
412
|
+
((Cursor *)lexer)->column = 0;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
static bool emit(TSLexer *l, const bool *valid, enum Token token) {
|
|
416
|
+
if (!valid[token])
|
|
417
|
+
return false;
|
|
418
|
+
l->result_symbol = token;
|
|
419
|
+
return true;
|
|
420
|
+
}
|
|
421
|
+
static void step(TSLexer *l) {
|
|
422
|
+
l->advance(l, false);
|
|
423
|
+
}
|
|
424
|
+
static bool finish(TSLexer *l, const bool *valid, enum Token token) {
|
|
425
|
+
l->mark_end(l);
|
|
426
|
+
return emit(l, valid, token);
|
|
427
|
+
}
|
|
428
|
+
static uint32_t count_spaces(TSLexer *l) {
|
|
429
|
+
uint32_t spaces = 0;
|
|
430
|
+
while (l->lookahead == ' ') {
|
|
431
|
+
step(l);
|
|
432
|
+
spaces++;
|
|
433
|
+
}
|
|
434
|
+
return spaces;
|
|
435
|
+
}
|
|
436
|
+
static void skip_blanks(TSLexer *l) {
|
|
437
|
+
while (blank(l->lookahead))
|
|
438
|
+
step(l);
|
|
439
|
+
}
|
|
440
|
+
static bool take(TSLexer *l, const bool *valid, enum Token token) {
|
|
441
|
+
if (!valid[token])
|
|
442
|
+
return false;
|
|
443
|
+
step(l);
|
|
444
|
+
return finish(l, valid, token);
|
|
445
|
+
}
|
|
446
|
+
static bool emit_missing(
|
|
447
|
+
TSLexer *l,
|
|
448
|
+
const bool *valid,
|
|
449
|
+
enum Token missing,
|
|
450
|
+
enum Token incomplete
|
|
451
|
+
) {
|
|
452
|
+
return emit(l, valid, l->eof(l) ? incomplete : missing);
|
|
453
|
+
}
|
|
454
|
+
static bool scan_separation(TSLexer *l, const bool *valid) {
|
|
455
|
+
step(l);
|
|
456
|
+
skip_blanks(l);
|
|
457
|
+
return finish(l, valid, SEPARATION);
|
|
458
|
+
}
|
|
459
|
+
static bool
|
|
460
|
+
close_flow(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
|
|
461
|
+
bool closed = token == FLOW_SEQUENCE_CLOSE || token == FLOW_MAPPING_CLOSE
|
|
462
|
+
? take(l, valid, token)
|
|
463
|
+
: emit(l, valid, token);
|
|
464
|
+
if (closed) {
|
|
465
|
+
s->flow--;
|
|
466
|
+
s->json = true;
|
|
467
|
+
/* A mismatched closer ends the collection mid-line without consuming
|
|
468
|
+
* source, so the rest of the line is content rather than layout. */
|
|
469
|
+
s->line = false;
|
|
470
|
+
}
|
|
471
|
+
return closed;
|
|
472
|
+
}
|
|
473
|
+
static bool emit_closing(
|
|
474
|
+
Scanner *s,
|
|
475
|
+
TSLexer *l,
|
|
476
|
+
const bool *valid,
|
|
477
|
+
const enum Token *closings,
|
|
478
|
+
size_t count
|
|
479
|
+
) {
|
|
480
|
+
for (size_t i = 0; i < count; i++) {
|
|
481
|
+
enum Token token = closings[i];
|
|
482
|
+
if (!valid[token])
|
|
483
|
+
continue;
|
|
484
|
+
switch (token) {
|
|
485
|
+
case MISSING_FLOW_SEQUENCE_CLOSE:
|
|
486
|
+
case MISSING_FLOW_MAPPING_CLOSE:
|
|
487
|
+
case INCOMPLETE_FLOW_SEQUENCE_CLOSE:
|
|
488
|
+
case INCOMPLETE_FLOW_MAPPING_CLOSE:
|
|
489
|
+
return close_flow(s, l, valid, token);
|
|
490
|
+
case DEDENT:
|
|
491
|
+
case OUTDENT:
|
|
492
|
+
s->indent--;
|
|
493
|
+
break;
|
|
494
|
+
case RESTORE_INDENT:
|
|
495
|
+
case INDENT:
|
|
496
|
+
s->indent++;
|
|
497
|
+
break;
|
|
498
|
+
default:
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
return emit(l, valid, token);
|
|
502
|
+
}
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
static bool start_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
506
|
+
if (!valid[PLAIN_START])
|
|
507
|
+
return false;
|
|
508
|
+
s->mode = PLAIN;
|
|
509
|
+
s->first = true;
|
|
510
|
+
s->json = false;
|
|
511
|
+
return emit(l, valid, PLAIN_START);
|
|
512
|
+
}
|
|
513
|
+
static bool scan_invalid_character(TSLexer *l, const bool *valid) {
|
|
514
|
+
if (l->eof(l) || !invalid_unquoted(l->lookahead))
|
|
515
|
+
return false;
|
|
516
|
+
return take(
|
|
517
|
+
l,
|
|
518
|
+
valid,
|
|
519
|
+
invalid_encoding(l->lookahead) ? INVALID_ENCODING : INVALID_CHARACTER
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
static bool scan_line_text(TSLexer *l, const bool *valid, enum Token token) {
|
|
524
|
+
if (scan_invalid_character(l, valid))
|
|
525
|
+
return true;
|
|
526
|
+
do {
|
|
527
|
+
step(l);
|
|
528
|
+
} while (
|
|
529
|
+
!l->eof(l) && !newline(l->lookahead) && !invalid_unquoted(l->lookahead)
|
|
530
|
+
);
|
|
531
|
+
return finish(l, valid, token);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
static enum Boundary document_marker(TSLexer *l) {
|
|
535
|
+
if (l->get_column(l) != 0 || (l->lookahead != '-' && l->lookahead != '.'))
|
|
536
|
+
return NO_BOUNDARY;
|
|
537
|
+
int32_t marker = l->lookahead;
|
|
538
|
+
for (unsigned i = 0; i < 3; i++) {
|
|
539
|
+
if (l->lookahead != marker)
|
|
540
|
+
return NO_BOUNDARY;
|
|
541
|
+
step(l);
|
|
542
|
+
}
|
|
543
|
+
if (!space(l->lookahead) && !l->eof(l))
|
|
544
|
+
return NO_BOUNDARY;
|
|
545
|
+
return marker == '-' ? DOCUMENT_START_LINE : DOCUMENT_END_LINE;
|
|
546
|
+
}
|
|
547
|
+
/* Outside flow collections and scalars, a directive indicator or a BOM at
|
|
548
|
+
* the start of a line also ends the open constructs of the document. */
|
|
549
|
+
static enum Boundary line_boundary(const Scanner *s, TSLexer *l) {
|
|
550
|
+
if (l->lookahead == '-' || l->lookahead == '.')
|
|
551
|
+
return document_marker(l);
|
|
552
|
+
if (s->flow || (s->mode != NORMAL && s->mode != BLOCK_BODY))
|
|
553
|
+
return NO_BOUNDARY;
|
|
554
|
+
if (l->lookahead == '%')
|
|
555
|
+
return s->mode == NORMAL ? DIRECTIVE_LINE : NO_BOUNDARY;
|
|
556
|
+
return l->lookahead == 0xfeff ? STREAM_BOM : NO_BOUNDARY;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
static enum Token node_start(int32_t c) {
|
|
560
|
+
switch (c) {
|
|
561
|
+
case '[':
|
|
562
|
+
return FLOW_SEQUENCE_START;
|
|
563
|
+
case '{':
|
|
564
|
+
return FLOW_MAPPING_START;
|
|
565
|
+
case '\'':
|
|
566
|
+
return SINGLE_START;
|
|
567
|
+
case '"':
|
|
568
|
+
return DOUBLE_START;
|
|
569
|
+
case '&':
|
|
570
|
+
case '!':
|
|
571
|
+
return PROPERTIES_START;
|
|
572
|
+
case '*':
|
|
573
|
+
return ALIAS_START;
|
|
574
|
+
default:
|
|
575
|
+
return PLAIN_START;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
static bool name_boundary(TSLexer *l) {
|
|
579
|
+
return l->eof(l) || space(l->lookahead) || flow_indicator(l->lookahead);
|
|
580
|
+
}
|
|
581
|
+
static bool block_collection(enum Token kind) {
|
|
582
|
+
return kind == MAPPING_START || kind == SEQUENCE_START;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/* Only starts within the same line's last 1024 characters can remain valid. */
|
|
586
|
+
static void advance_keys(Scanner *s, uint64_t characters, bool broken) {
|
|
587
|
+
if (broken || characters > IMPLICIT_KEY_LIMIT) {
|
|
588
|
+
memset(s->implicit_keys, 0, sizeof(s->implicit_keys));
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
unsigned words = (unsigned)(characters / 64);
|
|
592
|
+
unsigned bits = (unsigned)(characters % 64);
|
|
593
|
+
for (unsigned i = IMPLICIT_KEY_WORDS; i-- > 0;) {
|
|
594
|
+
uint64_t value = i >= words ? s->implicit_keys[i - words] << bits : 0;
|
|
595
|
+
if (bits && i > words)
|
|
596
|
+
value |= s->implicit_keys[i - words - 1] >> (64 - bits);
|
|
597
|
+
s->implicit_keys[i] = value;
|
|
598
|
+
}
|
|
599
|
+
s->implicit_keys[IMPLICIT_KEY_WORDS - 1] &= 1;
|
|
600
|
+
}
|
|
601
|
+
static unsigned end_key(Scanner *s) {
|
|
602
|
+
for (unsigned i = 0; i < IMPLICIT_KEY_WORDS; i++) {
|
|
603
|
+
uint64_t word = s->implicit_keys[i];
|
|
604
|
+
if (word) {
|
|
605
|
+
s->implicit_keys[i] &= word - 1;
|
|
606
|
+
unsigned age = i * 64;
|
|
607
|
+
while (!(word & 1)) {
|
|
608
|
+
word >>= 1;
|
|
609
|
+
age++;
|
|
610
|
+
}
|
|
611
|
+
return age;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return IMPLICIT_KEY_LIMIT + 1;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/* Flow entries and values are optional, so the parser reduces a flow node only
|
|
618
|
+
* at the token that follows the layout after it. Reading that layout keeps an
|
|
619
|
+
* edit inside it from leaving a reused node's reduction unrevised. The key
|
|
620
|
+
* lookahead reads the same layout because the colon may follow comment lines.
|
|
621
|
+
*/
|
|
622
|
+
static void skip_layout(TSLexer *l) {
|
|
623
|
+
for (;;) {
|
|
624
|
+
while (space(l->lookahead))
|
|
625
|
+
step(l);
|
|
626
|
+
if (l->lookahead != '#')
|
|
627
|
+
return;
|
|
628
|
+
while (!l->eof(l) && !newline(l->lookahead))
|
|
629
|
+
step(l);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
static bool scan_key_end(Scanner *s, TSLexer *l, const bool *valid) {
|
|
633
|
+
if (!s->line && blank(l->lookahead))
|
|
634
|
+
return scan_separation(l, valid);
|
|
635
|
+
unsigned age = end_key(s);
|
|
636
|
+
if (s->flow)
|
|
637
|
+
skip_layout(l);
|
|
638
|
+
bool key_invalid =
|
|
639
|
+
cursor_broken(l) || age + cursor_characters(l) > IMPLICIT_KEY_LIMIT;
|
|
640
|
+
if (valid[FLOW_NODE_END]) {
|
|
641
|
+
bool colon = l->lookahead == ':';
|
|
642
|
+
if (colon) {
|
|
643
|
+
step(l);
|
|
644
|
+
colon = s->json || colon_boundary(l, true);
|
|
645
|
+
}
|
|
646
|
+
if (!colon)
|
|
647
|
+
return emit(l, valid, FLOW_NODE_END);
|
|
648
|
+
}
|
|
649
|
+
s->key_done = true;
|
|
650
|
+
return emit(l, valid, key_invalid ? INVALID_KEY_END : KEY_END);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
static void skip_property_or_alias(TSLexer *l) {
|
|
654
|
+
bool tag = l->lookahead == '!';
|
|
655
|
+
step(l);
|
|
656
|
+
if (tag && l->lookahead == '<') {
|
|
657
|
+
step(l);
|
|
658
|
+
while (!l->eof(l) && !space(l->lookahead) && l->lookahead != '>')
|
|
659
|
+
step(l);
|
|
660
|
+
if (l->lookahead == '>')
|
|
661
|
+
step(l);
|
|
662
|
+
} else {
|
|
663
|
+
while (!name_boundary(l))
|
|
664
|
+
step(l);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
static enum Token classify_block_node(TSLexer *l) {
|
|
669
|
+
bool properties = l->lookahead == '&' || l->lookahead == '!';
|
|
670
|
+
while (l->lookahead == '&' || l->lookahead == '!') {
|
|
671
|
+
skip_property_or_alias(l);
|
|
672
|
+
skip_blanks(l);
|
|
673
|
+
if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
|
|
674
|
+
return PROPERTIES_START;
|
|
675
|
+
}
|
|
676
|
+
int32_t first = l->lookahead;
|
|
677
|
+
if (first == '|' || first == '>')
|
|
678
|
+
return properties ? PROPERTIES_START
|
|
679
|
+
: first == '|' ? LITERAL_START
|
|
680
|
+
: FOLDED_START;
|
|
681
|
+
enum Token content = node_start(first);
|
|
682
|
+
enum Token fallback = properties ? PROPERTIES_START : content;
|
|
683
|
+
bool structured = content ==
|
|
684
|
+
SINGLE_START ||
|
|
685
|
+
content ==
|
|
686
|
+
DOUBLE_START ||
|
|
687
|
+
content ==
|
|
688
|
+
FLOW_SEQUENCE_START ||
|
|
689
|
+
content == FLOW_MAPPING_START;
|
|
690
|
+
if (first == '*') {
|
|
691
|
+
skip_property_or_alias(l);
|
|
692
|
+
}
|
|
693
|
+
if (first == '-' || first == '?') {
|
|
694
|
+
step(l);
|
|
695
|
+
if (space(l->lookahead) || l->eof(l))
|
|
696
|
+
return properties ? PROPERTIES_START
|
|
697
|
+
: first == '-' ? SEQUENCE_START
|
|
698
|
+
: MAPPING_START;
|
|
699
|
+
}
|
|
700
|
+
int32_t quote = 0;
|
|
701
|
+
char initial_closings[32];
|
|
702
|
+
char *closings = initial_closings;
|
|
703
|
+
size_t flow = 0, capacity = sizeof(initial_closings);
|
|
704
|
+
bool separated = false;
|
|
705
|
+
bool complete = content == ALIAS_START;
|
|
706
|
+
bool plain = content == PLAIN_START;
|
|
707
|
+
bool adjacent = false;
|
|
708
|
+
while (!l->eof(l)) {
|
|
709
|
+
if (
|
|
710
|
+
l->get_column(l) ==
|
|
711
|
+
0 &&
|
|
712
|
+
cursor_characters(l) &&
|
|
713
|
+
(l->lookahead == '-' || l->lookahead == '.')
|
|
714
|
+
) {
|
|
715
|
+
if (document_marker(l) || l->eof(l))
|
|
716
|
+
break;
|
|
717
|
+
if (!quote)
|
|
718
|
+
plain = true;
|
|
719
|
+
}
|
|
720
|
+
int32_t c = l->lookahead;
|
|
721
|
+
if (!quote && !flow) {
|
|
722
|
+
if (complete && !space(c) && c != ':')
|
|
723
|
+
break;
|
|
724
|
+
if (newline(c) || (c == '#' && separated))
|
|
725
|
+
break;
|
|
726
|
+
}
|
|
727
|
+
if (quote) {
|
|
728
|
+
if (c == '\\' && quote == '"') {
|
|
729
|
+
step(l);
|
|
730
|
+
if (l->eof(l))
|
|
731
|
+
break;
|
|
732
|
+
} else if (c == quote) {
|
|
733
|
+
if (quote == '\'') {
|
|
734
|
+
step(l);
|
|
735
|
+
if (l->lookahead == '\'') {
|
|
736
|
+
step(l);
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
quote = 0;
|
|
741
|
+
adjacent = true;
|
|
742
|
+
if (!flow)
|
|
743
|
+
complete = true;
|
|
744
|
+
separated = false;
|
|
745
|
+
if (c == '\'')
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
} else if (structured && !plain && (c == '\'' || c == '"'))
|
|
749
|
+
quote = c;
|
|
750
|
+
else if (flow && !plain && (c == '&' || c == '*' || c == '!')) {
|
|
751
|
+
skip_property_or_alias(l);
|
|
752
|
+
adjacent = false;
|
|
753
|
+
separated = false;
|
|
754
|
+
continue;
|
|
755
|
+
} else if (flow && c == '#' && (separated || !plain)) {
|
|
756
|
+
while (!l->eof(l) && !newline(l->lookahead))
|
|
757
|
+
step(l);
|
|
758
|
+
plain = false;
|
|
759
|
+
separated = true;
|
|
760
|
+
continue;
|
|
761
|
+
} else if (structured && (c == '[' || c == '{')) {
|
|
762
|
+
if (flow == capacity) {
|
|
763
|
+
capacity *= 2;
|
|
764
|
+
char *expanded = ts_calloc(capacity, sizeof(*expanded));
|
|
765
|
+
memcpy(expanded, closings, flow);
|
|
766
|
+
if (closings != initial_closings)
|
|
767
|
+
ts_free(closings);
|
|
768
|
+
closings = expanded;
|
|
769
|
+
}
|
|
770
|
+
closings[flow++] = c == '[' ? ']' : '}';
|
|
771
|
+
plain = false;
|
|
772
|
+
adjacent = false;
|
|
773
|
+
} else if ((c == ']' || c == '}') && flow) {
|
|
774
|
+
while (flow && closings[flow - 1] != c)
|
|
775
|
+
flow--;
|
|
776
|
+
if (!flow)
|
|
777
|
+
break;
|
|
778
|
+
flow--;
|
|
779
|
+
plain = false;
|
|
780
|
+
adjacent = true;
|
|
781
|
+
if (!flow)
|
|
782
|
+
complete = true;
|
|
783
|
+
} else if (flow && c == ',') {
|
|
784
|
+
plain = false;
|
|
785
|
+
adjacent = false;
|
|
786
|
+
} else if (c == ':') {
|
|
787
|
+
step(l);
|
|
788
|
+
bool indicator = colon_boundary(l, flow);
|
|
789
|
+
if (!flow && indicator) {
|
|
790
|
+
fallback = MAPPING_START;
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
if (!flow && complete)
|
|
794
|
+
break;
|
|
795
|
+
plain = !indicator && !adjacent;
|
|
796
|
+
adjacent = false;
|
|
797
|
+
separated = false;
|
|
798
|
+
continue;
|
|
799
|
+
} else if (flow && !plain && c == '?') {
|
|
800
|
+
step(l);
|
|
801
|
+
plain = !space(l->lookahead) && !l->eof(l);
|
|
802
|
+
adjacent = false;
|
|
803
|
+
separated = false;
|
|
804
|
+
continue;
|
|
805
|
+
} else if (!space(c)) {
|
|
806
|
+
plain = true;
|
|
807
|
+
adjacent = false;
|
|
808
|
+
}
|
|
809
|
+
separated = space(c);
|
|
810
|
+
step(l);
|
|
811
|
+
}
|
|
812
|
+
if (closings != initial_closings)
|
|
813
|
+
ts_free(closings);
|
|
814
|
+
return fallback;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
static enum Token classify_block_start(Scanner *s, TSLexer *l) {
|
|
818
|
+
if (!s->block_kind)
|
|
819
|
+
s->block_kind = (uint8_t)(classify_block_node(l) + 1);
|
|
820
|
+
return (enum Token)(s->block_kind - 1);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static enum Token
|
|
824
|
+
property_content_start(Scanner *s, TSLexer *l, const bool *valid) {
|
|
825
|
+
if (l->lookahead == '*' && !(s->line && s->line_mapping_key))
|
|
826
|
+
return PROPERTY_ALIAS_START;
|
|
827
|
+
if (!s->flow) {
|
|
828
|
+
enum Token kind = classify_block_start(s, l);
|
|
829
|
+
if (
|
|
830
|
+
s->line &&
|
|
831
|
+
valid[BLOCK_KEY_CONTENT_START] &&
|
|
832
|
+
(block_collection(kind) || kind == LITERAL_START || kind == FOLDED_START)
|
|
833
|
+
)
|
|
834
|
+
return BLOCK_KEY_CONTENT_START;
|
|
835
|
+
if (
|
|
836
|
+
!s->line &&
|
|
837
|
+
valid[PROPERTY_COMPACT_START] &&
|
|
838
|
+
(kind ==
|
|
839
|
+
SEQUENCE_START ||
|
|
840
|
+
(kind == MAPPING_START && valid[BLOCK_PROPERTY_CONTENT_START]))
|
|
841
|
+
)
|
|
842
|
+
return PROPERTY_COMPACT_START;
|
|
843
|
+
}
|
|
844
|
+
return valid[BLOCK_PROPERTY_CONTENT_START] ? BLOCK_PROPERTY_CONTENT_START
|
|
845
|
+
: PROPERTY_CONTENT_START;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
static bool
|
|
849
|
+
emit_indicator(Scanner *s, TSLexer *l, const bool *valid, enum Token token) {
|
|
850
|
+
l->mark_end(l);
|
|
851
|
+
if (!s->flow && blank(l->lookahead)) {
|
|
852
|
+
skip_blanks(l);
|
|
853
|
+
if (!l->eof(l) && !newline(l->lookahead) && l->lookahead != '#') {
|
|
854
|
+
enum Token kind = classify_block_node(l);
|
|
855
|
+
if (block_collection(kind))
|
|
856
|
+
s->mode = COMPACT_PREFIX;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return emit(l, valid, token);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
static void skip_line_break(TSLexer *l) {
|
|
863
|
+
int32_t first = l->lookahead;
|
|
864
|
+
step(l);
|
|
865
|
+
if (first == '\r' && l->lookahead == '\n')
|
|
866
|
+
step(l);
|
|
867
|
+
}
|
|
868
|
+
static bool line_break(TSLexer *l, const bool *valid, enum Token token) {
|
|
869
|
+
skip_line_break(l);
|
|
870
|
+
return finish(l, valid, token);
|
|
871
|
+
}
|
|
872
|
+
static unsigned hex_value(int32_t c) {
|
|
873
|
+
if (c >= '0' && c <= '9')
|
|
874
|
+
return (unsigned)(c - '0');
|
|
875
|
+
if (c >= 'a' && c <= 'f')
|
|
876
|
+
return (unsigned)(c - 'a' + 10);
|
|
877
|
+
if (c >= 'A' && c <= 'F')
|
|
878
|
+
return (unsigned)(c - 'A' + 10);
|
|
879
|
+
return 16;
|
|
880
|
+
}
|
|
881
|
+
static unsigned hex_digits(TSLexer *l, unsigned remaining, uint32_t *value) {
|
|
882
|
+
*value = 0;
|
|
883
|
+
while (remaining && !l->eof(l)) {
|
|
884
|
+
unsigned digit = hex_value(l->lookahead);
|
|
885
|
+
if (digit == 16)
|
|
886
|
+
break;
|
|
887
|
+
*value = (*value << 4) | digit;
|
|
888
|
+
step(l);
|
|
889
|
+
l->mark_end(l);
|
|
890
|
+
remaining--;
|
|
891
|
+
}
|
|
892
|
+
return remaining;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
static bool word_char(int32_t c) {
|
|
896
|
+
return (c >= 'a' && c <= 'z') ||
|
|
897
|
+
(c >= 'A' && c <= 'Z') ||
|
|
898
|
+
(c >= '0' && c <= '9') ||
|
|
899
|
+
c == '-';
|
|
900
|
+
}
|
|
901
|
+
static bool uri_char(int32_t c, bool suffix) {
|
|
902
|
+
return word_char(c) ||
|
|
903
|
+
(c >
|
|
904
|
+
0 &&
|
|
905
|
+
c <
|
|
906
|
+
128 &&
|
|
907
|
+
strchr("#;/?:@&=+$,_.!~*'()[]", (int)c) &&
|
|
908
|
+
(!suffix || (c != '!' && !flow_indicator(c))));
|
|
909
|
+
}
|
|
910
|
+
static void finish_tag(Scanner *s) {
|
|
911
|
+
s->mode = NORMAL;
|
|
912
|
+
s->property_flags |= PROPERTY_TAG;
|
|
913
|
+
}
|
|
914
|
+
static bool scan_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
915
|
+
bool anchor = s->mode == ANCHOR_BODY;
|
|
916
|
+
if (name_boundary(l)) {
|
|
917
|
+
if (s->first) {
|
|
918
|
+
s->first = false;
|
|
919
|
+
return anchor
|
|
920
|
+
? emit_missing(l, valid, MISSING_ANCHOR_NAME, INCOMPLETE_ANCHOR_NAME)
|
|
921
|
+
: emit_missing(l, valid, MISSING_ALIAS_NAME, INCOMPLETE_ALIAS_NAME);
|
|
922
|
+
}
|
|
923
|
+
s->mode = NORMAL;
|
|
924
|
+
if (anchor)
|
|
925
|
+
s->property_flags |= PROPERTY_ANCHOR;
|
|
926
|
+
return emit(l, valid, NAME_END);
|
|
927
|
+
}
|
|
928
|
+
s->first = false;
|
|
929
|
+
if (scan_invalid_character(l, valid))
|
|
930
|
+
return true;
|
|
931
|
+
do {
|
|
932
|
+
step(l);
|
|
933
|
+
} while (!name_boundary(l) && !invalid_unquoted(l->lookahead));
|
|
934
|
+
return finish(l, valid, anchor ? ANCHOR_NAME : ALIAS_NAME);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* The starting lookahead has already selected the tag handle form. */
|
|
938
|
+
static bool scan_handle(Scanner *s, TSLexer *l, const bool *valid) {
|
|
939
|
+
if (s->mode == HANDLE_SELECT) {
|
|
940
|
+
step(l);
|
|
941
|
+
enum Token token = s->handle_form == PRIMARY_HANDLE ? PRIMARY_TAG_HANDLE
|
|
942
|
+
: s->handle_form == SECONDARY_HANDLE ? SECONDARY_TAG_HANDLE
|
|
943
|
+
: TAG_HANDLE_OPEN;
|
|
944
|
+
if (s->handle_form == SECONDARY_HANDLE)
|
|
945
|
+
step(l);
|
|
946
|
+
l->mark_end(l);
|
|
947
|
+
s->mode = s->handle_form == NAMED_HANDLE ? HANDLE_BODY
|
|
948
|
+
: s->directive_handle ? DIRECTIVE_PREFIX
|
|
949
|
+
: SUFFIX_BEGIN;
|
|
950
|
+
return emit(l, valid, token);
|
|
951
|
+
}
|
|
952
|
+
if (s->directive_handle && (l->eof(l) || space(l->lookahead))) {
|
|
953
|
+
s->mode = DIRECTIVE_PREFIX;
|
|
954
|
+
return emit_missing(
|
|
955
|
+
l,
|
|
956
|
+
valid,
|
|
957
|
+
MISSING_TAG_HANDLE_CLOSE,
|
|
958
|
+
INCOMPLETE_TAG_HANDLE_CLOSE
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
if (l->lookahead == '!') {
|
|
962
|
+
s->mode = s->directive_handle ? DIRECTIVE_PREFIX : SUFFIX_BEGIN;
|
|
963
|
+
return take(l, valid, TAG_HANDLE_CLOSE);
|
|
964
|
+
}
|
|
965
|
+
if (scan_invalid_character(l, valid))
|
|
966
|
+
return true;
|
|
967
|
+
if (!word_char(l->lookahead))
|
|
968
|
+
return take(l, valid, INVALID_TAG_HANDLE);
|
|
969
|
+
do {
|
|
970
|
+
step(l);
|
|
971
|
+
} while (word_char(l->lookahead));
|
|
972
|
+
return finish(l, valid, TAG_HANDLE_NAME);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
/* The zero-width boundaries around a verbatim URI or a tag suffix. */
|
|
976
|
+
static bool scan_tag_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
977
|
+
if (s->mode == URI_BEGIN) {
|
|
978
|
+
s->mode = URI_BODY;
|
|
979
|
+
if (l->eof(l) || space(l->lookahead) || l->lookahead == '>') {
|
|
980
|
+
s->mode = VERBATIM_CLOSE;
|
|
981
|
+
return emit_missing(l, valid, MISSING_TAG_URI, INCOMPLETE_TAG_URI);
|
|
982
|
+
}
|
|
983
|
+
return emit(l, valid, TAG_URI_START);
|
|
984
|
+
}
|
|
985
|
+
if (s->mode == VERBATIM_CLOSE) {
|
|
986
|
+
finish_tag(s);
|
|
987
|
+
if (l->lookahead == '>')
|
|
988
|
+
return take(l, valid, VERBATIM_TAG_CLOSE);
|
|
989
|
+
return emit_missing(
|
|
990
|
+
l,
|
|
991
|
+
valid,
|
|
992
|
+
MISSING_VERBATIM_TAG_CLOSE,
|
|
993
|
+
INCOMPLETE_VERBATIM_TAG_CLOSE
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
s->mode = SUFFIX_BODY;
|
|
997
|
+
if (name_boundary(l))
|
|
998
|
+
return emit_missing(l, valid, MISSING_TAG_SUFFIX, INCOMPLETE_TAG_SUFFIX);
|
|
999
|
+
return emit(l, valid, TAG_SUFFIX_START);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
static bool scan_uri(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1003
|
+
bool prefix = s->mode == PREFIX_BODY;
|
|
1004
|
+
bool suffix = s->mode == SUFFIX_BODY;
|
|
1005
|
+
if (
|
|
1006
|
+
l->eof(l) ||
|
|
1007
|
+
space(l->lookahead) ||
|
|
1008
|
+
(suffix ? flow_indicator(l->lookahead) : !prefix && l->lookahead == '>')
|
|
1009
|
+
) {
|
|
1010
|
+
if (prefix) {
|
|
1011
|
+
s->mode = DIRECTIVE_PARAMETERS;
|
|
1012
|
+
return emit(l, valid, TAG_PREFIX_END);
|
|
1013
|
+
}
|
|
1014
|
+
if (suffix) {
|
|
1015
|
+
finish_tag(s);
|
|
1016
|
+
return emit(l, valid, TAG_END);
|
|
1017
|
+
}
|
|
1018
|
+
s->mode = VERBATIM_CLOSE;
|
|
1019
|
+
return emit(l, valid, TAG_URI_END);
|
|
1020
|
+
}
|
|
1021
|
+
if (scan_invalid_character(l, valid))
|
|
1022
|
+
return true;
|
|
1023
|
+
if (prefix && s->first) {
|
|
1024
|
+
s->first = false;
|
|
1025
|
+
if (flow_indicator(l->lookahead))
|
|
1026
|
+
return take(l, valid, INVALID_TAG_CHARACTER);
|
|
1027
|
+
}
|
|
1028
|
+
if (l->lookahead == '%') {
|
|
1029
|
+
step(l);
|
|
1030
|
+
l->mark_end(l);
|
|
1031
|
+
uint32_t value;
|
|
1032
|
+
unsigned remaining = hex_digits(l, 2, &value);
|
|
1033
|
+
return emit(
|
|
1034
|
+
l,
|
|
1035
|
+
valid,
|
|
1036
|
+
!remaining ? URI_ESCAPE
|
|
1037
|
+
: l->eof(l) ? INCOMPLETE_URI_ESCAPE
|
|
1038
|
+
: INVALID_URI_ESCAPE
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
if (!uri_char(l->lookahead, suffix))
|
|
1042
|
+
return take(l, valid, INVALID_TAG_CHARACTER);
|
|
1043
|
+
do {
|
|
1044
|
+
step(l);
|
|
1045
|
+
} while (uri_char(l->lookahead, suffix));
|
|
1046
|
+
return finish(l, valid, suffix ? TAG_SUFFIX_TEXT : URI_TEXT);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
static bool directive_boundary(TSLexer *l) {
|
|
1050
|
+
return l->eof(l) || space(l->lookahead) || invalid_unquoted(l->lookahead);
|
|
1051
|
+
}
|
|
1052
|
+
static bool
|
|
1053
|
+
scan_directive_word(TSLexer *l, const bool *valid, enum Token token) {
|
|
1054
|
+
do {
|
|
1055
|
+
step(l);
|
|
1056
|
+
} while (!directive_boundary(l));
|
|
1057
|
+
return finish(l, valid, token);
|
|
1058
|
+
}
|
|
1059
|
+
/* The zero-width start token reads to the end of the line so that any edit
|
|
1060
|
+
* inside the comment invalidates the comment's first leaf. Tree-sitter then
|
|
1061
|
+
* breaks down the reused node before it, whose reduction may have depended on
|
|
1062
|
+
* the content that follows the comment. */
|
|
1063
|
+
static bool start_comment(
|
|
1064
|
+
Scanner *s,
|
|
1065
|
+
TSLexer *l,
|
|
1066
|
+
const bool *valid,
|
|
1067
|
+
enum Mode return_mode,
|
|
1068
|
+
bool missing_separation
|
|
1069
|
+
) {
|
|
1070
|
+
if (!valid[COMMENT_START])
|
|
1071
|
+
return false;
|
|
1072
|
+
while (!l->eof(l) && !newline(l->lookahead))
|
|
1073
|
+
step(l);
|
|
1074
|
+
s->mode = COMMENT_BEGIN;
|
|
1075
|
+
s->return_mode = (uint8_t)return_mode;
|
|
1076
|
+
s->first = missing_separation;
|
|
1077
|
+
return emit(l, valid, COMMENT_START);
|
|
1078
|
+
}
|
|
1079
|
+
static bool scan_directive_name(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1080
|
+
if (l->eof(l) || space(l->lookahead)) {
|
|
1081
|
+
if (s->first) {
|
|
1082
|
+
s->first = false;
|
|
1083
|
+
return emit_missing(
|
|
1084
|
+
l,
|
|
1085
|
+
valid,
|
|
1086
|
+
MISSING_DIRECTIVE_NAME,
|
|
1087
|
+
INCOMPLETE_DIRECTIVE_NAME
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
s->mode = s->directive_kind == YAML_DIRECTIVE ? DIRECTIVE_VERSION
|
|
1091
|
+
: s->directive_kind == TAG_DIRECTIVE ? DIRECTIVE_HANDLE
|
|
1092
|
+
: DIRECTIVE_PARAMETERS;
|
|
1093
|
+
return emit(l, valid, DIRECTIVE_NAME_END);
|
|
1094
|
+
}
|
|
1095
|
+
s->first = false;
|
|
1096
|
+
if (scan_invalid_character(l, valid))
|
|
1097
|
+
return true;
|
|
1098
|
+
return scan_directive_word(l, valid, DIRECTIVE_NAME);
|
|
1099
|
+
}
|
|
1100
|
+
static bool
|
|
1101
|
+
scan_yaml_version(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
1102
|
+
if (scan_invalid_character(l, valid))
|
|
1103
|
+
return true;
|
|
1104
|
+
s->mode = DIRECTIVE_PARAMETERS;
|
|
1105
|
+
if (end)
|
|
1106
|
+
return emit_missing(
|
|
1107
|
+
l,
|
|
1108
|
+
valid,
|
|
1109
|
+
MISSING_YAML_VERSION,
|
|
1110
|
+
INCOMPLETE_YAML_VERSION
|
|
1111
|
+
);
|
|
1112
|
+
unsigned part = 0;
|
|
1113
|
+
bool correct = true;
|
|
1114
|
+
do {
|
|
1115
|
+
int32_t c = l->lookahead;
|
|
1116
|
+
if (c >= '0' && c <= '9') {
|
|
1117
|
+
if (part == 0 || part == 2)
|
|
1118
|
+
part++;
|
|
1119
|
+
} else if (c == '.' && part == 1)
|
|
1120
|
+
part = 2;
|
|
1121
|
+
else
|
|
1122
|
+
correct = false;
|
|
1123
|
+
step(l);
|
|
1124
|
+
} while (!directive_boundary(l));
|
|
1125
|
+
return finish(
|
|
1126
|
+
l,
|
|
1127
|
+
valid,
|
|
1128
|
+
correct && part == 3 ? YAML_VERSION
|
|
1129
|
+
: correct && l->eof(l) ? UNFINISHED_YAML_VERSION
|
|
1130
|
+
: INVALID_YAML_VERSION
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
static bool
|
|
1134
|
+
scan_directive_handle(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
1135
|
+
if (scan_invalid_character(l, valid))
|
|
1136
|
+
return true;
|
|
1137
|
+
s->mode = DIRECTIVE_PREFIX;
|
|
1138
|
+
s->property_separation_notified = false;
|
|
1139
|
+
if (end)
|
|
1140
|
+
return emit_missing(l, valid, MISSING_TAG_HANDLE, INCOMPLETE_TAG_HANDLE);
|
|
1141
|
+
if (l->lookahead == '!') {
|
|
1142
|
+
step(l);
|
|
1143
|
+
s->handle_form = l->lookahead == '!' ? SECONDARY_HANDLE
|
|
1144
|
+
: directive_boundary(l) ? PRIMARY_HANDLE
|
|
1145
|
+
: NAMED_HANDLE;
|
|
1146
|
+
s->directive_handle = true;
|
|
1147
|
+
s->mode = HANDLE_SELECT;
|
|
1148
|
+
return emit(l, valid, TAG_HANDLE_START);
|
|
1149
|
+
}
|
|
1150
|
+
return scan_directive_word(l, valid, INVALID_TAG_HANDLE);
|
|
1151
|
+
}
|
|
1152
|
+
static bool
|
|
1153
|
+
scan_directive_prefix(Scanner *s, TSLexer *l, const bool *valid, bool end) {
|
|
1154
|
+
if (end) {
|
|
1155
|
+
s->mode = DIRECTIVE_PARAMETERS;
|
|
1156
|
+
return emit_missing(l, valid, MISSING_TAG_PREFIX, INCOMPLETE_TAG_PREFIX);
|
|
1157
|
+
}
|
|
1158
|
+
if (!s->separated && !s->property_separation_notified) {
|
|
1159
|
+
s->property_separation_notified = true;
|
|
1160
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
1161
|
+
}
|
|
1162
|
+
s->mode = PREFIX_BODY;
|
|
1163
|
+
s->first = true;
|
|
1164
|
+
return emit(l, valid, TAG_PREFIX_START);
|
|
1165
|
+
}
|
|
1166
|
+
static bool scan_directive(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1167
|
+
if (s->mode == DIRECTIVE_NAME_BODY)
|
|
1168
|
+
return scan_directive_name(s, l, valid);
|
|
1169
|
+
if (blank(l->lookahead))
|
|
1170
|
+
return scan_separation(l, valid);
|
|
1171
|
+
bool end =
|
|
1172
|
+
l->eof(l) || newline(l->lookahead) || (l->lookahead == '#' && s->separated);
|
|
1173
|
+
switch ((enum Mode)s->mode) {
|
|
1174
|
+
case DIRECTIVE_VERSION:
|
|
1175
|
+
return scan_yaml_version(s, l, valid, end);
|
|
1176
|
+
case DIRECTIVE_HANDLE:
|
|
1177
|
+
return scan_directive_handle(s, l, valid, end);
|
|
1178
|
+
case DIRECTIVE_PREFIX:
|
|
1179
|
+
return scan_directive_prefix(s, l, valid, end);
|
|
1180
|
+
default:
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
if (l->lookahead == '#' && s->separated)
|
|
1184
|
+
return start_comment(s, l, valid, DIRECTIVE_PARAMETERS, false);
|
|
1185
|
+
if (end) {
|
|
1186
|
+
s->mode = NORMAL;
|
|
1187
|
+
return emit(l, valid, DIRECTIVE_END);
|
|
1188
|
+
}
|
|
1189
|
+
if (scan_invalid_character(l, valid))
|
|
1190
|
+
return true;
|
|
1191
|
+
return scan_directive_word(
|
|
1192
|
+
l,
|
|
1193
|
+
valid,
|
|
1194
|
+
s->directive_kind == RESERVED_DIRECTIVE ? DIRECTIVE_PARAMETER
|
|
1195
|
+
: UNEXPECTED_DIRECTIVE_PARAMETER
|
|
1196
|
+
);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
static bool scalar_break(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1200
|
+
s->prefix = true;
|
|
1201
|
+
s->continuation = false;
|
|
1202
|
+
s->quote_line_empty = s->mode == DOUBLE;
|
|
1203
|
+
s->scalar_indent = true;
|
|
1204
|
+
s->scalar_spaces = 0;
|
|
1205
|
+
s->scalar_tab = false;
|
|
1206
|
+
return line_break(l, valid, SCALAR_LINE_BREAK);
|
|
1207
|
+
}
|
|
1208
|
+
/* Content resumes after the prefix of a continuation line; its first token
|
|
1209
|
+
* must be indented past the enclosing block indentation. */
|
|
1210
|
+
static bool resume_scalar_line(Scanner *s) {
|
|
1211
|
+
s->prefix = false;
|
|
1212
|
+
s->continuation = false;
|
|
1213
|
+
if (!s->scalar_indent)
|
|
1214
|
+
return true;
|
|
1215
|
+
s->scalar_indent = false;
|
|
1216
|
+
return s->scalar_spaces > s->indent;
|
|
1217
|
+
}
|
|
1218
|
+
static bool scalar_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1219
|
+
if (l->lookahead == '\t' && s->scalar_spaces <= s->indent) {
|
|
1220
|
+
s->scalar_tab = true;
|
|
1221
|
+
return take(l, valid, INVALID_INDENTATION);
|
|
1222
|
+
}
|
|
1223
|
+
do {
|
|
1224
|
+
if (l->lookahead == '\t')
|
|
1225
|
+
s->scalar_tab = true;
|
|
1226
|
+
else if (!s->scalar_tab)
|
|
1227
|
+
s->scalar_spaces++;
|
|
1228
|
+
step(l);
|
|
1229
|
+
} while (
|
|
1230
|
+
blank(l->lookahead) &&
|
|
1231
|
+
!(l->lookahead == '\t' && s->scalar_spaces <= s->indent)
|
|
1232
|
+
);
|
|
1233
|
+
return finish(l, valid, SCALAR_LINE_PREFIX);
|
|
1234
|
+
}
|
|
1235
|
+
static bool scan_quote(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1236
|
+
int32_t quote = s->mode == SINGLE ? '\'' : '"';
|
|
1237
|
+
if (l->eof(l)) {
|
|
1238
|
+
if (!emit(l, valid, INCOMPLETE_QUOTE_CLOSE))
|
|
1239
|
+
return false;
|
|
1240
|
+
s->mode = NORMAL;
|
|
1241
|
+
s->prefix = false;
|
|
1242
|
+
s->json = true;
|
|
1243
|
+
return true;
|
|
1244
|
+
}
|
|
1245
|
+
if (newline(l->lookahead))
|
|
1246
|
+
return scalar_break(s, l, valid);
|
|
1247
|
+
if (s->prefix && blank(l->lookahead))
|
|
1248
|
+
return scalar_prefix(s, l, valid);
|
|
1249
|
+
if (!resume_scalar_line(s))
|
|
1250
|
+
return emit(l, valid, MISSING_INDENTATION);
|
|
1251
|
+
if (invalid_quoted(l->lookahead) && scan_invalid_character(l, valid))
|
|
1252
|
+
return true;
|
|
1253
|
+
if (l->lookahead == quote) {
|
|
1254
|
+
step(l);
|
|
1255
|
+
l->mark_end(l);
|
|
1256
|
+
if (quote == '\'' && l->lookahead == '\'') {
|
|
1257
|
+
step(l);
|
|
1258
|
+
return finish(l, valid, ESCAPED_QUOTE);
|
|
1259
|
+
}
|
|
1260
|
+
if (!emit(l, valid, QUOTE_CLOSE))
|
|
1261
|
+
return false;
|
|
1262
|
+
s->mode = NORMAL;
|
|
1263
|
+
s->json = true;
|
|
1264
|
+
return true;
|
|
1265
|
+
}
|
|
1266
|
+
if (s->mode == DOUBLE && l->lookahead == '\\') {
|
|
1267
|
+
step(l);
|
|
1268
|
+
l->mark_end(l);
|
|
1269
|
+
if (newline(l->lookahead))
|
|
1270
|
+
return emit(
|
|
1271
|
+
l,
|
|
1272
|
+
valid,
|
|
1273
|
+
s->quote_line_empty ? INVALID_LINE_CONTINUATION : ESCAPE_INDICATOR
|
|
1274
|
+
);
|
|
1275
|
+
if (l->eof(l))
|
|
1276
|
+
return emit(l, valid, INCOMPLETE_ESCAPE);
|
|
1277
|
+
if (invalid_quoted(l->lookahead)) {
|
|
1278
|
+
/* The prefix belongs to the scalar; decoding failure owns its own bytes.
|
|
1279
|
+
*/
|
|
1280
|
+
return emit(l, valid, INVALID_ESCAPE);
|
|
1281
|
+
}
|
|
1282
|
+
int32_t c = l->lookahead;
|
|
1283
|
+
const char *simple = "0abtnvfre \t\"/\\N_LP";
|
|
1284
|
+
bool ok = c > 0 && c < 128 && strchr(simple, (int)c);
|
|
1285
|
+
unsigned digits = c == 'x' ? 2 : c == 'u' ? 4 : c == 'U' ? 8 : 0;
|
|
1286
|
+
step(l);
|
|
1287
|
+
l->mark_end(l);
|
|
1288
|
+
if (digits) {
|
|
1289
|
+
uint32_t value;
|
|
1290
|
+
unsigned remaining = hex_digits(l, digits, &value);
|
|
1291
|
+
uint64_t lower = (uint64_t)value << (remaining * 4);
|
|
1292
|
+
uint64_t upper = lower | ((UINT64_C(1) << (remaining * 4)) - 1);
|
|
1293
|
+
ok = lower <= 0x10ffff && (lower < 0xd800 || upper > 0xdfff);
|
|
1294
|
+
if (remaining)
|
|
1295
|
+
return emit(
|
|
1296
|
+
l,
|
|
1297
|
+
valid,
|
|
1298
|
+
l->eof(l) && ok ? INCOMPLETE_ESCAPE : INVALID_ESCAPE
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
if (ok)
|
|
1302
|
+
s->quote_line_empty = false;
|
|
1303
|
+
return emit(l, valid, ok ? QUOTED_ESCAPE : INVALID_ESCAPE);
|
|
1304
|
+
}
|
|
1305
|
+
bool text = false;
|
|
1306
|
+
while (
|
|
1307
|
+
!l->eof(l) &&
|
|
1308
|
+
l->lookahead !=
|
|
1309
|
+
quote &&
|
|
1310
|
+
!newline(l->lookahead) &&
|
|
1311
|
+
!invalid_quoted(l->lookahead) &&
|
|
1312
|
+
!(s->mode == DOUBLE && l->lookahead == '\\')
|
|
1313
|
+
) {
|
|
1314
|
+
if (blank(l->lookahead)) {
|
|
1315
|
+
step(l);
|
|
1316
|
+
skip_blanks(l);
|
|
1317
|
+
if (newline(l->lookahead)) {
|
|
1318
|
+
if (text)
|
|
1319
|
+
return emit(l, valid, SCALAR_TEXT);
|
|
1320
|
+
return finish(l, valid, SCALAR_LINE_SUFFIX);
|
|
1321
|
+
}
|
|
1322
|
+
text = true;
|
|
1323
|
+
l->mark_end(l);
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
step(l);
|
|
1327
|
+
s->quote_line_empty = false;
|
|
1328
|
+
text = true;
|
|
1329
|
+
l->mark_end(l);
|
|
1330
|
+
}
|
|
1331
|
+
return text && emit(l, valid, SCALAR_TEXT);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
static bool scan_plain(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1335
|
+
bool text = false;
|
|
1336
|
+
if (s->first) {
|
|
1337
|
+
s->first = false;
|
|
1338
|
+
if (
|
|
1339
|
+
l->lookahead >
|
|
1340
|
+
0 &&
|
|
1341
|
+
l->lookahead <
|
|
1342
|
+
128 &&
|
|
1343
|
+
strchr(",]}@`%&*!|>", (int)l->lookahead)
|
|
1344
|
+
)
|
|
1345
|
+
return take(l, valid, INVALID_SCALAR_START);
|
|
1346
|
+
if (l->lookahead == '-' || l->lookahead == '?' || l->lookahead == ':') {
|
|
1347
|
+
step(l);
|
|
1348
|
+
if (
|
|
1349
|
+
space(l->lookahead) ||
|
|
1350
|
+
l->eof(l) ||
|
|
1351
|
+
(s->flow && flow_indicator(l->lookahead))
|
|
1352
|
+
) {
|
|
1353
|
+
return finish(l, valid, INVALID_SCALAR_START);
|
|
1354
|
+
}
|
|
1355
|
+
text = true;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (s->continuation || s->prefix) {
|
|
1359
|
+
if (newline(l->lookahead))
|
|
1360
|
+
return scalar_break(s, l, valid);
|
|
1361
|
+
if (blank(l->lookahead)) {
|
|
1362
|
+
if (s->prefix)
|
|
1363
|
+
return scalar_prefix(s, l, valid);
|
|
1364
|
+
step(l);
|
|
1365
|
+
skip_blanks(l);
|
|
1366
|
+
return finish(l, valid, SCALAR_LINE_SUFFIX);
|
|
1367
|
+
}
|
|
1368
|
+
if (!resume_scalar_line(s))
|
|
1369
|
+
return emit(l, valid, MISSING_INDENTATION);
|
|
1370
|
+
} else if (space(l->lookahead)) {
|
|
1371
|
+
bool broken = false;
|
|
1372
|
+
uint32_t indentation = 0;
|
|
1373
|
+
bool tab = false;
|
|
1374
|
+
while (space(l->lookahead)) {
|
|
1375
|
+
broken |= newline(l->lookahead);
|
|
1376
|
+
if (newline(l->lookahead)) {
|
|
1377
|
+
indentation = 0;
|
|
1378
|
+
tab = false;
|
|
1379
|
+
} else if (l->lookahead == '\t')
|
|
1380
|
+
tab = true;
|
|
1381
|
+
else if (!tab)
|
|
1382
|
+
indentation++;
|
|
1383
|
+
step(l);
|
|
1384
|
+
}
|
|
1385
|
+
bool more = !l->eof(l) &&
|
|
1386
|
+
l->lookahead !=
|
|
1387
|
+
'#' &&
|
|
1388
|
+
(!s->flow || !flow_indicator(l->lookahead)) &&
|
|
1389
|
+
(!broken || s->flow || indentation > s->indent);
|
|
1390
|
+
if (more && l->lookahead == ':') {
|
|
1391
|
+
step(l);
|
|
1392
|
+
more = !colon_boundary(l, s->flow);
|
|
1393
|
+
}
|
|
1394
|
+
if (
|
|
1395
|
+
more &&
|
|
1396
|
+
l->get_column(l) ==
|
|
1397
|
+
0 &&
|
|
1398
|
+
(l->lookahead == 0xfeff || document_marker(l))
|
|
1399
|
+
)
|
|
1400
|
+
more = false;
|
|
1401
|
+
if (more && !broken) {
|
|
1402
|
+
text = true;
|
|
1403
|
+
} else {
|
|
1404
|
+
if (more && emit(l, valid, PLAIN_CONTINUE)) {
|
|
1405
|
+
s->continuation = true;
|
|
1406
|
+
return true;
|
|
1407
|
+
}
|
|
1408
|
+
if (!emit(l, valid, PLAIN_END))
|
|
1409
|
+
return false;
|
|
1410
|
+
s->mode = NORMAL;
|
|
1411
|
+
return true;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (!text && scan_invalid_character(l, valid))
|
|
1415
|
+
return true;
|
|
1416
|
+
l->mark_end(l);
|
|
1417
|
+
while (!l->eof(l)) {
|
|
1418
|
+
int32_t c = l->lookahead;
|
|
1419
|
+
if (newline(c) || invalid_unquoted(c) || (s->flow && flow_indicator(c)))
|
|
1420
|
+
break;
|
|
1421
|
+
if (c == ':') {
|
|
1422
|
+
step(l);
|
|
1423
|
+
if (colon_boundary(l, s->flow))
|
|
1424
|
+
break;
|
|
1425
|
+
text = true;
|
|
1426
|
+
l->mark_end(l);
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
if (blank(c)) {
|
|
1430
|
+
step(l);
|
|
1431
|
+
skip_blanks(l);
|
|
1432
|
+
if (l->eof(l) || newline(l->lookahead) || l->lookahead == '#')
|
|
1433
|
+
break;
|
|
1434
|
+
if (invalid_unquoted(l->lookahead)) {
|
|
1435
|
+
text = true;
|
|
1436
|
+
l->mark_end(l);
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1441
|
+
step(l);
|
|
1442
|
+
text = true;
|
|
1443
|
+
l->mark_end(l);
|
|
1444
|
+
}
|
|
1445
|
+
if (text)
|
|
1446
|
+
return emit(l, valid, SCALAR_TEXT);
|
|
1447
|
+
if (!emit(l, valid, PLAIN_END))
|
|
1448
|
+
return false;
|
|
1449
|
+
s->mode = NORMAL;
|
|
1450
|
+
return true;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
static bool scan_block_header(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1454
|
+
if (s->mode == BLOCK_HEADER_DONE || l->eof(l)) {
|
|
1455
|
+
s->mode = BLOCK_DETECT;
|
|
1456
|
+
return emit(l, valid, BLOCK_HEADER_END);
|
|
1457
|
+
}
|
|
1458
|
+
if (scan_invalid_character(l, valid))
|
|
1459
|
+
return true;
|
|
1460
|
+
if (newline(l->lookahead)) {
|
|
1461
|
+
s->mode = BLOCK_HEADER_DONE;
|
|
1462
|
+
return line_break(l, valid, BLOCK_HEADER_BREAK);
|
|
1463
|
+
}
|
|
1464
|
+
if (blank(l->lookahead)) {
|
|
1465
|
+
s->header_flags |= HEADER_SEPARATION;
|
|
1466
|
+
return scan_separation(l, valid);
|
|
1467
|
+
}
|
|
1468
|
+
if (l->lookahead == '#' && valid[COMMENT_START])
|
|
1469
|
+
return start_comment(s, l, valid, BLOCK_HEADER, !s->separated);
|
|
1470
|
+
if (
|
|
1471
|
+
l->lookahead >=
|
|
1472
|
+
'1' &&
|
|
1473
|
+
l->lookahead <=
|
|
1474
|
+
'9' &&
|
|
1475
|
+
!(s->header_flags & (HEADER_INDENTATION | HEADER_SEPARATION))
|
|
1476
|
+
) {
|
|
1477
|
+
s->block_indent = s->indent + l->lookahead - '0';
|
|
1478
|
+
s->header_flags |= HEADER_INDENTATION;
|
|
1479
|
+
return take(l, valid, INDENTATION_INDICATOR);
|
|
1480
|
+
}
|
|
1481
|
+
if (
|
|
1482
|
+
(l->lookahead == '+' || l->lookahead == '-') &&
|
|
1483
|
+
!(s->header_flags & (HEADER_CHOMPING | HEADER_SEPARATION))
|
|
1484
|
+
) {
|
|
1485
|
+
s->header_flags |= HEADER_CHOMPING;
|
|
1486
|
+
return take(l, valid, CHOMPING_INDICATOR);
|
|
1487
|
+
}
|
|
1488
|
+
if (l->lookahead >= '1' && l->lookahead <= '9')
|
|
1489
|
+
return take(l, valid, INVALID_HEADER_INDENTATION);
|
|
1490
|
+
if (l->lookahead == '+' || l->lookahead == '-')
|
|
1491
|
+
return take(l, valid, INVALID_HEADER_CHOMPING);
|
|
1492
|
+
step(l);
|
|
1493
|
+
while (
|
|
1494
|
+
!l->eof(l) &&
|
|
1495
|
+
!space(l->lookahead) &&
|
|
1496
|
+
l->lookahead !=
|
|
1497
|
+
'#' &&
|
|
1498
|
+
!invalid_unquoted(l->lookahead) &&
|
|
1499
|
+
!(l->lookahead >= '0' && l->lookahead <= '9') &&
|
|
1500
|
+
l->lookahead !=
|
|
1501
|
+
'+' &&
|
|
1502
|
+
l->lookahead != '-'
|
|
1503
|
+
)
|
|
1504
|
+
step(l);
|
|
1505
|
+
return finish(l, valid, INVALID_BLOCK_HEADER);
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
static void reset_line(Scanner *s) {
|
|
1509
|
+
s->line = true;
|
|
1510
|
+
s->line_context = false;
|
|
1511
|
+
s->line_prefixed = false;
|
|
1512
|
+
s->line_indent = 0;
|
|
1513
|
+
s->line_mapping_key = false;
|
|
1514
|
+
s->prefix_invalid = false;
|
|
1515
|
+
s->after_document_end = false;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
/* A document that ends without "..." must be followed by an explicit
|
|
1519
|
+
* document; a directive document then also lacks its document end marker. */
|
|
1520
|
+
static void close_document(Scanner *s) {
|
|
1521
|
+
s->document = false;
|
|
1522
|
+
s->document_content = false;
|
|
1523
|
+
s->explicit_document_required = true;
|
|
1524
|
+
}
|
|
1525
|
+
static void open_document(Scanner *s, bool started) {
|
|
1526
|
+
s->document = true;
|
|
1527
|
+
s->document_started = started;
|
|
1528
|
+
s->document_content = false;
|
|
1529
|
+
s->flow = 0;
|
|
1530
|
+
s->indent = -1;
|
|
1531
|
+
s->block_out = false;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
/* Close open constructs before a document marker; directives and stream BOMs
|
|
1535
|
+
* are left for normal scanning. */
|
|
1536
|
+
static bool scan_boundary(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1537
|
+
if (s->mode == SINGLE || s->mode == DOUBLE) {
|
|
1538
|
+
s->mode = NORMAL;
|
|
1539
|
+
s->prefix = false;
|
|
1540
|
+
s->scalar_indent = false;
|
|
1541
|
+
return emit(l, valid, MISSING_QUOTE_CLOSE);
|
|
1542
|
+
}
|
|
1543
|
+
if (s->mode == PLAIN) {
|
|
1544
|
+
s->mode = NORMAL;
|
|
1545
|
+
return emit(l, valid, PLAIN_END);
|
|
1546
|
+
}
|
|
1547
|
+
if (s->mode == BLOCK_BODY) {
|
|
1548
|
+
s->mode = NORMAL;
|
|
1549
|
+
reset_line(s);
|
|
1550
|
+
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1551
|
+
}
|
|
1552
|
+
static const enum Token closings[] = {
|
|
1553
|
+
EMPTY_BLOCK_NODE,
|
|
1554
|
+
MISSING_FLOW_SEQUENCE_CLOSE,
|
|
1555
|
+
MISSING_FLOW_MAPPING_CLOSE,
|
|
1556
|
+
MAPPING_END,
|
|
1557
|
+
SEQUENCE_END,
|
|
1558
|
+
DEDENT,
|
|
1559
|
+
RESTORE_INDENT
|
|
1560
|
+
};
|
|
1561
|
+
if (emit_closing(s, l, valid, closings, sizeof(closings) / sizeof(*closings)))
|
|
1562
|
+
return true;
|
|
1563
|
+
if (valid[DOCUMENT_CLOSE] && s->document && s->document_started) {
|
|
1564
|
+
close_document(s);
|
|
1565
|
+
return emit(l, valid, DOCUMENT_CLOSE);
|
|
1566
|
+
}
|
|
1567
|
+
enum Boundary boundary = (enum Boundary)s->boundary;
|
|
1568
|
+
bool opens = boundary == DOCUMENT_START_LINE || boundary == DIRECTIVE_LINE;
|
|
1569
|
+
if (opens && valid[DOCUMENT_OPEN] && !s->document) {
|
|
1570
|
+
open_document(s, false);
|
|
1571
|
+
return emit(l, valid, DOCUMENT_OPEN);
|
|
1572
|
+
}
|
|
1573
|
+
if (boundary == DIRECTIVE_LINE || boundary == STREAM_BOM) {
|
|
1574
|
+
if (
|
|
1575
|
+
boundary ==
|
|
1576
|
+
DIRECTIVE_LINE &&
|
|
1577
|
+
s->explicit_document_required &&
|
|
1578
|
+
valid[MISSING_DOCUMENT_END]
|
|
1579
|
+
) {
|
|
1580
|
+
s->explicit_document_required = false;
|
|
1581
|
+
return emit(l, valid, MISSING_DOCUMENT_END);
|
|
1582
|
+
}
|
|
1583
|
+
return false;
|
|
1584
|
+
}
|
|
1585
|
+
enum Token token =
|
|
1586
|
+
boundary == DOCUMENT_START_LINE ? DOCUMENT_START : DOCUMENT_END;
|
|
1587
|
+
if (!valid[token])
|
|
1588
|
+
return false;
|
|
1589
|
+
for (unsigned i = 0; i < 3; i++)
|
|
1590
|
+
step(l);
|
|
1591
|
+
l->mark_end(l);
|
|
1592
|
+
s->document_started = token == DOCUMENT_START;
|
|
1593
|
+
s->after_document_end = token == DOCUMENT_END;
|
|
1594
|
+
s->explicit_document_required = false;
|
|
1595
|
+
return emit(l, valid, token);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
/* Auto-detects the content indentation from the first non-empty body line,
|
|
1599
|
+
* or from the longest leading empty line when no content follows. */
|
|
1600
|
+
static bool detect_block_indent(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1601
|
+
if (s->block_indent < 0) {
|
|
1602
|
+
uint32_t longest = 0;
|
|
1603
|
+
for (;;) {
|
|
1604
|
+
uint32_t spaces = count_spaces(l);
|
|
1605
|
+
if (newline(l->lookahead)) {
|
|
1606
|
+
if (spaces > longest)
|
|
1607
|
+
longest = spaces;
|
|
1608
|
+
skip_line_break(l);
|
|
1609
|
+
} else {
|
|
1610
|
+
bool content = !l->eof(l) && spaces > s->indent;
|
|
1611
|
+
if (
|
|
1612
|
+
content && !spaces && (l->lookahead == 0xfeff || document_marker(l))
|
|
1613
|
+
)
|
|
1614
|
+
content = false;
|
|
1615
|
+
s->block_indent =
|
|
1616
|
+
content ? spaces : (spaces > longest ? spaces : longest);
|
|
1617
|
+
break;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
s->block_leading = true;
|
|
1622
|
+
s->mode = BLOCK_BODY;
|
|
1623
|
+
return emit(l, valid, BLOCK_BODY_START);
|
|
1624
|
+
}
|
|
1625
|
+
static bool scan_block_body(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1626
|
+
if (l->eof(l)) {
|
|
1627
|
+
s->mode = NORMAL;
|
|
1628
|
+
reset_line(s);
|
|
1629
|
+
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1630
|
+
}
|
|
1631
|
+
uint32_t spaces = count_spaces(l);
|
|
1632
|
+
bool empty = newline(l->lookahead) || l->eof(l);
|
|
1633
|
+
bool spaced = spaces > s->block_indent || l->lookahead == '\t';
|
|
1634
|
+
/* A less indented line that holds only blanks and a comment is a
|
|
1635
|
+
* separation line of the enclosing construct, not scalar content. */
|
|
1636
|
+
bool separation = false;
|
|
1637
|
+
if (!empty && spaces < s->block_indent && l->lookahead == '\t') {
|
|
1638
|
+
skip_blanks(l);
|
|
1639
|
+
separation = l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
|
|
1640
|
+
}
|
|
1641
|
+
if (
|
|
1642
|
+
!empty &&
|
|
1643
|
+
(spaces <=
|
|
1644
|
+
s->indent ||
|
|
1645
|
+
separation ||
|
|
1646
|
+
(spaces < s->block_indent && l->lookahead == '#'))
|
|
1647
|
+
) {
|
|
1648
|
+
s->mode = NORMAL;
|
|
1649
|
+
reset_line(s);
|
|
1650
|
+
return emit(l, valid, BLOCK_SCALAR_END);
|
|
1651
|
+
}
|
|
1652
|
+
s->block_empty = empty &&
|
|
1653
|
+
(spaces <=
|
|
1654
|
+
s->block_indent ||
|
|
1655
|
+
(s->block_leading && !(s->header_flags & HEADER_INDENTATION)));
|
|
1656
|
+
if (!s->block_empty)
|
|
1657
|
+
s->block_leading = false;
|
|
1658
|
+
s->block_prefix = true;
|
|
1659
|
+
s->scalar_indent = true;
|
|
1660
|
+
s->mode = BLOCK_LINE;
|
|
1661
|
+
return emit(
|
|
1662
|
+
l,
|
|
1663
|
+
valid,
|
|
1664
|
+
s->block_empty ? BLOCK_EMPTY_LINE_START
|
|
1665
|
+
: spaced ? BLOCK_SPACED_LINE_START
|
|
1666
|
+
: BLOCK_TEXT_LINE_START
|
|
1667
|
+
);
|
|
1668
|
+
}
|
|
1669
|
+
static bool scan_block_line(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1670
|
+
if (s->mode == BLOCK_LINE_DONE || l->eof(l)) {
|
|
1671
|
+
s->mode = BLOCK_BODY;
|
|
1672
|
+
return emit(l, valid, BLOCK_LINE_END);
|
|
1673
|
+
}
|
|
1674
|
+
if (s->block_prefix) {
|
|
1675
|
+
s->block_prefix = false;
|
|
1676
|
+
bool consumed = false;
|
|
1677
|
+
while (l->lookahead == ' ' && l->get_column(l) < s->block_indent) {
|
|
1678
|
+
step(l);
|
|
1679
|
+
consumed = true;
|
|
1680
|
+
}
|
|
1681
|
+
if (consumed) {
|
|
1682
|
+
return finish(l, valid, SCALAR_LINE_PREFIX);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (s->scalar_indent) {
|
|
1686
|
+
s->scalar_indent = false;
|
|
1687
|
+
if (s->block_empty && s->block_leading && l->lookahead == ' ') {
|
|
1688
|
+
count_spaces(l);
|
|
1689
|
+
return finish(l, valid, INVALID_INDENTATION);
|
|
1690
|
+
}
|
|
1691
|
+
if (!s->block_empty && l->get_column(l) < s->block_indent)
|
|
1692
|
+
return emit(l, valid, MISSING_INDENTATION);
|
|
1693
|
+
}
|
|
1694
|
+
if (newline(l->lookahead)) {
|
|
1695
|
+
s->mode = BLOCK_LINE_DONE;
|
|
1696
|
+
reset_line(s);
|
|
1697
|
+
return line_break(l, valid, SCALAR_LINE_BREAK);
|
|
1698
|
+
}
|
|
1699
|
+
return scan_line_text(l, valid, SCALAR_TEXT);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
static bool scan_comment(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1703
|
+
if (s->mode == COMMENT_BEGIN) {
|
|
1704
|
+
if (s->first) {
|
|
1705
|
+
s->first = false;
|
|
1706
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
1707
|
+
}
|
|
1708
|
+
s->mode = COMMENT;
|
|
1709
|
+
return take(l, valid, COMMENT_MARKER);
|
|
1710
|
+
}
|
|
1711
|
+
if (l->eof(l) || newline(l->lookahead)) {
|
|
1712
|
+
if (!emit(l, valid, COMMENT_END))
|
|
1713
|
+
return false;
|
|
1714
|
+
s->mode = s->return_mode;
|
|
1715
|
+
s->return_mode = NORMAL;
|
|
1716
|
+
return true;
|
|
1717
|
+
}
|
|
1718
|
+
return scan_line_text(l, valid, COMMENT_TEXT);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
static bool start_line_prefix(
|
|
1722
|
+
Scanner *s,
|
|
1723
|
+
TSLexer *l,
|
|
1724
|
+
const bool *valid,
|
|
1725
|
+
bool prefix_invalid,
|
|
1726
|
+
bool tab_invalid,
|
|
1727
|
+
bool indent_checked
|
|
1728
|
+
) {
|
|
1729
|
+
s->prefix_invalid = prefix_invalid;
|
|
1730
|
+
s->tab_invalid = tab_invalid;
|
|
1731
|
+
s->indent_checked = indent_checked;
|
|
1732
|
+
s->prefix_tab = false;
|
|
1733
|
+
s->mode = PREFIX;
|
|
1734
|
+
return emit(l, valid, LINE_PREFIX_START);
|
|
1735
|
+
}
|
|
1736
|
+
static bool scan_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1737
|
+
if (s->mode == COMPACT_PREFIX)
|
|
1738
|
+
return start_line_prefix(s, l, valid, false, true, true);
|
|
1739
|
+
if (l->lookahead == ' ' && !s->prefix_tab) {
|
|
1740
|
+
bool excess = s->prefix_invalid && l->get_column(l) >= s->indent;
|
|
1741
|
+
do {
|
|
1742
|
+
step(l);
|
|
1743
|
+
} while (
|
|
1744
|
+
l->lookahead ==
|
|
1745
|
+
' ' &&
|
|
1746
|
+
(excess || !s->prefix_invalid || l->get_column(l) < s->indent)
|
|
1747
|
+
);
|
|
1748
|
+
return finish(l, valid, excess ? INVALID_INDENTATION : INDENTATION);
|
|
1749
|
+
}
|
|
1750
|
+
if (blank(l->lookahead)) {
|
|
1751
|
+
s->prefix_tab = true;
|
|
1752
|
+
if (s->tab_invalid && l->lookahead == '\t')
|
|
1753
|
+
return take(l, valid, INVALID_INDENTATION);
|
|
1754
|
+
do {
|
|
1755
|
+
step(l);
|
|
1756
|
+
} while (blank(l->lookahead) && !(s->tab_invalid && l->lookahead == '\t'));
|
|
1757
|
+
return finish(l, valid, SEPARATION);
|
|
1758
|
+
}
|
|
1759
|
+
if (
|
|
1760
|
+
!s->indent_checked &&
|
|
1761
|
+
s->flow &&
|
|
1762
|
+
!newline(l->lookahead) &&
|
|
1763
|
+
!l->eof(l) &&
|
|
1764
|
+
l->lookahead !=
|
|
1765
|
+
'#' &&
|
|
1766
|
+
s->line_indent <= s->indent
|
|
1767
|
+
) {
|
|
1768
|
+
s->indent_checked = true;
|
|
1769
|
+
return emit(l, valid, MISSING_INDENTATION);
|
|
1770
|
+
}
|
|
1771
|
+
s->mode = NORMAL;
|
|
1772
|
+
return emit(l, valid, LINE_PREFIX_END);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
static bool
|
|
1776
|
+
scan_node_start(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
1777
|
+
int32_t first = l->lookahead;
|
|
1778
|
+
enum Token kind = s->flow ? node_start(first) : classify_block_start(s, l);
|
|
1779
|
+
if (!s->line && valid[DOCUMENT_COMPACT_START] && block_collection(kind))
|
|
1780
|
+
return emit(l, valid, DOCUMENT_COMPACT_START);
|
|
1781
|
+
if (
|
|
1782
|
+
!s->flow &&
|
|
1783
|
+
s->line &&
|
|
1784
|
+
column ==
|
|
1785
|
+
s->indent &&
|
|
1786
|
+
kind !=
|
|
1787
|
+
SEQUENCE_START &&
|
|
1788
|
+
valid[SEQUENCE_END]
|
|
1789
|
+
)
|
|
1790
|
+
return emit(l, valid, SEQUENCE_END);
|
|
1791
|
+
if (
|
|
1792
|
+
!s->flow &&
|
|
1793
|
+
s->line &&
|
|
1794
|
+
(column == s->indent || s->prefix_invalid) &&
|
|
1795
|
+
kind ==
|
|
1796
|
+
SEQUENCE_START &&
|
|
1797
|
+
valid[MAPPING_END]
|
|
1798
|
+
)
|
|
1799
|
+
return emit(l, valid, MAPPING_END);
|
|
1800
|
+
if (
|
|
1801
|
+
!s->flow &&
|
|
1802
|
+
s->line &&
|
|
1803
|
+
(column == s->indent || s->prefix_invalid) &&
|
|
1804
|
+
valid[PAIR_START] &&
|
|
1805
|
+
kind != SEQUENCE_START
|
|
1806
|
+
) {
|
|
1807
|
+
s->key_done = false;
|
|
1808
|
+
return emit(l, valid, PAIR_START);
|
|
1809
|
+
}
|
|
1810
|
+
if (
|
|
1811
|
+
kind ==
|
|
1812
|
+
MAPPING_START &&
|
|
1813
|
+
!valid[MAPPING_START] &&
|
|
1814
|
+
!valid[INDENT] &&
|
|
1815
|
+
!valid[PAIR_START]
|
|
1816
|
+
)
|
|
1817
|
+
kind = node_start(first);
|
|
1818
|
+
if ((kind == LITERAL_START || kind == FOLDED_START) && !valid[kind])
|
|
1819
|
+
kind = PLAIN_START;
|
|
1820
|
+
if (!s->flow && block_collection(kind)) {
|
|
1821
|
+
enum Token shift = column < s->indent ? OUTDENT : INDENT;
|
|
1822
|
+
if (column != s->indent && emit_closing(s, l, valid, &shift, 1))
|
|
1823
|
+
return true;
|
|
1824
|
+
if (column == s->indent || (s->line && s->prefix_invalid)) {
|
|
1825
|
+
enum Token token = kind == MAPPING_START && valid[PAIR_START] ? PAIR_START
|
|
1826
|
+
: kind == SEQUENCE_START && valid[ENTRY_START] ? ENTRY_START
|
|
1827
|
+
: kind;
|
|
1828
|
+
if (valid[token]) {
|
|
1829
|
+
if (token == PAIR_START)
|
|
1830
|
+
s->key_done = false;
|
|
1831
|
+
return emit(l, valid, token);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
if (kind == PLAIN_START || (kind == MAPPING_START && valid[PLAIN_START]))
|
|
1836
|
+
return start_plain(s, l, valid);
|
|
1837
|
+
if (kind == PROPERTIES_START) {
|
|
1838
|
+
s->json = false;
|
|
1839
|
+
s->property_flags = 0;
|
|
1840
|
+
s->properties_ready = false;
|
|
1841
|
+
s->duplicate_pending = false;
|
|
1842
|
+
s->property_separation_notified = false;
|
|
1843
|
+
}
|
|
1844
|
+
return !block_collection(kind) && emit(l, valid, kind);
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
static bool scan_node_open(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1848
|
+
if (
|
|
1849
|
+
(l->lookahead == '\'' && valid[SINGLE_OPEN]) ||
|
|
1850
|
+
(l->lookahead == '"' && valid[DOUBLE_OPEN])
|
|
1851
|
+
) {
|
|
1852
|
+
bool single = l->lookahead == '\'';
|
|
1853
|
+
s->mode = single ? SINGLE : DOUBLE;
|
|
1854
|
+
s->quote_line_empty = false;
|
|
1855
|
+
return take(l, valid, single ? SINGLE_OPEN : DOUBLE_OPEN);
|
|
1856
|
+
}
|
|
1857
|
+
if (
|
|
1858
|
+
(l->lookahead == '[' && valid[FLOW_SEQUENCE_OPEN]) ||
|
|
1859
|
+
(l->lookahead == '{' && valid[FLOW_MAPPING_OPEN])
|
|
1860
|
+
) {
|
|
1861
|
+
bool sequence = l->lookahead == '[';
|
|
1862
|
+
s->flow++;
|
|
1863
|
+
return take(l, valid, sequence ? FLOW_SEQUENCE_OPEN : FLOW_MAPPING_OPEN);
|
|
1864
|
+
}
|
|
1865
|
+
if (
|
|
1866
|
+
(l->lookahead == '|' && valid[LITERAL_INDICATOR]) ||
|
|
1867
|
+
(l->lookahead == '>' && valid[FOLDED_INDICATOR])
|
|
1868
|
+
) {
|
|
1869
|
+
bool literal = l->lookahead == '|';
|
|
1870
|
+
s->mode = BLOCK_HEADER;
|
|
1871
|
+
s->block_indent = -1;
|
|
1872
|
+
s->header_flags = 0;
|
|
1873
|
+
return take(l, valid, literal ? LITERAL_INDICATOR : FOLDED_INDICATOR);
|
|
1874
|
+
}
|
|
1875
|
+
return false;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
static bool scan(Scanner *s, TSLexer *l, const bool *valid);
|
|
1879
|
+
|
|
1880
|
+
static bool scan_content(Scanner *s, TSLexer *l, const bool *valid);
|
|
1881
|
+
static bool
|
|
1882
|
+
scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column);
|
|
1883
|
+
static bool scan_properties(
|
|
1884
|
+
Scanner *s,
|
|
1885
|
+
TSLexer *l,
|
|
1886
|
+
const bool *valid,
|
|
1887
|
+
bool property_pending
|
|
1888
|
+
);
|
|
1889
|
+
|
|
1890
|
+
static bool scan_line_context(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1891
|
+
s->line_indent = count_spaces(l);
|
|
1892
|
+
skip_blanks(l);
|
|
1893
|
+
s->line_head = l->lookahead;
|
|
1894
|
+
s->layout_only = l->eof(l) || newline(l->lookahead) || l->lookahead == '#';
|
|
1895
|
+
if (s->line_head == '-' || s->line_head == ':') {
|
|
1896
|
+
step(l);
|
|
1897
|
+
if (!space(l->lookahead) && !l->eof(l))
|
|
1898
|
+
s->line_head = 0;
|
|
1899
|
+
} else if (
|
|
1900
|
+
!s->flow &&
|
|
1901
|
+
(s->line_head == '&' || s->line_head == '!' || s->line_head == '*')
|
|
1902
|
+
) {
|
|
1903
|
+
s->line_mapping_key = classify_block_start(s, l) == MAPPING_START;
|
|
1904
|
+
}
|
|
1905
|
+
s->line_context = true;
|
|
1906
|
+
return emit(l, valid, LINE_CONTEXT);
|
|
1907
|
+
}
|
|
1908
|
+
static bool begin_line_prefix(Scanner *s, TSLexer *l, const bool *valid) {
|
|
1909
|
+
uint32_t spaces = count_spaces(l);
|
|
1910
|
+
skip_blanks(l);
|
|
1911
|
+
bool prefix_invalid = !s->layout_only &&
|
|
1912
|
+
!s->flow &&
|
|
1913
|
+
spaces >
|
|
1914
|
+
s->indent &&
|
|
1915
|
+
!valid[VALUE_START] &&
|
|
1916
|
+
!valid[SEQUENCE_VALUE_START] &&
|
|
1917
|
+
!valid[INDENT] &&
|
|
1918
|
+
(valid[PAIR_START] || valid[ENTRY_START]);
|
|
1919
|
+
bool tab_invalid = !s->layout_only && spaces <= s->indent;
|
|
1920
|
+
if (!s->layout_only && !s->flow)
|
|
1921
|
+
tab_invalid |= block_collection(classify_block_node(l));
|
|
1922
|
+
s->line_prefixed = true;
|
|
1923
|
+
return start_line_prefix(s, l, valid, prefix_invalid, tab_invalid, false);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
static bool
|
|
1927
|
+
scan_normal(Scanner *s, TSLexer *l, const bool *valid, bool property_pending) {
|
|
1928
|
+
if (
|
|
1929
|
+
!property_pending &&
|
|
1930
|
+
(valid[KEY_END] || valid[INVALID_KEY_END] || valid[FLOW_NODE_END])
|
|
1931
|
+
)
|
|
1932
|
+
return scan_key_end(s, l, valid);
|
|
1933
|
+
if (
|
|
1934
|
+
s->key_done &&
|
|
1935
|
+
(valid[MISSING_VALUE_INDICATOR] || valid[INCOMPLETE_VALUE_INDICATOR])
|
|
1936
|
+
) {
|
|
1937
|
+
s->key_done = false;
|
|
1938
|
+
if (l->lookahead == ':') {
|
|
1939
|
+
step(l);
|
|
1940
|
+
if (colon_boundary(l, false))
|
|
1941
|
+
return emit_indicator(s, l, valid, VALUE_INDICATOR);
|
|
1942
|
+
}
|
|
1943
|
+
return emit_missing(
|
|
1944
|
+
l,
|
|
1945
|
+
valid,
|
|
1946
|
+
MISSING_VALUE_INDICATOR,
|
|
1947
|
+
INCOMPLETE_VALUE_INDICATOR
|
|
1948
|
+
);
|
|
1949
|
+
}
|
|
1950
|
+
if (s->line && !s->line_context && valid[LINE_CONTEXT])
|
|
1951
|
+
return scan_line_context(s, l, valid);
|
|
1952
|
+
if (s->line_context && !s->layout_only && !property_line_follows(s)) {
|
|
1953
|
+
s->properties_ready = false;
|
|
1954
|
+
property_pending = false;
|
|
1955
|
+
if (valid[PROPERTIES_END])
|
|
1956
|
+
return emit(l, valid, PROPERTIES_END);
|
|
1957
|
+
}
|
|
1958
|
+
static const enum Token restorations[] = {DEDENT, RESTORE_INDENT};
|
|
1959
|
+
if (
|
|
1960
|
+
!property_pending &&
|
|
1961
|
+
emit_closing(
|
|
1962
|
+
s,
|
|
1963
|
+
l,
|
|
1964
|
+
valid,
|
|
1965
|
+
restorations,
|
|
1966
|
+
sizeof(restorations) / sizeof(*restorations)
|
|
1967
|
+
)
|
|
1968
|
+
)
|
|
1969
|
+
return true;
|
|
1970
|
+
if (
|
|
1971
|
+
!property_pending &&
|
|
1972
|
+
s->line &&
|
|
1973
|
+
s->line_context &&
|
|
1974
|
+
!s->layout_only &&
|
|
1975
|
+
!s->flow
|
|
1976
|
+
) {
|
|
1977
|
+
if (valid[EMPTY_BLOCK_NODE] && !block_value_follows(s, l, valid))
|
|
1978
|
+
return emit(l, valid, EMPTY_BLOCK_NODE);
|
|
1979
|
+
if (
|
|
1980
|
+
valid[MAPPING_END] &&
|
|
1981
|
+
(s->line_indent <
|
|
1982
|
+
s->indent ||
|
|
1983
|
+
(s->line_indent ==
|
|
1984
|
+
s->indent &&
|
|
1985
|
+
s->line_head ==
|
|
1986
|
+
'-' &&
|
|
1987
|
+
!valid[VALUE_START]))
|
|
1988
|
+
)
|
|
1989
|
+
return emit(l, valid, MAPPING_END);
|
|
1990
|
+
if (
|
|
1991
|
+
valid[SEQUENCE_END] && (s->line_indent < s->indent || s->line_head != '-')
|
|
1992
|
+
)
|
|
1993
|
+
return emit(l, valid, SEQUENCE_END);
|
|
1994
|
+
}
|
|
1995
|
+
if (
|
|
1996
|
+
s->line &&
|
|
1997
|
+
!s->line_prefixed &&
|
|
1998
|
+
valid[LINE_PREFIX_START] &&
|
|
1999
|
+
(blank(l->lookahead) ||
|
|
2000
|
+
(s->flow &&
|
|
2001
|
+
s->indent >=
|
|
2002
|
+
0 &&
|
|
2003
|
+
!newline(l->lookahead) &&
|
|
2004
|
+
!l->eof(l) &&
|
|
2005
|
+
l->lookahead != '#'))
|
|
2006
|
+
)
|
|
2007
|
+
return begin_line_prefix(s, l, valid);
|
|
2008
|
+
if (newline(l->lookahead) && valid[LINE_BREAK]) {
|
|
2009
|
+
reset_line(s);
|
|
2010
|
+
return line_break(l, valid, LINE_BREAK);
|
|
2011
|
+
}
|
|
2012
|
+
if (blank(l->lookahead) && valid[SEPARATION])
|
|
2013
|
+
return scan_separation(l, valid);
|
|
2014
|
+
if (l->lookahead == '#' && valid[COMMENT_START])
|
|
2015
|
+
return start_comment(
|
|
2016
|
+
s,
|
|
2017
|
+
l,
|
|
2018
|
+
valid,
|
|
2019
|
+
NORMAL,
|
|
2020
|
+
!s->separated && l->get_column(l) != 0
|
|
2021
|
+
);
|
|
2022
|
+
if (valid[DIRECTIVE_INDICATOR]) {
|
|
2023
|
+
s->mode = DIRECTIVE_NAME_BODY;
|
|
2024
|
+
s->first = true;
|
|
2025
|
+
return take(l, valid, DIRECTIVE_INDICATOR);
|
|
2026
|
+
}
|
|
2027
|
+
if (
|
|
2028
|
+
l->lookahead ==
|
|
2029
|
+
'%' &&
|
|
2030
|
+
l->get_column(l) ==
|
|
2031
|
+
0 &&
|
|
2032
|
+
valid[RESERVED_DIRECTIVE_START]
|
|
2033
|
+
) {
|
|
2034
|
+
char name[5] = {0};
|
|
2035
|
+
unsigned length = 0;
|
|
2036
|
+
step(l);
|
|
2037
|
+
while (!directive_boundary(l)) {
|
|
2038
|
+
if (length < 4 && l->lookahead < 128)
|
|
2039
|
+
name[length] = (char)l->lookahead;
|
|
2040
|
+
if (length < 5)
|
|
2041
|
+
length++;
|
|
2042
|
+
step(l);
|
|
2043
|
+
}
|
|
2044
|
+
s->directive_kind = length == 4 && !strcmp(name, "YAML") ? YAML_DIRECTIVE
|
|
2045
|
+
: length == 3 && !strcmp(name, "TAG") ? TAG_DIRECTIVE
|
|
2046
|
+
: RESERVED_DIRECTIVE;
|
|
2047
|
+
return emit(
|
|
2048
|
+
l,
|
|
2049
|
+
valid,
|
|
2050
|
+
s->directive_kind == YAML_DIRECTIVE ? YAML_DIRECTIVE_START
|
|
2051
|
+
: s->directive_kind == TAG_DIRECTIVE ? TAG_DIRECTIVE_START
|
|
2052
|
+
: RESERVED_DIRECTIVE_START
|
|
2053
|
+
);
|
|
2054
|
+
}
|
|
2055
|
+
if (
|
|
2056
|
+
!s->document_started &&
|
|
2057
|
+
(valid[MISSING_DOCUMENT_START] || valid[INCOMPLETE_DOCUMENT_START])
|
|
2058
|
+
) {
|
|
2059
|
+
s->document_started = true;
|
|
2060
|
+
s->explicit_document_required = false;
|
|
2061
|
+
return emit_missing(
|
|
2062
|
+
l,
|
|
2063
|
+
valid,
|
|
2064
|
+
MISSING_DOCUMENT_START,
|
|
2065
|
+
INCOMPLETE_DOCUMENT_START
|
|
2066
|
+
);
|
|
2067
|
+
}
|
|
2068
|
+
return scan_properties(s, l, valid, property_pending);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
static void begin_property(Scanner *s) {
|
|
2072
|
+
s->duplicate_pending = false;
|
|
2073
|
+
s->property_separation_notified = false;
|
|
2074
|
+
}
|
|
2075
|
+
static bool scan_properties(
|
|
2076
|
+
Scanner *s,
|
|
2077
|
+
TSLexer *l,
|
|
2078
|
+
const bool *valid,
|
|
2079
|
+
bool property_pending
|
|
2080
|
+
) {
|
|
2081
|
+
/* Properties at the start of a line end the node's own properties when
|
|
2082
|
+
* they belong to the first key of a block mapping that is its content.
|
|
2083
|
+
* The line context records whether the leading property or alias of the
|
|
2084
|
+
* line is such a key. */
|
|
2085
|
+
if (
|
|
2086
|
+
valid[PROPERTIES_END] &&
|
|
2087
|
+
((l->lookahead != '&' && l->lookahead != '!') ||
|
|
2088
|
+
(s->property_flags &&
|
|
2089
|
+
!s->flow &&
|
|
2090
|
+
s->line &&
|
|
2091
|
+
(s->line_indent <= s->indent || s->line_mapping_key)))
|
|
2092
|
+
) {
|
|
2093
|
+
s->properties_ready = true;
|
|
2094
|
+
s->property_separation_notified = false;
|
|
2095
|
+
if (l->lookahead == ':') {
|
|
2096
|
+
step(l);
|
|
2097
|
+
if (!colon_boundary(l, s->flow))
|
|
2098
|
+
s->property_flags |= PROPERTY_COLON_CONTENT;
|
|
2099
|
+
}
|
|
2100
|
+
return emit(l, valid, PROPERTIES_END);
|
|
2101
|
+
}
|
|
2102
|
+
if (property_pending) {
|
|
2103
|
+
bool content = !l->eof(l) && !(s->flow && flow_entry_end(l->lookahead));
|
|
2104
|
+
if (
|
|
2105
|
+
l->lookahead ==
|
|
2106
|
+
':' &&
|
|
2107
|
+
!(s->property_flags & PROPERTY_COLON_CONTENT) &&
|
|
2108
|
+
!(s->line && !s->flow && valid[BLOCK_PROPERTY_CONTENT_START])
|
|
2109
|
+
)
|
|
2110
|
+
content = false;
|
|
2111
|
+
if (!property_line_follows(s))
|
|
2112
|
+
content = false;
|
|
2113
|
+
if (!content) {
|
|
2114
|
+
s->properties_ready = false;
|
|
2115
|
+
return scan(s, l, valid);
|
|
2116
|
+
}
|
|
2117
|
+
if (
|
|
2118
|
+
!s->separated &&
|
|
2119
|
+
!s->property_separation_notified &&
|
|
2120
|
+
valid[MISSING_SEPARATION]
|
|
2121
|
+
) {
|
|
2122
|
+
s->property_separation_notified = true;
|
|
2123
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
2124
|
+
}
|
|
2125
|
+
s->properties_ready = false;
|
|
2126
|
+
return emit(l, valid, property_content_start(s, l, valid));
|
|
2127
|
+
}
|
|
2128
|
+
if (
|
|
2129
|
+
s->property_flags &&
|
|
2130
|
+
!s->separated &&
|
|
2131
|
+
!s->property_separation_notified &&
|
|
2132
|
+
valid[MISSING_SEPARATION] &&
|
|
2133
|
+
((l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
|
|
2134
|
+
(l->lookahead == '!' && valid[SHORTHAND_TAG_START]))
|
|
2135
|
+
) {
|
|
2136
|
+
s->property_separation_notified = true;
|
|
2137
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
2138
|
+
}
|
|
2139
|
+
if (
|
|
2140
|
+
(l->lookahead == '&' && valid[ANCHOR_INDICATOR]) ||
|
|
2141
|
+
(l->lookahead == '*' && valid[ALIAS_INDICATOR])
|
|
2142
|
+
) {
|
|
2143
|
+
bool anchor = l->lookahead == '&';
|
|
2144
|
+
if (
|
|
2145
|
+
anchor &&
|
|
2146
|
+
(s->property_flags & PROPERTY_ANCHOR) &&
|
|
2147
|
+
!s->duplicate_pending &&
|
|
2148
|
+
valid[DUPLICATE_ANCHOR_START]
|
|
2149
|
+
) {
|
|
2150
|
+
s->duplicate_pending = true;
|
|
2151
|
+
return emit(l, valid, DUPLICATE_ANCHOR_START);
|
|
2152
|
+
}
|
|
2153
|
+
begin_property(s);
|
|
2154
|
+
s->mode = anchor ? ANCHOR_BODY : ALIAS_BODY;
|
|
2155
|
+
s->first = true;
|
|
2156
|
+
s->json = false;
|
|
2157
|
+
return take(l, valid, anchor ? ANCHOR_INDICATOR : ALIAS_INDICATOR);
|
|
2158
|
+
}
|
|
2159
|
+
if (
|
|
2160
|
+
l->lookahead ==
|
|
2161
|
+
'!' &&
|
|
2162
|
+
(valid[VERBATIM_TAG_START] ||
|
|
2163
|
+
valid[SHORTHAND_TAG_START] ||
|
|
2164
|
+
valid[NON_SPECIFIC_TAG])
|
|
2165
|
+
) {
|
|
2166
|
+
if (
|
|
2167
|
+
(s->property_flags & PROPERTY_TAG) &&
|
|
2168
|
+
!s->duplicate_pending &&
|
|
2169
|
+
valid[DUPLICATE_TAG_START]
|
|
2170
|
+
) {
|
|
2171
|
+
s->duplicate_pending = true;
|
|
2172
|
+
return emit(l, valid, DUPLICATE_TAG_START);
|
|
2173
|
+
}
|
|
2174
|
+
step(l);
|
|
2175
|
+
if (l->lookahead == '<')
|
|
2176
|
+
return emit(l, valid, VERBATIM_TAG_START);
|
|
2177
|
+
if (!name_boundary(l))
|
|
2178
|
+
return emit(l, valid, SHORTHAND_TAG_START);
|
|
2179
|
+
l->mark_end(l);
|
|
2180
|
+
begin_property(s);
|
|
2181
|
+
s->property_flags |= PROPERTY_TAG;
|
|
2182
|
+
return emit(l, valid, NON_SPECIFIC_TAG);
|
|
2183
|
+
}
|
|
2184
|
+
if (valid[VERBATIM_TAG_OPEN]) {
|
|
2185
|
+
step(l);
|
|
2186
|
+
step(l);
|
|
2187
|
+
l->mark_end(l);
|
|
2188
|
+
begin_property(s);
|
|
2189
|
+
s->mode = URI_BEGIN;
|
|
2190
|
+
return emit(l, valid, VERBATIM_TAG_OPEN);
|
|
2191
|
+
}
|
|
2192
|
+
if (valid[TAG_HANDLE_START]) {
|
|
2193
|
+
s->directive_handle = false;
|
|
2194
|
+
step(l);
|
|
2195
|
+
s->handle_form = PRIMARY_HANDLE;
|
|
2196
|
+
if (l->lookahead == '!')
|
|
2197
|
+
s->handle_form = SECONDARY_HANDLE;
|
|
2198
|
+
else {
|
|
2199
|
+
while (!name_boundary(l)) {
|
|
2200
|
+
if (l->lookahead == '!') {
|
|
2201
|
+
s->handle_form = NAMED_HANDLE;
|
|
2202
|
+
break;
|
|
2203
|
+
}
|
|
2204
|
+
step(l);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
s->mode = HANDLE_SELECT;
|
|
2208
|
+
begin_property(s);
|
|
2209
|
+
return emit(l, valid, TAG_HANDLE_START);
|
|
2210
|
+
}
|
|
2211
|
+
return scan_content(s, l, valid);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
static bool scan_content(Scanner *s, TSLexer *l, const bool *valid) {
|
|
2215
|
+
if (
|
|
2216
|
+
l->lookahead == 0xfeff && l->get_column(l) == 0 && valid[BYTE_ORDER_MARK]
|
|
2217
|
+
) {
|
|
2218
|
+
step(l);
|
|
2219
|
+
/* The line starts after the BOM; its layout is measured from there. */
|
|
2220
|
+
cursor_start_line(l);
|
|
2221
|
+
reset_line(s);
|
|
2222
|
+
return finish(l, valid, BYTE_ORDER_MARK);
|
|
2223
|
+
}
|
|
2224
|
+
if (scan_invalid_character(l, valid))
|
|
2225
|
+
return true;
|
|
2226
|
+
bool end = l->eof(l);
|
|
2227
|
+
if (s->after_document_end && !end) {
|
|
2228
|
+
do {
|
|
2229
|
+
step(l);
|
|
2230
|
+
} while (
|
|
2231
|
+
!l->eof(l) && !space(l->lookahead) && !invalid_unquoted(l->lookahead)
|
|
2232
|
+
);
|
|
2233
|
+
return finish(l, valid, UNEXPECTED_DOCUMENT_END_CONTENT);
|
|
2234
|
+
}
|
|
2235
|
+
int64_t column = s->line ? s->line_indent : l->get_column(l);
|
|
2236
|
+
if (
|
|
2237
|
+
valid[EXPLICIT_VALUE_START] &&
|
|
2238
|
+
l->lookahead ==
|
|
2239
|
+
':' &&
|
|
2240
|
+
s->line_head ==
|
|
2241
|
+
':' &&
|
|
2242
|
+
s->line &&
|
|
2243
|
+
column == s->indent
|
|
2244
|
+
)
|
|
2245
|
+
return emit(l, valid, EXPLICIT_VALUE_START);
|
|
2246
|
+
if (
|
|
2247
|
+
valid[VALUE_START] || valid[SEQUENCE_VALUE_START] || valid[EMPTY_BLOCK_NODE]
|
|
2248
|
+
) {
|
|
2249
|
+
if (block_value_follows(s, l, valid)) {
|
|
2250
|
+
if (!s->line && valid[INVALID_COMPACT_START]) {
|
|
2251
|
+
enum Token kind = classify_block_node(l);
|
|
2252
|
+
if (block_collection(kind))
|
|
2253
|
+
return emit(l, valid, INVALID_COMPACT_START);
|
|
2254
|
+
}
|
|
2255
|
+
s->block_out = valid[VALUE_START];
|
|
2256
|
+
return emit(l, valid, s->block_out ? VALUE_START : SEQUENCE_VALUE_START);
|
|
2257
|
+
}
|
|
2258
|
+
return emit(l, valid, EMPTY_BLOCK_NODE);
|
|
2259
|
+
}
|
|
2260
|
+
if (valid[DOCUMENT_CLOSE] && end) {
|
|
2261
|
+
close_document(s);
|
|
2262
|
+
return emit(l, valid, DOCUMENT_CLOSE);
|
|
2263
|
+
}
|
|
2264
|
+
if (valid[DOCUMENT_OPEN] && !end && !s->document) {
|
|
2265
|
+
open_document(s, !s->explicit_document_required);
|
|
2266
|
+
return emit(l, valid, DOCUMENT_OPEN);
|
|
2267
|
+
}
|
|
2268
|
+
if (valid[UNEXPECTED_CONTENT_START] && s->document_content && !end) {
|
|
2269
|
+
s->document_content = false;
|
|
2270
|
+
return emit(l, valid, UNEXPECTED_CONTENT_START);
|
|
2271
|
+
}
|
|
2272
|
+
if (
|
|
2273
|
+
!s->flow && !s->line && !valid[VALUE_START] && !valid[SEQUENCE_VALUE_START]
|
|
2274
|
+
) {
|
|
2275
|
+
if (valid[MAPPING_END])
|
|
2276
|
+
return emit(l, valid, MAPPING_END);
|
|
2277
|
+
if (valid[SEQUENCE_END])
|
|
2278
|
+
return emit(l, valid, SEQUENCE_END);
|
|
2279
|
+
}
|
|
2280
|
+
if (end) {
|
|
2281
|
+
static const enum Token endings[] = {
|
|
2282
|
+
MAPPING_END,
|
|
2283
|
+
SEQUENCE_END,
|
|
2284
|
+
INCOMPLETE_FLOW_SEQUENCE_CLOSE,
|
|
2285
|
+
INCOMPLETE_FLOW_MAPPING_CLOSE,
|
|
2286
|
+
END_OF_FILE
|
|
2287
|
+
};
|
|
2288
|
+
return emit_closing(
|
|
2289
|
+
s,
|
|
2290
|
+
l,
|
|
2291
|
+
valid,
|
|
2292
|
+
endings,
|
|
2293
|
+
sizeof(endings) / sizeof(*endings)
|
|
2294
|
+
);
|
|
2295
|
+
}
|
|
2296
|
+
if (valid[MAPPING_END] && column < s->indent)
|
|
2297
|
+
return emit(l, valid, MAPPING_END);
|
|
2298
|
+
if (
|
|
2299
|
+
valid[SEQUENCE_END] &&
|
|
2300
|
+
(column < s->indent || (s->line && l->lookahead != '-'))
|
|
2301
|
+
)
|
|
2302
|
+
return emit(l, valid, SEQUENCE_END);
|
|
2303
|
+
return scan_entry(s, l, valid, column);
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
static bool
|
|
2307
|
+
scan_entry(Scanner *s, TSLexer *l, const bool *valid, int64_t column) {
|
|
2308
|
+
if (
|
|
2309
|
+
l->lookahead ==
|
|
2310
|
+
',' &&
|
|
2311
|
+
!valid[FLOW_SEPARATOR] &&
|
|
2312
|
+
valid[UNEXPECTED_FLOW_SEPARATOR]
|
|
2313
|
+
)
|
|
2314
|
+
return take(l, valid, UNEXPECTED_FLOW_SEPARATOR);
|
|
2315
|
+
if (valid[FLOW_MAP_PAIR_START] && !flow_entry_end(l->lookahead)) {
|
|
2316
|
+
s->json = false;
|
|
2317
|
+
return emit(l, valid, FLOW_MAP_PAIR_START);
|
|
2318
|
+
}
|
|
2319
|
+
if (valid[IMPLICIT_KEY_START] && !(s->flow && flow_entry_end(l->lookahead))) {
|
|
2320
|
+
int32_t first = l->lookahead;
|
|
2321
|
+
bool indicator = false;
|
|
2322
|
+
if (l->lookahead == '?' || l->lookahead == ':') {
|
|
2323
|
+
step(l);
|
|
2324
|
+
indicator = colon_boundary(l, first == ':' && s->flow);
|
|
2325
|
+
}
|
|
2326
|
+
if (indicator) {
|
|
2327
|
+
if (valid[FLOW_SEQ_PAIR_START]) {
|
|
2328
|
+
s->json = false;
|
|
2329
|
+
return emit(l, valid, FLOW_SEQ_PAIR_START);
|
|
2330
|
+
}
|
|
2331
|
+
return emit_indicator(
|
|
2332
|
+
s,
|
|
2333
|
+
l,
|
|
2334
|
+
valid,
|
|
2335
|
+
first == '?' ? KEY_INDICATOR : VALUE_INDICATOR
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
s->implicit_keys[0] |= 1;
|
|
2339
|
+
s->block_out = false;
|
|
2340
|
+
return emit(l, valid, IMPLICIT_KEY_START);
|
|
2341
|
+
}
|
|
2342
|
+
if (l->lookahead == '?' && valid[KEY_INDICATOR]) {
|
|
2343
|
+
step(l);
|
|
2344
|
+
if (space(l->lookahead) || l->eof(l)) {
|
|
2345
|
+
return emit_indicator(s, l, valid, KEY_INDICATOR);
|
|
2346
|
+
}
|
|
2347
|
+
return start_plain(s, l, valid);
|
|
2348
|
+
}
|
|
2349
|
+
if (l->lookahead == ':' && valid[VALUE_INDICATOR]) {
|
|
2350
|
+
bool adjacent = s->flow && s->json;
|
|
2351
|
+
step(l);
|
|
2352
|
+
if (adjacent || colon_boundary(l, s->flow)) {
|
|
2353
|
+
s->value_separation =
|
|
2354
|
+
s->flow && !adjacent && (l->lookahead == '[' || l->lookahead == '{');
|
|
2355
|
+
s->json = false;
|
|
2356
|
+
return emit_indicator(s, l, valid, VALUE_INDICATOR);
|
|
2357
|
+
}
|
|
2358
|
+
return start_plain(s, l, valid) || emit(l, valid, MISSING_FLOW_SEPARATOR);
|
|
2359
|
+
}
|
|
2360
|
+
if (l->lookahead == '-' && valid[SEQUENCE_INDICATOR]) {
|
|
2361
|
+
step(l);
|
|
2362
|
+
return emit_indicator(s, l, valid, SEQUENCE_INDICATOR);
|
|
2363
|
+
}
|
|
2364
|
+
if (s->value_separation && valid[MISSING_SEPARATION]) {
|
|
2365
|
+
s->value_separation = false;
|
|
2366
|
+
return emit(l, valid, MISSING_SEPARATION);
|
|
2367
|
+
}
|
|
2368
|
+
if (l->lookahead == ',' && valid[FLOW_SEPARATOR])
|
|
2369
|
+
return take(l, valid, FLOW_SEPARATOR);
|
|
2370
|
+
if (l->lookahead == ']' && valid[FLOW_SEQUENCE_CLOSE])
|
|
2371
|
+
return close_flow(s, l, valid, FLOW_SEQUENCE_CLOSE);
|
|
2372
|
+
if (l->lookahead == '}' && valid[FLOW_MAPPING_CLOSE])
|
|
2373
|
+
return close_flow(s, l, valid, FLOW_MAPPING_CLOSE);
|
|
2374
|
+
if (l->lookahead == ']' && valid[MISSING_FLOW_MAPPING_CLOSE])
|
|
2375
|
+
return close_flow(s, l, valid, MISSING_FLOW_MAPPING_CLOSE);
|
|
2376
|
+
if (l->lookahead == '}' && valid[MISSING_FLOW_SEQUENCE_CLOSE])
|
|
2377
|
+
return close_flow(s, l, valid, MISSING_FLOW_SEQUENCE_CLOSE);
|
|
2378
|
+
if (
|
|
2379
|
+
valid[MISSING_FLOW_SEPARATOR] &&
|
|
2380
|
+
!valid[PLAIN_START] &&
|
|
2381
|
+
!valid[SINGLE_START] &&
|
|
2382
|
+
!valid[DOUBLE_START] &&
|
|
2383
|
+
!valid[FLOW_SEQUENCE_START] &&
|
|
2384
|
+
!valid[FLOW_MAPPING_START] &&
|
|
2385
|
+
!flow_entry_end(l->lookahead)
|
|
2386
|
+
)
|
|
2387
|
+
return emit(l, valid, MISSING_FLOW_SEPARATOR);
|
|
2388
|
+
if (
|
|
2389
|
+
valid[PAIR_START] ||
|
|
2390
|
+
valid[ENTRY_START] ||
|
|
2391
|
+
valid[MAPPING_START] ||
|
|
2392
|
+
valid[SEQUENCE_START] ||
|
|
2393
|
+
valid[PLAIN_START] ||
|
|
2394
|
+
valid[INDENT] ||
|
|
2395
|
+
valid[OUTDENT] ||
|
|
2396
|
+
valid[SINGLE_START] ||
|
|
2397
|
+
valid[DOUBLE_START] ||
|
|
2398
|
+
valid[FLOW_SEQUENCE_START] ||
|
|
2399
|
+
valid[FLOW_MAPPING_START] ||
|
|
2400
|
+
valid[LITERAL_START] ||
|
|
2401
|
+
valid[FOLDED_START] ||
|
|
2402
|
+
valid[PROPERTIES_START] ||
|
|
2403
|
+
valid[ALIAS_START]
|
|
2404
|
+
) {
|
|
2405
|
+
return scan_node_start(s, l, valid, column);
|
|
2406
|
+
}
|
|
2407
|
+
return scan_node_open(s, l, valid);
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
static bool scan(Scanner *s, TSLexer *l, const bool *valid) {
|
|
2411
|
+
if (valid[ERROR_SENTINEL])
|
|
2412
|
+
return false;
|
|
2413
|
+
l->mark_end(l);
|
|
2414
|
+
bool boundary_mode = s->mode ==
|
|
2415
|
+
NORMAL ||
|
|
2416
|
+
s->mode ==
|
|
2417
|
+
PLAIN ||
|
|
2418
|
+
s->mode ==
|
|
2419
|
+
SINGLE ||
|
|
2420
|
+
s->mode ==
|
|
2421
|
+
DOUBLE ||
|
|
2422
|
+
s->mode == BLOCK_BODY;
|
|
2423
|
+
if (
|
|
2424
|
+
boundary_mode &&
|
|
2425
|
+
!s->boundary_checked &&
|
|
2426
|
+
l->get_column(l) ==
|
|
2427
|
+
0 &&
|
|
2428
|
+
valid[BOUNDARY_CHECK]
|
|
2429
|
+
) {
|
|
2430
|
+
int32_t first = l->lookahead;
|
|
2431
|
+
enum Boundary boundary = line_boundary(s, l);
|
|
2432
|
+
if (boundary || first == '-' || first == '.') {
|
|
2433
|
+
s->boundary = (uint8_t)boundary;
|
|
2434
|
+
s->boundary_checked = true;
|
|
2435
|
+
return emit(l, valid, BOUNDARY_CHECK);
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
if (s->mode == NORMAL && s->boundary && valid[PROPERTIES_END]) {
|
|
2439
|
+
s->properties_ready = true;
|
|
2440
|
+
return emit(l, valid, PROPERTIES_END);
|
|
2441
|
+
}
|
|
2442
|
+
if (s->boundary)
|
|
2443
|
+
s->properties_ready = false;
|
|
2444
|
+
bool property_pending = s->properties_ready &&
|
|
2445
|
+
(valid[PROPERTY_CONTENT_START] || valid[BLOCK_PROPERTY_CONTENT_START]);
|
|
2446
|
+
if (
|
|
2447
|
+
s->mode ==
|
|
2448
|
+
NORMAL &&
|
|
2449
|
+
s->boundary ==
|
|
2450
|
+
DOCUMENT_END_LINE &&
|
|
2451
|
+
valid[MISSING_DOCUMENT_START]
|
|
2452
|
+
) {
|
|
2453
|
+
s->document_started = true;
|
|
2454
|
+
return emit(l, valid, MISSING_DOCUMENT_START);
|
|
2455
|
+
}
|
|
2456
|
+
if (s->mode == NORMAL && !property_pending && valid[DOCUMENT_CONTENT_END]) {
|
|
2457
|
+
s->document_content = true;
|
|
2458
|
+
return emit(l, valid, DOCUMENT_CONTENT_END);
|
|
2459
|
+
}
|
|
2460
|
+
if (
|
|
2461
|
+
boundary_mode &&
|
|
2462
|
+
s->boundary &&
|
|
2463
|
+
!(s->mode ==
|
|
2464
|
+
NORMAL &&
|
|
2465
|
+
(valid[KEY_END] ||
|
|
2466
|
+
valid[INVALID_KEY_END] ||
|
|
2467
|
+
valid[FLOW_NODE_END] ||
|
|
2468
|
+
(s->key_done && valid[MISSING_VALUE_INDICATOR])))
|
|
2469
|
+
) {
|
|
2470
|
+
if (scan_boundary(s, l, valid))
|
|
2471
|
+
return true;
|
|
2472
|
+
if (s->boundary != DIRECTIVE_LINE && s->boundary != STREAM_BOM)
|
|
2473
|
+
return false;
|
|
2474
|
+
}
|
|
2475
|
+
switch ((enum Mode)s->mode) {
|
|
2476
|
+
case NORMAL:
|
|
2477
|
+
break;
|
|
2478
|
+
case PLAIN:
|
|
2479
|
+
return scan_plain(s, l, valid);
|
|
2480
|
+
case SINGLE:
|
|
2481
|
+
case DOUBLE:
|
|
2482
|
+
return scan_quote(s, l, valid);
|
|
2483
|
+
case COMMENT_BEGIN:
|
|
2484
|
+
case COMMENT:
|
|
2485
|
+
return scan_comment(s, l, valid);
|
|
2486
|
+
case COMPACT_PREFIX:
|
|
2487
|
+
case PREFIX:
|
|
2488
|
+
return scan_prefix(s, l, valid);
|
|
2489
|
+
case BLOCK_HEADER:
|
|
2490
|
+
case BLOCK_HEADER_DONE:
|
|
2491
|
+
return scan_block_header(s, l, valid);
|
|
2492
|
+
case BLOCK_DETECT:
|
|
2493
|
+
return detect_block_indent(s, l, valid);
|
|
2494
|
+
case BLOCK_BODY:
|
|
2495
|
+
return scan_block_body(s, l, valid);
|
|
2496
|
+
case BLOCK_LINE:
|
|
2497
|
+
case BLOCK_LINE_DONE:
|
|
2498
|
+
return scan_block_line(s, l, valid);
|
|
2499
|
+
case ANCHOR_BODY:
|
|
2500
|
+
case ALIAS_BODY:
|
|
2501
|
+
return scan_name(s, l, valid);
|
|
2502
|
+
case HANDLE_SELECT:
|
|
2503
|
+
case HANDLE_BODY:
|
|
2504
|
+
return scan_handle(s, l, valid);
|
|
2505
|
+
case URI_BEGIN:
|
|
2506
|
+
case VERBATIM_CLOSE:
|
|
2507
|
+
case SUFFIX_BEGIN:
|
|
2508
|
+
return scan_tag_boundary(s, l, valid);
|
|
2509
|
+
case URI_BODY:
|
|
2510
|
+
case SUFFIX_BODY:
|
|
2511
|
+
case PREFIX_BODY:
|
|
2512
|
+
return scan_uri(s, l, valid);
|
|
2513
|
+
case DIRECTIVE_NAME_BODY:
|
|
2514
|
+
case DIRECTIVE_VERSION:
|
|
2515
|
+
case DIRECTIVE_HANDLE:
|
|
2516
|
+
case DIRECTIVE_PREFIX:
|
|
2517
|
+
case DIRECTIVE_PARAMETERS:
|
|
2518
|
+
return scan_directive(s, l, valid);
|
|
2519
|
+
default:
|
|
2520
|
+
return false;
|
|
2521
|
+
}
|
|
2522
|
+
return scan_normal(s, l, valid, property_pending);
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
static bool layout_token(TSSymbol token) {
|
|
2526
|
+
switch (token) {
|
|
2527
|
+
case LINE_BREAK:
|
|
2528
|
+
case SEPARATION:
|
|
2529
|
+
case COMMENT_START:
|
|
2530
|
+
case COMMENT_MARKER:
|
|
2531
|
+
case COMMENT_TEXT:
|
|
2532
|
+
case COMMENT_END:
|
|
2533
|
+
case LINE_PREFIX_START:
|
|
2534
|
+
case LINE_PREFIX_END:
|
|
2535
|
+
case INDENTATION:
|
|
2536
|
+
case INVALID_INDENTATION:
|
|
2537
|
+
case BYTE_ORDER_MARK:
|
|
2538
|
+
case LINE_CONTEXT:
|
|
2539
|
+
case BOUNDARY_CHECK:
|
|
2540
|
+
return true;
|
|
2541
|
+
default:
|
|
2542
|
+
return false;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
static void reset_scanner(Scanner *s) {
|
|
2546
|
+
*s = (Scanner){
|
|
2547
|
+
.indent = -1,
|
|
2548
|
+
.block_indent = -1,
|
|
2549
|
+
.line = true,
|
|
2550
|
+
.separated = true
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
static void write_integer(char **cursor, uint64_t value, unsigned width) {
|
|
2554
|
+
for (unsigned i = 0; i < width; i++) {
|
|
2555
|
+
*(*cursor)++ = (char)value;
|
|
2556
|
+
value >>= 8;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
static uint64_t read_integer(const char **cursor, unsigned width) {
|
|
2560
|
+
uint64_t value = 0;
|
|
2561
|
+
for (unsigned i = 0; i < width; i++)
|
|
2562
|
+
value |= (uint64_t)(uint8_t)*(*cursor)++ << (i * 8);
|
|
2563
|
+
return value;
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
void *tree_sitter_yaml_external_scanner_create(void) {
|
|
2567
|
+
Scanner *s = ts_calloc(1, sizeof(Scanner));
|
|
2568
|
+
reset_scanner(s);
|
|
2569
|
+
return s;
|
|
2570
|
+
}
|
|
2571
|
+
void tree_sitter_yaml_external_scanner_destroy(void *payload) {
|
|
2572
|
+
ts_free(payload);
|
|
2573
|
+
}
|
|
2574
|
+
unsigned
|
|
2575
|
+
tree_sitter_yaml_external_scanner_serialize(void *payload, char *buffer) {
|
|
2576
|
+
const Scanner *s = payload;
|
|
2577
|
+
char *cursor = buffer;
|
|
2578
|
+
#define WRITE_FIELD(type, name, width, bias) \
|
|
2579
|
+
write_integer(&cursor, (uint64_t)(s->name + bias), width);
|
|
2580
|
+
SCANNER_FIELDS(WRITE_FIELD)
|
|
2581
|
+
#undef WRITE_FIELD
|
|
2582
|
+
unsigned key_bytes = SCANNER_KEY_BYTES;
|
|
2583
|
+
while (
|
|
2584
|
+
key_bytes &&
|
|
2585
|
+
!(uint8_t)(s->implicit_keys[(key_bytes - 1) / 8] >>
|
|
2586
|
+
(((key_bytes - 1) % 8) * 8))
|
|
2587
|
+
)
|
|
2588
|
+
key_bytes--;
|
|
2589
|
+
for (unsigned i = 0; i < key_bytes; i++)
|
|
2590
|
+
*cursor++ = (char)(s->implicit_keys[i / 8] >> ((i % 8) * 8));
|
|
2591
|
+
return (unsigned)(cursor - buffer);
|
|
2592
|
+
}
|
|
2593
|
+
void tree_sitter_yaml_external_scanner_deserialize(
|
|
2594
|
+
void *payload,
|
|
2595
|
+
const char *buffer,
|
|
2596
|
+
unsigned length
|
|
2597
|
+
) {
|
|
2598
|
+
Scanner *s = payload;
|
|
2599
|
+
reset_scanner(s);
|
|
2600
|
+
if (
|
|
2601
|
+
length <
|
|
2602
|
+
SCANNER_STATE_BYTES ||
|
|
2603
|
+
length >
|
|
2604
|
+
SCANNER_STATE_BYTES +
|
|
2605
|
+
SCANNER_KEY_BYTES
|
|
2606
|
+
)
|
|
2607
|
+
return;
|
|
2608
|
+
const char *cursor = buffer;
|
|
2609
|
+
#define READ_FIELD(type, name, width, bias) \
|
|
2610
|
+
s->name = (type)read_integer(&cursor, width) - bias;
|
|
2611
|
+
SCANNER_FIELDS(READ_FIELD)
|
|
2612
|
+
#undef READ_FIELD
|
|
2613
|
+
for (unsigned i = 0; i < length - SCANNER_STATE_BYTES; i++)
|
|
2614
|
+
s->implicit_keys[i / 8] |= (uint64_t)(uint8_t)*cursor++ << ((i % 8) * 8);
|
|
2615
|
+
}
|
|
2616
|
+
#undef SCANNER_FIELDS
|
|
2617
|
+
|
|
2618
|
+
bool tree_sitter_yaml_external_scanner_scan(
|
|
2619
|
+
void *payload,
|
|
2620
|
+
TSLexer *lexer,
|
|
2621
|
+
const bool *valid
|
|
2622
|
+
) {
|
|
2623
|
+
Scanner next = *(Scanner *)payload;
|
|
2624
|
+
Cursor cursor = {0};
|
|
2625
|
+
cursor.source = lexer;
|
|
2626
|
+
cursor.column = next.column;
|
|
2627
|
+
cursor.marked_column = next.column;
|
|
2628
|
+
cursor.separated = next.separated;
|
|
2629
|
+
cursor.marked_separation = next.separated;
|
|
2630
|
+
cursor.lexer.lookahead = lexer->lookahead;
|
|
2631
|
+
cursor.lexer.advance = cursor_advance;
|
|
2632
|
+
cursor.lexer.mark_end = cursor_mark;
|
|
2633
|
+
cursor.lexer.get_column = cursor_column;
|
|
2634
|
+
cursor.lexer.eof = cursor_eof;
|
|
2635
|
+
if (!scan(&next, &cursor.lexer, valid))
|
|
2636
|
+
return false;
|
|
2637
|
+
/* Edits inside the final lookahead codepoint must invalidate this token. */
|
|
2638
|
+
if (!cursor.lexer.eof(&cursor.lexer))
|
|
2639
|
+
step(&cursor.lexer);
|
|
2640
|
+
if (next.flow && !layout_token(cursor.lexer.result_symbol))
|
|
2641
|
+
skip_layout(&cursor.lexer);
|
|
2642
|
+
next.column = cursor.marked_column;
|
|
2643
|
+
next.separated = cursor.marked_separation;
|
|
2644
|
+
if (cursor.marked_characters) {
|
|
2645
|
+
next.block_kind = 0;
|
|
2646
|
+
advance_keys(&next, cursor.marked_characters, cursor.marked_broken);
|
|
2647
|
+
next.boundary = 0;
|
|
2648
|
+
next.boundary_checked = false;
|
|
2649
|
+
if (!layout_token(cursor.lexer.result_symbol))
|
|
2650
|
+
next.line = false;
|
|
2651
|
+
}
|
|
2652
|
+
lexer->result_symbol = cursor.lexer.result_symbol;
|
|
2653
|
+
*(Scanner *)payload = next;
|
|
2654
|
+
return true;
|
|
2655
|
+
}
|