tree-sitter-glsl-spec 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/binding.gyp +21 -0
- package/bindings/node/binding.cc +20 -0
- package/bindings/node/binding_test.js +11 -0
- package/bindings/node/index.d.ts +91 -0
- package/bindings/node/index.js +39 -0
- package/grammar.js +2932 -0
- package/package.json +71 -0
- package/queries/constructor-heuristics.scm +7 -0
- package/queries/highlights.in +112 -0
- package/queries/highlights.scm +486 -0
- package/queries/injections.scm +5 -0
- package/queries/locals.scm +34 -0
- package/queries/tags.scm +50 -0
- package/queries/version-tags.scm +150 -0
- package/src/grammar.json +7839 -0
- package/src/node-types.json +5807 -0
- package/src/parser.c +237532 -0
- package/src/tree_sitter/alloc.h +54 -0
- package/src/tree_sitter/array.h +330 -0
- package/src/tree_sitter/parser.h +286 -0
- package/src/tree_sitter/runtime.h +112 -0
package/grammar.js
ADDED
|
@@ -0,0 +1,2932 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file GLSL grammar for tree-sitter
|
|
3
|
+
* @license MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// @ts-check
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
INTERPOLATION_QUALIFIER_KEYWORDS,
|
|
10
|
+
PRECISION_QUALIFIER_KEYWORDS,
|
|
11
|
+
STORAGE_QUALIFIER_KEYWORDS,
|
|
12
|
+
TYPE_KEYWORDS,
|
|
13
|
+
flattenKeywordGroups,
|
|
14
|
+
} from './keywords.js';
|
|
15
|
+
|
|
16
|
+
import EXTENSIONS from './extensions.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Collect all `grammarExtension` rule builders from the extension registry
|
|
20
|
+
* into a single flat object suitable for `Object.assign()` into rules.
|
|
21
|
+
*
|
|
22
|
+
* @returns {RuleBuilders<string, never>}
|
|
23
|
+
*/
|
|
24
|
+
function collectExtensionRules() {
|
|
25
|
+
/** @type {RuleBuilders<string, never>} */
|
|
26
|
+
const rules = {};
|
|
27
|
+
for (const ext of Object.values(EXTENSIONS)) {
|
|
28
|
+
if (ext.grammarExtension) {
|
|
29
|
+
Object.assign(rules, ext.grammarExtension);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return rules;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const EXTENSION_RULES = collectExtensionRules();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Conditionally include an extension rule in a `choice()`.
|
|
39
|
+
* Returns `[$.rule_name]` if the extension defines it, `[]` otherwise.
|
|
40
|
+
*
|
|
41
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
42
|
+
* @param {string} ruleName Name of the extension-defined rule.
|
|
43
|
+
* @returns {RuleOrLiteral[]}
|
|
44
|
+
*/
|
|
45
|
+
function extRule($, ruleName) {
|
|
46
|
+
return ruleName in EXTENSION_RULES ? [$[ruleName]] : [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Parser configuration flags.
|
|
51
|
+
*
|
|
52
|
+
* The first three extend the core GLSL grammar to handle real-world
|
|
53
|
+
* shader code (preprocessor structure, unexpanded macros, shared
|
|
54
|
+
* C++/GLSL headers). `ESSL` restricts it to the OpenGL ES subset.
|
|
55
|
+
*
|
|
56
|
+
* Document any rule drift caused by these flags at the affected rules.
|
|
57
|
+
*/
|
|
58
|
+
const OPT = {
|
|
59
|
+
/**
|
|
60
|
+
* Parse preprocessor directives (`#define`, `#if`, `#pragma`, etc.)
|
|
61
|
+
* into structured nodes instead of opaque `preproc_call`.
|
|
62
|
+
*/
|
|
63
|
+
MACRO_PARSING: true,
|
|
64
|
+
/**
|
|
65
|
+
* Accept unexpanded macros as qualifiers, types, and expressions.
|
|
66
|
+
* E.g. `COMPAT_PRECISION float x;`, `CONCAT(vec, 3) value;`.
|
|
67
|
+
*/
|
|
68
|
+
MACRO_EXPANSION: true,
|
|
69
|
+
/**
|
|
70
|
+
* Recognize `#ifdef __cplusplus` / `#ifndef __STDC__` language
|
|
71
|
+
* guards and preserve non-GLSL branches for language injection.
|
|
72
|
+
*/
|
|
73
|
+
MULTILINGUAL: true,
|
|
74
|
+
/**
|
|
75
|
+
* Restrict to the ESSL (OpenGL ES) subset: no aggregate
|
|
76
|
+
* initializers (`{ ... }`), no standalone `;` declarations.
|
|
77
|
+
*/
|
|
78
|
+
ESSL: false,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Expression precedence levels (specification/chapters/operators.adoc).
|
|
83
|
+
* Higher number = higher precedence (binds tighter).
|
|
84
|
+
* Used for prec.left/prec.right within each production.
|
|
85
|
+
*/
|
|
86
|
+
const PRECEDENCE = {
|
|
87
|
+
COMMA: 1, // spec 17 (lowest)
|
|
88
|
+
ASSIGNMENT: 2, // spec 16
|
|
89
|
+
CONDITIONAL: 3, // spec 15
|
|
90
|
+
LOGICAL_OR: 4, // spec 14
|
|
91
|
+
LOGICAL_XOR: 5, // spec 13
|
|
92
|
+
LOGICAL_AND: 6, // spec 12
|
|
93
|
+
INCLUSIVE_OR: 7, // spec 11
|
|
94
|
+
EXCLUSIVE_OR: 8, // spec 10
|
|
95
|
+
AND: 9, // spec 9
|
|
96
|
+
EQUALITY: 10, // spec 8
|
|
97
|
+
RELATIONAL: 11, // spec 7
|
|
98
|
+
SHIFT: 12, // spec 6
|
|
99
|
+
ADDITIVE: 13, // spec 5
|
|
100
|
+
MULTIPLICATIVE: 14, // spec 4
|
|
101
|
+
UNARY: 15, // spec 3
|
|
102
|
+
POSTFIX: 16, // spec 2
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates a preprocessor regex rule.
|
|
109
|
+
* Based on: ref/c_grammar.js preprocessor()
|
|
110
|
+
*
|
|
111
|
+
* @param {string} command Preprocessor directive name without `#`.
|
|
112
|
+
* @returns {RuleOrLiteral} Tree-sitter alias rule for the directive token.
|
|
113
|
+
*/
|
|
114
|
+
function preprocessor(command) {
|
|
115
|
+
return alias(token(prec(1, new RegExp('#[ \\t]*' + command))), '#' + command);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates preproc_if / preproc_ifdef / preproc_else / preproc_elif rules
|
|
120
|
+
* parameterized by a suffix and content rule, so they can appear in different
|
|
121
|
+
* contexts (top-level, inside structs, inside statement lists).
|
|
122
|
+
* Based on: ref/c_grammar.js preprocIf()
|
|
123
|
+
*
|
|
124
|
+
* @param {string} suffix Rule-name suffix used for specialized variants.
|
|
125
|
+
* @param {($: any) => *} content Content builder for the directive body.
|
|
126
|
+
* @param {number} precedence Precedence used for the generated rules. Defaults to `0`.
|
|
127
|
+
* @returns {{[ruleName: string]: *}} Generated preprocessor rule builders.
|
|
128
|
+
*/
|
|
129
|
+
function preprocIf(suffix, content, precedence = 0) {
|
|
130
|
+
/**
|
|
131
|
+
* Builds the `#else` / `#elif` alternative branch for a generated rule.
|
|
132
|
+
*
|
|
133
|
+
* @param {*} $ Grammar symbols.
|
|
134
|
+
* @returns {RuleOrLiteral} Alternative branch rule.
|
|
135
|
+
*/
|
|
136
|
+
function alternativeBlock($) {
|
|
137
|
+
return choice(
|
|
138
|
+
suffix ?
|
|
139
|
+
alias($['preproc_else' + suffix], $.preproc_else) :
|
|
140
|
+
$.preproc_else,
|
|
141
|
+
suffix ?
|
|
142
|
+
alias($['preproc_elif' + suffix], $.preproc_elif) :
|
|
143
|
+
$.preproc_elif,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
/**
|
|
149
|
+
* @param {*} $ Grammar symbols.
|
|
150
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
151
|
+
*/
|
|
152
|
+
['preproc_if' + suffix]: ($) =>
|
|
153
|
+
prec(
|
|
154
|
+
precedence,
|
|
155
|
+
seq(
|
|
156
|
+
preprocessor('if'),
|
|
157
|
+
field('condition', $._preproc_expression),
|
|
158
|
+
token.immediate(/\r?\n/),
|
|
159
|
+
repeat(content($)),
|
|
160
|
+
field('alternative', optional(alternativeBlock($))),
|
|
161
|
+
preprocessor('endif'),
|
|
162
|
+
),
|
|
163
|
+
),
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* @param {*} $ Grammar symbols.
|
|
167
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
168
|
+
*/
|
|
169
|
+
['preproc_ifdef' + suffix]: ($) =>
|
|
170
|
+
prec(
|
|
171
|
+
precedence,
|
|
172
|
+
seq(
|
|
173
|
+
choice(preprocessor('ifdef'), preprocessor('ifndef')),
|
|
174
|
+
field('name', $.identifier),
|
|
175
|
+
repeat(content($)),
|
|
176
|
+
field('alternative', optional(alternativeBlock($))),
|
|
177
|
+
preprocessor('endif'),
|
|
178
|
+
),
|
|
179
|
+
),
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* @param {*} $ Grammar symbols.
|
|
183
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
184
|
+
*/
|
|
185
|
+
['preproc_else' + suffix]: ($) =>
|
|
186
|
+
prec(precedence, seq(preprocessor('else'), repeat(content($)))),
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @param {*} $ Grammar symbols.
|
|
190
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
191
|
+
*/
|
|
192
|
+
['preproc_elif' + suffix]: ($) =>
|
|
193
|
+
prec(
|
|
194
|
+
precedence,
|
|
195
|
+
seq(
|
|
196
|
+
preprocessor('elif'),
|
|
197
|
+
field('condition', $._preproc_expression),
|
|
198
|
+
token.immediate(/\r?\n/),
|
|
199
|
+
repeat(content($)),
|
|
200
|
+
field('alternative', optional(alternativeBlock($))),
|
|
201
|
+
),
|
|
202
|
+
),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Creates a rule to optionally match one or more of the rules
|
|
208
|
+
* separated by a comma.
|
|
209
|
+
*
|
|
210
|
+
* @param {*} rule Rule to repeat.
|
|
211
|
+
* @returns {RuleOrLiteral} Optional comma-separated rule sequence.
|
|
212
|
+
*/
|
|
213
|
+
function commaSep(rule) {
|
|
214
|
+
return optional(commaSep1(rule));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Creates a rule to match one or more of the rules separated by a comma.
|
|
219
|
+
*
|
|
220
|
+
* @param {*} rule Rule to repeat.
|
|
221
|
+
* @returns {RuleOrLiteral} Comma-separated rule sequence.
|
|
222
|
+
*/
|
|
223
|
+
function commaSep1(rule) {
|
|
224
|
+
return seq(rule, repeat(seq(',', rule)));
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Builds a logical negation wrapper around a rule fragment.
|
|
229
|
+
*
|
|
230
|
+
* @param {*} expr Rule fragment to negate.
|
|
231
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
232
|
+
*/
|
|
233
|
+
function not(expr) {
|
|
234
|
+
return seq('!', expr);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ── OPT.MULTILINGUAL Helpers ─────────────────────────────────────────────
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Language check: `MACRO`, `defined MACRO`, or `defined(MACRO)`.
|
|
241
|
+
*
|
|
242
|
+
* @param {*} macro The language macro rule.
|
|
243
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
244
|
+
*/
|
|
245
|
+
function langCheck(macro) {
|
|
246
|
+
return choice(macro, seq('defined', macro), seq('defined', '(', macro, ')'));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Compound condition patterns: `A || B`, `(A || B)`, `A && !B`, etc.
|
|
251
|
+
*
|
|
252
|
+
* @param {*} primary The primary language check (e.g. cpp).
|
|
253
|
+
* @param {*} secondary The secondary language check (e.g. c).
|
|
254
|
+
* @returns {Array} Alternatives to spread into a `choice()`.
|
|
255
|
+
*/
|
|
256
|
+
function langCompound(primary, secondary) {
|
|
257
|
+
return [
|
|
258
|
+
seq('(', primary, '||', secondary, ')'),
|
|
259
|
+
seq('(', secondary, '||', primary, ')'),
|
|
260
|
+
seq('(', primary, '&&', not(secondary), ')'),
|
|
261
|
+
seq('(', not(secondary), '&&', primary, ')'),
|
|
262
|
+
seq(primary, '||', secondary),
|
|
263
|
+
seq(secondary, '||', primary),
|
|
264
|
+
seq(primary, '&&', not(secondary)),
|
|
265
|
+
seq(not(secondary), '&&', primary),
|
|
266
|
+
];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Positive language guard body: condition selects foreign code.
|
|
271
|
+
*
|
|
272
|
+
* @param {*} condition The positive condition rule.
|
|
273
|
+
* @param {*} codeBlock The foreign code block rule.
|
|
274
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
275
|
+
*/
|
|
276
|
+
function langForeignBody(condition, codeBlock) {
|
|
277
|
+
return seq(
|
|
278
|
+
field('condition', condition),
|
|
279
|
+
token.immediate(/\r?\n/),
|
|
280
|
+
field('consequence', codeBlock),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Negated language guard body: condition excludes foreign code → body is GLSL.
|
|
286
|
+
*
|
|
287
|
+
* @param {*} $ Grammar symbols.
|
|
288
|
+
* @param {*} condition The negated condition rule.
|
|
289
|
+
* @param {*} foreignElse The foreign-language else rule.
|
|
290
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
291
|
+
*/
|
|
292
|
+
function langGlslBody($, condition, foreignElse) {
|
|
293
|
+
return seq(
|
|
294
|
+
field('condition', condition),
|
|
295
|
+
repeat($._top_level_item),
|
|
296
|
+
field('alternative', optional(alias(foreignElse, $.preproc_else))),
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* `#ifdef` arm: foreign code in body, optional GLSL in `#else`.
|
|
302
|
+
*
|
|
303
|
+
* @param {*} $ Grammar symbols.
|
|
304
|
+
* @param {*} macro The language macro rule.
|
|
305
|
+
* @param {*} codeBlock The foreign code block rule.
|
|
306
|
+
* @param {*} glslElse The GLSL else rule.
|
|
307
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
308
|
+
*/
|
|
309
|
+
function langIfdefArm($, macro, codeBlock, glslElse) {
|
|
310
|
+
return seq(
|
|
311
|
+
field('name', macro),
|
|
312
|
+
field('consequence', codeBlock),
|
|
313
|
+
field('alternative', optional(alias(glslElse, $.preproc_else))),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* `#ifndef` arm: GLSL in body, optional foreign code in `#else`.
|
|
319
|
+
*
|
|
320
|
+
* @param {*} $ Grammar symbols.
|
|
321
|
+
* @param {*} macro The language macro rule.
|
|
322
|
+
* @param {*} foreignElse The foreign-language else rule.
|
|
323
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
324
|
+
*/
|
|
325
|
+
function langIfndefArm($, macro, foreignElse) {
|
|
326
|
+
return seq(
|
|
327
|
+
field('name', macro),
|
|
328
|
+
repeat($._top_level_item),
|
|
329
|
+
field('alternative', optional(alias(foreignElse, $.preproc_else))),
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export default grammar({
|
|
334
|
+
name: 'glsl',
|
|
335
|
+
|
|
336
|
+
conflicts: ($) => [
|
|
337
|
+
// `const foo;` — GLSL allows bare type declarations like `const vec3;`
|
|
338
|
+
// where `foo` is a _type_identifier starting a declarator_list, but
|
|
339
|
+
// also `type_qualifier identifier_list SEMICOLON` where `foo` is a
|
|
340
|
+
// plain identifier in identifier_list. Without a symbol table we
|
|
341
|
+
// can't tell which.
|
|
342
|
+
[$.identifier_list, $._type_identifier],
|
|
343
|
+
|
|
344
|
+
...(OPT.MACRO_EXPANSION ?
|
|
345
|
+
[
|
|
346
|
+
// `MYMACRO vec3 x;` — `MYMACRO` could be a type name
|
|
347
|
+
// (constructor) or a macro_invocation standing in for a qualifier.
|
|
348
|
+
// Resolved by context after the next token.
|
|
349
|
+
[$._type_identifier, $.macro_invocation],
|
|
350
|
+
|
|
351
|
+
// `MYMACRO(args) x;` — `MYMACRO(args)` could be a function-like
|
|
352
|
+
// type constructor or a macro_invocation in type position.
|
|
353
|
+
[$._type_specifier_nonarray, $.macro_invocation],
|
|
354
|
+
|
|
355
|
+
// `foo[0]` — `foo` could be a variable (primary_expression) for
|
|
356
|
+
// subscript or a type name for an array constructor. GLSL has no
|
|
357
|
+
// way to distinguish TYPE_NAME from IDENTIFIER without a symbol
|
|
358
|
+
// table.
|
|
359
|
+
// `foo(` — `foo` could be a variable starting a function_call,
|
|
360
|
+
// a macro_invocation, a type identifier, or a macro_function_call.
|
|
361
|
+
[$._primary_expression, $._type_identifier, $.macro_invocation, $._macro_function_call],
|
|
362
|
+
|
|
363
|
+
// `foo(` — identifier could start a macro_invocation or be a
|
|
364
|
+
// primary_expression in various contexts.
|
|
365
|
+
[$._primary_expression, $.macro_invocation],
|
|
366
|
+
[$._primary_expression, $._type_identifier, $.macro_invocation],
|
|
367
|
+
|
|
368
|
+
// `QUAL1 QUAL2 type x;` — when multiple identifiers appear as
|
|
369
|
+
// qualifiers, the repeat in type_qualifier can't tell where
|
|
370
|
+
// qualifiers end and the type begins without lookahead.
|
|
371
|
+
[$.type_qualifier],
|
|
372
|
+
|
|
373
|
+
// `MYMACRO;` at statement level — could be an expression
|
|
374
|
+
// statement (identifier followed by `;`) or a macro_invocation
|
|
375
|
+
// used as a statement-like construct.
|
|
376
|
+
[$.expression_statement, $.macro_invocation],
|
|
377
|
+
|
|
378
|
+
// Combination of the above two: `MYMACRO(args)` at statement
|
|
379
|
+
// level is three-way ambiguous between expression statement,
|
|
380
|
+
// type specifier starting a declaration, and macro_invocation.
|
|
381
|
+
[
|
|
382
|
+
$.expression_statement,
|
|
383
|
+
$._type_specifier_nonarray,
|
|
384
|
+
$.macro_invocation,
|
|
385
|
+
],
|
|
386
|
+
] :
|
|
387
|
+
[]),
|
|
388
|
+
],
|
|
389
|
+
|
|
390
|
+
extras: ($) => [/\s|\\\r?\n/, $.comment],
|
|
391
|
+
|
|
392
|
+
inline: (_) => [],
|
|
393
|
+
|
|
394
|
+
supertypes: ($) => [$.statement, $.simple_statement, $.single_type_qualifier],
|
|
395
|
+
|
|
396
|
+
word: ($) => $.identifier,
|
|
397
|
+
|
|
398
|
+
rules: Object.assign(
|
|
399
|
+
{
|
|
400
|
+
// ── Top-level ── grammar.adoc ──────────────────────────────────────
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* ```bnf
|
|
404
|
+
* translation_unit :
|
|
405
|
+
* external_declaration
|
|
406
|
+
* translation_unit external_declaration
|
|
407
|
+
* ```
|
|
408
|
+
*
|
|
409
|
+
* Tree-sitter compromise: uses repeat() instead of left-recursive list.
|
|
410
|
+
*
|
|
411
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
412
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
413
|
+
*/
|
|
414
|
+
translation_unit: ($) => repeat($._top_level_item),
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* ```bnf
|
|
418
|
+
* external_declaration :
|
|
419
|
+
* function_definition
|
|
420
|
+
* declaration
|
|
421
|
+
* SEMICOLON
|
|
422
|
+
* ```
|
|
423
|
+
*
|
|
424
|
+
* Hidden: transparent pass-through so top-level items appear
|
|
425
|
+
* directly under translation_unit.
|
|
426
|
+
*
|
|
427
|
+
* @param {GrammarSymbols<string>} $
|
|
428
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
429
|
+
*/
|
|
430
|
+
_external_declaration: ($) =>
|
|
431
|
+
choice(
|
|
432
|
+
$.function_definition,
|
|
433
|
+
$.declaration,
|
|
434
|
+
...(OPT.ESSL ? [] : [';']),
|
|
435
|
+
),
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* ```bnf
|
|
439
|
+
* function_definition :
|
|
440
|
+
* function_prototype compound_statement_no_new_scope
|
|
441
|
+
* ```
|
|
442
|
+
*
|
|
443
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
444
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
445
|
+
*/
|
|
446
|
+
function_definition: ($) =>
|
|
447
|
+
seq($.function_declarator, $.compound_statement),
|
|
448
|
+
|
|
449
|
+
// ── Expressions ── grammar.adoc ────────────────────────────────────
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* ```bnf
|
|
453
|
+
* primary_expression :
|
|
454
|
+
* variable_identifier
|
|
455
|
+
* INTCONSTANT
|
|
456
|
+
* UINTCONSTANT
|
|
457
|
+
* FLOATCONSTANT
|
|
458
|
+
* BOOLCONSTANT
|
|
459
|
+
* DOUBLECONSTANT
|
|
460
|
+
* LEFT_PAREN expression RIGHT_PAREN
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
463
|
+
* Hidden: transparent pass-through so bare identifiers/literals
|
|
464
|
+
* appear directly without a wrapper node.
|
|
465
|
+
* variable_identifier is inlined (just IDENTIFIER).
|
|
466
|
+
* BOOLCONSTANT is `true` or `false`.
|
|
467
|
+
*
|
|
468
|
+
* @param {GrammarSymbols<string>} $
|
|
469
|
+
*/
|
|
470
|
+
_primary_expression: ($) =>
|
|
471
|
+
choice(
|
|
472
|
+
$.identifier,
|
|
473
|
+
$.number_literal,
|
|
474
|
+
$.bool_literal,
|
|
475
|
+
$.parenthesized_expression,
|
|
476
|
+
...(OPT.MACRO_EXPANSION ?
|
|
477
|
+
[prec.dynamic(-1, $.macro_invocation)] :
|
|
478
|
+
[]),
|
|
479
|
+
),
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* ```bnf
|
|
483
|
+
* primary_expression : BOOLCONSTANT
|
|
484
|
+
* ```
|
|
485
|
+
*
|
|
486
|
+
* @param {GrammarSymbols<string>} _
|
|
487
|
+
*/
|
|
488
|
+
bool_literal: (_) => choice('true', 'false'),
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* ```bnf
|
|
492
|
+
* primary_expression : LEFT_PAREN expression RIGHT_PAREN
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* Tree-sitter compromise: extracted from _primary_expression as
|
|
496
|
+
* a named node for editor fold/highlight support.
|
|
497
|
+
*
|
|
498
|
+
* @param {GrammarSymbols<string>} $
|
|
499
|
+
*/
|
|
500
|
+
parenthesized_expression: ($) => seq('(', $._expression, ')'),
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* ```bnf
|
|
504
|
+
* postfix_expression :
|
|
505
|
+
* primary_expression
|
|
506
|
+
* postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
|
|
507
|
+
* function_call
|
|
508
|
+
* postfix_expression DOT FIELD_SELECTION
|
|
509
|
+
* postfix_expression INC_OP
|
|
510
|
+
* postfix_expression DEC_OP
|
|
511
|
+
* ```
|
|
512
|
+
*
|
|
513
|
+
* Hidden: transparent pass-through. Public sub-rules
|
|
514
|
+
* (subscript_expression, function_call, field_expression,
|
|
515
|
+
* update_expression) are extracted as named nodes.
|
|
516
|
+
* integer_expression is inlined (just expression).
|
|
517
|
+
*
|
|
518
|
+
* @param {GrammarSymbols<string>} $
|
|
519
|
+
*/
|
|
520
|
+
_postfix_expression: ($) =>
|
|
521
|
+
choice(
|
|
522
|
+
$._primary_expression,
|
|
523
|
+
$.subscript_expression,
|
|
524
|
+
$.function_call,
|
|
525
|
+
$.field_expression,
|
|
526
|
+
alias($._postfix_update, $.update_expression),
|
|
527
|
+
),
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Hidden helper: postfix increment/decrement, aliased to
|
|
531
|
+
* update_expression in _postfix_expression.
|
|
532
|
+
*
|
|
533
|
+
* @param {GrammarSymbols<string>} $
|
|
534
|
+
*/
|
|
535
|
+
_postfix_update: ($) =>
|
|
536
|
+
prec.left(
|
|
537
|
+
PRECEDENCE.POSTFIX,
|
|
538
|
+
seq(
|
|
539
|
+
field('argument', $._postfix_expression),
|
|
540
|
+
field('operator', choice('++', '--')),
|
|
541
|
+
),
|
|
542
|
+
),
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* ```bnf
|
|
546
|
+
* postfix_expression :
|
|
547
|
+
* postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET
|
|
548
|
+
* ```
|
|
549
|
+
*
|
|
550
|
+
* Tree-sitter compromise: extracted from _postfix_expression as a
|
|
551
|
+
* named node. integer_expression is just expression.
|
|
552
|
+
*
|
|
553
|
+
* @param {GrammarSymbols<string>} $
|
|
554
|
+
*/
|
|
555
|
+
subscript_expression: ($) =>
|
|
556
|
+
prec(
|
|
557
|
+
PRECEDENCE.POSTFIX,
|
|
558
|
+
seq(
|
|
559
|
+
field('argument', $._postfix_expression),
|
|
560
|
+
'[',
|
|
561
|
+
field('index', $._expression),
|
|
562
|
+
']',
|
|
563
|
+
),
|
|
564
|
+
),
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* ```bnf
|
|
568
|
+
* postfix_expression : postfix_expression DOT FIELD_SELECTION
|
|
569
|
+
* ```
|
|
570
|
+
*
|
|
571
|
+
* Tree-sitter compromise: extracted from _postfix_expression as a
|
|
572
|
+
* named node. FIELD_SELECTION is aliased to field_identifier.
|
|
573
|
+
*
|
|
574
|
+
* @param {GrammarSymbols<string>} $
|
|
575
|
+
*/
|
|
576
|
+
field_expression: ($) =>
|
|
577
|
+
prec(
|
|
578
|
+
PRECEDENCE.POSTFIX,
|
|
579
|
+
seq(
|
|
580
|
+
field('argument', $._postfix_expression),
|
|
581
|
+
'.',
|
|
582
|
+
field('field', alias($.identifier, $.field_identifier)),
|
|
583
|
+
),
|
|
584
|
+
),
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* ```bnf
|
|
588
|
+
* function_call : function_call_or_method
|
|
589
|
+
*
|
|
590
|
+
* function_call_or_method : function_call_generic
|
|
591
|
+
*
|
|
592
|
+
* function_call_generic :
|
|
593
|
+
* function_call_header_with_parameters RIGHT_PAREN
|
|
594
|
+
* function_call_header_no_parameters RIGHT_PAREN
|
|
595
|
+
*
|
|
596
|
+
* function_call_header_no_parameters :
|
|
597
|
+
* function_call_header VOID
|
|
598
|
+
* function_call_header
|
|
599
|
+
*
|
|
600
|
+
* function_call_header_with_parameters :
|
|
601
|
+
* function_call_header assignment_expression
|
|
602
|
+
* function_call_header_with_parameters COMMA assignment_expression
|
|
603
|
+
*
|
|
604
|
+
* function_call_header :
|
|
605
|
+
* function_identifier LEFT_PAREN
|
|
606
|
+
*
|
|
607
|
+
* function_identifier :
|
|
608
|
+
* type_specifier
|
|
609
|
+
* postfix_expression
|
|
610
|
+
* ```
|
|
611
|
+
*
|
|
612
|
+
* Tree-sitter compromise: the 6-level spec chain
|
|
613
|
+
* (function_call → function_call_or_method → function_call_generic →
|
|
614
|
+
* function_call_header_* → function_call_header → function_identifier)
|
|
615
|
+
* is collapsed into a single function_call node.
|
|
616
|
+
*
|
|
617
|
+
* @param {GrammarSymbols<string>} $
|
|
618
|
+
*/
|
|
619
|
+
function_call: ($) =>
|
|
620
|
+
prec.dynamic(
|
|
621
|
+
1,
|
|
622
|
+
prec(
|
|
623
|
+
PRECEDENCE.POSTFIX,
|
|
624
|
+
seq(
|
|
625
|
+
field(
|
|
626
|
+
'function',
|
|
627
|
+
choice($.type_specifier, $._postfix_expression),
|
|
628
|
+
),
|
|
629
|
+
'(',
|
|
630
|
+
optional(field('arguments', $.argument_list)),
|
|
631
|
+
')',
|
|
632
|
+
),
|
|
633
|
+
),
|
|
634
|
+
),
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Tree-sitter compromise: preserves the spec's `void` no-argument form.
|
|
638
|
+
*
|
|
639
|
+
* @param {GrammarSymbols<string>} $
|
|
640
|
+
*/
|
|
641
|
+
argument_list: ($) => choice('void', commaSep1($._assignment_expression)),
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* ```bnf
|
|
645
|
+
* unary_expression :
|
|
646
|
+
* postfix_expression
|
|
647
|
+
* INC_OP unary_expression
|
|
648
|
+
* DEC_OP unary_expression
|
|
649
|
+
* unary_operator unary_expression
|
|
650
|
+
*
|
|
651
|
+
* unary_operator :
|
|
652
|
+
* PLUS | DASH | BANG | TILDE
|
|
653
|
+
* ```
|
|
654
|
+
*
|
|
655
|
+
* Hidden: transparent pass-through. Public sub-rules
|
|
656
|
+
* (unary_expression for operators, update_expression for ++/--)
|
|
657
|
+
* are extracted as named nodes.
|
|
658
|
+
*
|
|
659
|
+
* @param {GrammarSymbols<string>} $
|
|
660
|
+
*/
|
|
661
|
+
_unary_expression: ($) =>
|
|
662
|
+
choice(
|
|
663
|
+
$._postfix_expression,
|
|
664
|
+
alias($._prefix_update, $.update_expression),
|
|
665
|
+
$.unary_expression,
|
|
666
|
+
),
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Hidden helper: prefix increment/decrement, aliased to
|
|
670
|
+
* update_expression in _unary_expression.
|
|
671
|
+
*
|
|
672
|
+
* @param {GrammarSymbols<string>} $
|
|
673
|
+
*/
|
|
674
|
+
_prefix_update: ($) =>
|
|
675
|
+
prec.right(
|
|
676
|
+
PRECEDENCE.UNARY,
|
|
677
|
+
seq(
|
|
678
|
+
field('operator', choice('++', '--')),
|
|
679
|
+
field('argument', $._unary_expression),
|
|
680
|
+
),
|
|
681
|
+
),
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Public sub-rule of _unary_expression: only emitted when a
|
|
685
|
+
* unary operator (+, -, !, ~) is present.
|
|
686
|
+
*
|
|
687
|
+
* @param {GrammarSymbols<string>} $
|
|
688
|
+
*/
|
|
689
|
+
unary_expression: ($) =>
|
|
690
|
+
prec.right(
|
|
691
|
+
PRECEDENCE.UNARY,
|
|
692
|
+
seq(
|
|
693
|
+
field('operator', choice('+', '-', '!', '~')),
|
|
694
|
+
field('argument', $._unary_expression),
|
|
695
|
+
),
|
|
696
|
+
),
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Public alias target for both prefix and postfix ++/--
|
|
700
|
+
* (via _postfix_update and _prefix_update).
|
|
701
|
+
*
|
|
702
|
+
* @param {GrammarSymbols<string>} $
|
|
703
|
+
*/
|
|
704
|
+
update_expression: ($) => choice($._postfix_update, $._prefix_update),
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* ```bnf
|
|
708
|
+
* multiplicative_expression :
|
|
709
|
+
* unary_expression
|
|
710
|
+
* multiplicative_expression STAR unary_expression
|
|
711
|
+
* multiplicative_expression SLASH unary_expression
|
|
712
|
+
* multiplicative_expression PERCENT unary_expression
|
|
713
|
+
* ```
|
|
714
|
+
*
|
|
715
|
+
* @param {GrammarSymbols<string>} $
|
|
716
|
+
*/
|
|
717
|
+
_multiplicative_expression: ($) =>
|
|
718
|
+
choice(
|
|
719
|
+
$._unary_expression,
|
|
720
|
+
alias($._multiplicative_operation, $.binary_expression),
|
|
721
|
+
),
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Hidden helper for multiplicative binary operations.
|
|
725
|
+
*
|
|
726
|
+
* @param {GrammarSymbols<string>} $
|
|
727
|
+
*/
|
|
728
|
+
_multiplicative_operation: ($) =>
|
|
729
|
+
prec.left(
|
|
730
|
+
PRECEDENCE.MULTIPLICATIVE,
|
|
731
|
+
seq(
|
|
732
|
+
field('left', $._multiplicative_expression),
|
|
733
|
+
field('operator', choice('*', '/', '%')),
|
|
734
|
+
field('right', $._unary_expression),
|
|
735
|
+
),
|
|
736
|
+
),
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* ```bnf
|
|
740
|
+
* additive_expression :
|
|
741
|
+
* multiplicative_expression
|
|
742
|
+
* additive_expression PLUS multiplicative_expression
|
|
743
|
+
* additive_expression DASH multiplicative_expression
|
|
744
|
+
* ```
|
|
745
|
+
*
|
|
746
|
+
* @param {GrammarSymbols<string>} $
|
|
747
|
+
*/
|
|
748
|
+
_additive_expression: ($) =>
|
|
749
|
+
choice(
|
|
750
|
+
$._multiplicative_expression,
|
|
751
|
+
alias($._additive_operation, $.binary_expression),
|
|
752
|
+
),
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Hidden helper for additive binary operations.
|
|
756
|
+
*
|
|
757
|
+
* @param {GrammarSymbols<string>} $
|
|
758
|
+
*/
|
|
759
|
+
_additive_operation: ($) =>
|
|
760
|
+
prec.left(
|
|
761
|
+
PRECEDENCE.ADDITIVE,
|
|
762
|
+
seq(
|
|
763
|
+
field('left', $._additive_expression),
|
|
764
|
+
field('operator', choice('+', '-')),
|
|
765
|
+
field('right', $._multiplicative_expression),
|
|
766
|
+
),
|
|
767
|
+
),
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* ```bnf
|
|
771
|
+
* shift_expression :
|
|
772
|
+
* additive_expression
|
|
773
|
+
* shift_expression LEFT_OP additive_expression
|
|
774
|
+
* shift_expression RIGHT_OP additive_expression
|
|
775
|
+
* ```
|
|
776
|
+
*
|
|
777
|
+
* @param {GrammarSymbols<string>} $
|
|
778
|
+
*/
|
|
779
|
+
_shift_expression: ($) =>
|
|
780
|
+
choice(
|
|
781
|
+
$._additive_expression,
|
|
782
|
+
alias($._shift_operation, $.binary_expression),
|
|
783
|
+
),
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Hidden helper for shift binary operations.
|
|
787
|
+
*
|
|
788
|
+
* @param {GrammarSymbols<string>} $
|
|
789
|
+
*/
|
|
790
|
+
_shift_operation: ($) =>
|
|
791
|
+
prec.left(
|
|
792
|
+
PRECEDENCE.SHIFT,
|
|
793
|
+
seq(
|
|
794
|
+
field('left', $._shift_expression),
|
|
795
|
+
field('operator', choice('<<', '>>')),
|
|
796
|
+
field('right', $._additive_expression),
|
|
797
|
+
),
|
|
798
|
+
),
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* ```bnf
|
|
802
|
+
* relational_expression :
|
|
803
|
+
* shift_expression
|
|
804
|
+
* relational_expression LEFT_ANGLE shift_expression
|
|
805
|
+
* relational_expression RIGHT_ANGLE shift_expression
|
|
806
|
+
* relational_expression LE_OP shift_expression
|
|
807
|
+
* relational_expression GE_OP shift_expression
|
|
808
|
+
* ```
|
|
809
|
+
*
|
|
810
|
+
* @param {GrammarSymbols<string>} $
|
|
811
|
+
*/
|
|
812
|
+
_relational_expression: ($) =>
|
|
813
|
+
choice(
|
|
814
|
+
$._shift_expression,
|
|
815
|
+
alias($._relational_operation, $.binary_expression),
|
|
816
|
+
),
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Hidden helper for relational binary operations.
|
|
820
|
+
*
|
|
821
|
+
* @param {GrammarSymbols<string>} $
|
|
822
|
+
*/
|
|
823
|
+
_relational_operation: ($) =>
|
|
824
|
+
prec.left(
|
|
825
|
+
PRECEDENCE.RELATIONAL,
|
|
826
|
+
seq(
|
|
827
|
+
field('left', $._relational_expression),
|
|
828
|
+
field('operator', choice('<', '>', '<=', '>=')),
|
|
829
|
+
field('right', $._shift_expression),
|
|
830
|
+
),
|
|
831
|
+
),
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* ```bnf
|
|
835
|
+
* equality_expression :
|
|
836
|
+
* relational_expression
|
|
837
|
+
* equality_expression EQ_OP relational_expression
|
|
838
|
+
* equality_expression NE_OP relational_expression
|
|
839
|
+
* ```
|
|
840
|
+
*
|
|
841
|
+
* @param {GrammarSymbols<string>} $
|
|
842
|
+
*/
|
|
843
|
+
_equality_expression: ($) =>
|
|
844
|
+
choice(
|
|
845
|
+
$._relational_expression,
|
|
846
|
+
alias($._equality_operation, $.binary_expression),
|
|
847
|
+
),
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Hidden helper for equality binary operations.
|
|
851
|
+
*
|
|
852
|
+
* @param {GrammarSymbols<string>} $
|
|
853
|
+
*/
|
|
854
|
+
_equality_operation: ($) =>
|
|
855
|
+
prec.left(
|
|
856
|
+
PRECEDENCE.EQUALITY,
|
|
857
|
+
seq(
|
|
858
|
+
field('left', $._equality_expression),
|
|
859
|
+
field('operator', choice('==', '!=')),
|
|
860
|
+
field('right', $._relational_expression),
|
|
861
|
+
),
|
|
862
|
+
),
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* ```bnf
|
|
866
|
+
* and_expression :
|
|
867
|
+
* equality_expression
|
|
868
|
+
* and_expression AMPERSAND equality_expression
|
|
869
|
+
* ```
|
|
870
|
+
*
|
|
871
|
+
* @param {GrammarSymbols<string>} $
|
|
872
|
+
*/
|
|
873
|
+
_and_expression: ($) =>
|
|
874
|
+
choice(
|
|
875
|
+
$._equality_expression,
|
|
876
|
+
alias($._and_operation, $.binary_expression),
|
|
877
|
+
),
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Hidden helper for bitwise-and operations.
|
|
881
|
+
*
|
|
882
|
+
* @param {GrammarSymbols<string>} $
|
|
883
|
+
*/
|
|
884
|
+
_and_operation: ($) =>
|
|
885
|
+
prec.left(
|
|
886
|
+
PRECEDENCE.AND,
|
|
887
|
+
seq(
|
|
888
|
+
field('left', $._and_expression),
|
|
889
|
+
field('operator', '&'),
|
|
890
|
+
field('right', $._equality_expression),
|
|
891
|
+
),
|
|
892
|
+
),
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* ```bnf
|
|
896
|
+
* exclusive_or_expression :
|
|
897
|
+
* and_expression
|
|
898
|
+
* exclusive_or_expression CARET and_expression
|
|
899
|
+
* ```
|
|
900
|
+
*
|
|
901
|
+
* @param {GrammarSymbols<string>} $
|
|
902
|
+
*/
|
|
903
|
+
_exclusive_or_expression: ($) =>
|
|
904
|
+
choice(
|
|
905
|
+
$._and_expression,
|
|
906
|
+
alias($._exclusive_or_operation, $.binary_expression),
|
|
907
|
+
),
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Hidden helper for bitwise-xor operations.
|
|
911
|
+
*
|
|
912
|
+
* @param {GrammarSymbols<string>} $
|
|
913
|
+
*/
|
|
914
|
+
_exclusive_or_operation: ($) =>
|
|
915
|
+
prec.left(
|
|
916
|
+
PRECEDENCE.EXCLUSIVE_OR,
|
|
917
|
+
seq(
|
|
918
|
+
field('left', $._exclusive_or_expression),
|
|
919
|
+
field('operator', '^'),
|
|
920
|
+
field('right', $._and_expression),
|
|
921
|
+
),
|
|
922
|
+
),
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* ```bnf
|
|
926
|
+
* inclusive_or_expression :
|
|
927
|
+
* exclusive_or_expression
|
|
928
|
+
* inclusive_or_expression VERTICAL_BAR exclusive_or_expression
|
|
929
|
+
* ```
|
|
930
|
+
*
|
|
931
|
+
* @param {GrammarSymbols<string>} $
|
|
932
|
+
*/
|
|
933
|
+
_inclusive_or_expression: ($) =>
|
|
934
|
+
choice(
|
|
935
|
+
$._exclusive_or_expression,
|
|
936
|
+
alias($._inclusive_or_operation, $.binary_expression),
|
|
937
|
+
),
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Hidden helper for bitwise-or operations.
|
|
941
|
+
*
|
|
942
|
+
* @param {GrammarSymbols<string>} $
|
|
943
|
+
*/
|
|
944
|
+
_inclusive_or_operation: ($) =>
|
|
945
|
+
prec.left(
|
|
946
|
+
PRECEDENCE.INCLUSIVE_OR,
|
|
947
|
+
seq(
|
|
948
|
+
field('left', $._inclusive_or_expression),
|
|
949
|
+
field('operator', '|'),
|
|
950
|
+
field('right', $._exclusive_or_expression),
|
|
951
|
+
),
|
|
952
|
+
),
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* ```bnf
|
|
956
|
+
* logical_and_expression :
|
|
957
|
+
* inclusive_or_expression
|
|
958
|
+
* logical_and_expression AND_OP inclusive_or_expression
|
|
959
|
+
* ```
|
|
960
|
+
*
|
|
961
|
+
* @param {GrammarSymbols<string>} $
|
|
962
|
+
*/
|
|
963
|
+
_logical_and_expression: ($) =>
|
|
964
|
+
choice(
|
|
965
|
+
$._inclusive_or_expression,
|
|
966
|
+
alias($._logical_and_operation, $.binary_expression),
|
|
967
|
+
),
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Hidden helper for logical-and operations.
|
|
971
|
+
*
|
|
972
|
+
* @param {GrammarSymbols<string>} $
|
|
973
|
+
*/
|
|
974
|
+
_logical_and_operation: ($) =>
|
|
975
|
+
prec.left(
|
|
976
|
+
PRECEDENCE.LOGICAL_AND,
|
|
977
|
+
seq(
|
|
978
|
+
field('left', $._logical_and_expression),
|
|
979
|
+
field('operator', '&&'),
|
|
980
|
+
field('right', $._inclusive_or_expression),
|
|
981
|
+
),
|
|
982
|
+
),
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* ```bnf
|
|
986
|
+
* logical_xor_expression :
|
|
987
|
+
* logical_and_expression
|
|
988
|
+
* logical_xor_expression XOR_OP logical_and_expression
|
|
989
|
+
* ```
|
|
990
|
+
*
|
|
991
|
+
* @param {GrammarSymbols<string>} $
|
|
992
|
+
*/
|
|
993
|
+
_logical_xor_expression: ($) =>
|
|
994
|
+
choice(
|
|
995
|
+
$._logical_and_expression,
|
|
996
|
+
alias($._logical_xor_operation, $.binary_expression),
|
|
997
|
+
),
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Hidden helper for logical-xor operations.
|
|
1001
|
+
*
|
|
1002
|
+
* @param {GrammarSymbols<string>} $
|
|
1003
|
+
*/
|
|
1004
|
+
_logical_xor_operation: ($) =>
|
|
1005
|
+
prec.left(
|
|
1006
|
+
PRECEDENCE.LOGICAL_XOR,
|
|
1007
|
+
seq(
|
|
1008
|
+
field('left', $._logical_xor_expression),
|
|
1009
|
+
field('operator', '^^'),
|
|
1010
|
+
field('right', $._logical_and_expression),
|
|
1011
|
+
),
|
|
1012
|
+
),
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* ```bnf
|
|
1016
|
+
* logical_or_expression :
|
|
1017
|
+
* logical_xor_expression
|
|
1018
|
+
* logical_or_expression OR_OP logical_xor_expression
|
|
1019
|
+
* ```
|
|
1020
|
+
*
|
|
1021
|
+
* @param {GrammarSymbols<string>} $
|
|
1022
|
+
*/
|
|
1023
|
+
_logical_or_expression: ($) =>
|
|
1024
|
+
choice(
|
|
1025
|
+
$._logical_xor_expression,
|
|
1026
|
+
alias($._logical_or_operation, $.binary_expression),
|
|
1027
|
+
),
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Hidden helper for logical-or operations.
|
|
1031
|
+
*
|
|
1032
|
+
* @param {GrammarSymbols<string>} $
|
|
1033
|
+
*/
|
|
1034
|
+
_logical_or_operation: ($) =>
|
|
1035
|
+
prec.left(
|
|
1036
|
+
PRECEDENCE.LOGICAL_OR,
|
|
1037
|
+
seq(
|
|
1038
|
+
field('left', $._logical_or_expression),
|
|
1039
|
+
field('operator', '||'),
|
|
1040
|
+
field('right', $._logical_xor_expression),
|
|
1041
|
+
),
|
|
1042
|
+
),
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Tree-sitter compromise: the spec's binary precedence ladder is parsed
|
|
1046
|
+
* via hidden rules but emitted as one consumer-facing node.
|
|
1047
|
+
*
|
|
1048
|
+
* @param {GrammarSymbols<string>} $
|
|
1049
|
+
*/
|
|
1050
|
+
binary_expression: ($) =>
|
|
1051
|
+
choice(
|
|
1052
|
+
$._multiplicative_operation,
|
|
1053
|
+
$._additive_operation,
|
|
1054
|
+
$._shift_operation,
|
|
1055
|
+
$._relational_operation,
|
|
1056
|
+
$._equality_operation,
|
|
1057
|
+
$._and_operation,
|
|
1058
|
+
$._exclusive_or_operation,
|
|
1059
|
+
$._inclusive_or_operation,
|
|
1060
|
+
$._logical_and_operation,
|
|
1061
|
+
$._logical_xor_operation,
|
|
1062
|
+
$._logical_or_operation,
|
|
1063
|
+
),
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* ```bnf
|
|
1067
|
+
* conditional_expression :
|
|
1068
|
+
* logical_or_expression
|
|
1069
|
+
* logical_or_expression QUESTION expression COLON
|
|
1070
|
+
* assignment_expression
|
|
1071
|
+
* ```
|
|
1072
|
+
*
|
|
1073
|
+
* @param {GrammarSymbols<string>} $
|
|
1074
|
+
*/
|
|
1075
|
+
_conditional_expression: ($) =>
|
|
1076
|
+
choice($._logical_or_expression, $.conditional_expression),
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Tree-sitter compromise: visible conditional node only when `?:`
|
|
1080
|
+
* is present; the spec base case stays hidden in _conditional_expression.
|
|
1081
|
+
*
|
|
1082
|
+
* @param {GrammarSymbols<string>} $
|
|
1083
|
+
*/
|
|
1084
|
+
conditional_expression: ($) =>
|
|
1085
|
+
prec.right(
|
|
1086
|
+
PRECEDENCE.CONDITIONAL,
|
|
1087
|
+
seq(
|
|
1088
|
+
field('condition', $._logical_or_expression),
|
|
1089
|
+
'?',
|
|
1090
|
+
field('consequence', $._expression),
|
|
1091
|
+
':',
|
|
1092
|
+
field('alternative', $._assignment_expression),
|
|
1093
|
+
),
|
|
1094
|
+
),
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* ```bnf
|
|
1098
|
+
* assignment_expression :
|
|
1099
|
+
* conditional_expression
|
|
1100
|
+
* unary_expression assignment_operator assignment_expression
|
|
1101
|
+
* ```
|
|
1102
|
+
*
|
|
1103
|
+
* ```bnf
|
|
1104
|
+
* assignment_operator :
|
|
1105
|
+
* EQUAL | MUL_ASSIGN | DIV_ASSIGN | MOD_ASSIGN |
|
|
1106
|
+
* ADD_ASSIGN | SUB_ASSIGN | LEFT_ASSIGN | RIGHT_ASSIGN |
|
|
1107
|
+
* AND_ASSIGN | XOR_ASSIGN | OR_ASSIGN
|
|
1108
|
+
* ```
|
|
1109
|
+
*
|
|
1110
|
+
* @param {GrammarSymbols<string>} $
|
|
1111
|
+
*/
|
|
1112
|
+
_assignment_expression: ($) =>
|
|
1113
|
+
choice($._conditional_expression, $.assignment_expression),
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* Tree-sitter compromise: visible assignment node only when an
|
|
1117
|
+
* assignment operator is present; the spec base case stays hidden
|
|
1118
|
+
* in _assignment_expression.
|
|
1119
|
+
*
|
|
1120
|
+
* @param {GrammarSymbols<string>} $
|
|
1121
|
+
*/
|
|
1122
|
+
assignment_expression: ($) =>
|
|
1123
|
+
prec.right(
|
|
1124
|
+
PRECEDENCE.ASSIGNMENT,
|
|
1125
|
+
seq(
|
|
1126
|
+
field('left', $._unary_expression),
|
|
1127
|
+
field('operator', $.assignment_operator),
|
|
1128
|
+
field('right', $._assignment_expression),
|
|
1129
|
+
),
|
|
1130
|
+
),
|
|
1131
|
+
|
|
1132
|
+
/**
|
|
1133
|
+
* ```bnf
|
|
1134
|
+
* assignment_operator :
|
|
1135
|
+
* EQUAL | MUL_ASSIGN | DIV_ASSIGN | MOD_ASSIGN |
|
|
1136
|
+
* ADD_ASSIGN | SUB_ASSIGN | LEFT_ASSIGN | RIGHT_ASSIGN |
|
|
1137
|
+
* AND_ASSIGN | XOR_ASSIGN | OR_ASSIGN
|
|
1138
|
+
* ```
|
|
1139
|
+
*
|
|
1140
|
+
* @param {GrammarSymbols<string>} _
|
|
1141
|
+
*/
|
|
1142
|
+
assignment_operator: (_) =>
|
|
1143
|
+
choice(
|
|
1144
|
+
'=',
|
|
1145
|
+
'*=',
|
|
1146
|
+
'/=',
|
|
1147
|
+
'%=',
|
|
1148
|
+
'+=',
|
|
1149
|
+
'-=',
|
|
1150
|
+
'<<=',
|
|
1151
|
+
'>>=',
|
|
1152
|
+
'&=',
|
|
1153
|
+
'^=',
|
|
1154
|
+
'|=',
|
|
1155
|
+
),
|
|
1156
|
+
|
|
1157
|
+
/**
|
|
1158
|
+
* ```bnf
|
|
1159
|
+
* expression :
|
|
1160
|
+
* assignment_expression
|
|
1161
|
+
* expression COMMA assignment_expression
|
|
1162
|
+
* ```
|
|
1163
|
+
*
|
|
1164
|
+
* Tree-sitter compromise: _expression is hidden; the comma-operator
|
|
1165
|
+
* form surfaces as comma_expression (visible).
|
|
1166
|
+
*
|
|
1167
|
+
* @param {GrammarSymbols<string>} $
|
|
1168
|
+
*/
|
|
1169
|
+
_expression: ($) => choice($._assignment_expression, $.comma_expression),
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* ```bnf
|
|
1173
|
+
* expression : expression COMMA assignment_expression
|
|
1174
|
+
* ```
|
|
1175
|
+
*
|
|
1176
|
+
* Tree-sitter compromise: the comma-operator form is a separate
|
|
1177
|
+
* visible node; the single-assignment form is hidden in _expression.
|
|
1178
|
+
*
|
|
1179
|
+
* @param {GrammarSymbols<string>} $
|
|
1180
|
+
*/
|
|
1181
|
+
comma_expression: ($) =>
|
|
1182
|
+
prec.left(
|
|
1183
|
+
PRECEDENCE.COMMA,
|
|
1184
|
+
seq(
|
|
1185
|
+
field('left', $._expression),
|
|
1186
|
+
',',
|
|
1187
|
+
field('right', $._assignment_expression),
|
|
1188
|
+
),
|
|
1189
|
+
),
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* ```bnf
|
|
1193
|
+
* constant_expression : conditional_expression
|
|
1194
|
+
* ```
|
|
1195
|
+
*
|
|
1196
|
+
* Hidden: 1:1 pass-through so expressions appear directly in
|
|
1197
|
+
* layout arguments and array sizes.
|
|
1198
|
+
*
|
|
1199
|
+
* @param {GrammarSymbols<string>} $
|
|
1200
|
+
*/
|
|
1201
|
+
_constant_expression: ($) => $._conditional_expression,
|
|
1202
|
+
|
|
1203
|
+
// ── Types ── grammar.adoc ──────────────────────────────────────────
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* ```bnf
|
|
1207
|
+
* fully_specified_type :
|
|
1208
|
+
* type_specifier
|
|
1209
|
+
* type_qualifier type_specifier
|
|
1210
|
+
* ```
|
|
1211
|
+
*
|
|
1212
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1213
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1214
|
+
*/
|
|
1215
|
+
type: ($) =>
|
|
1216
|
+
choice(seq($.type_qualifier, $.type_specifier), $.type_specifier),
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* ```bnf
|
|
1220
|
+
* type_qualifier :
|
|
1221
|
+
* single_type_qualifier
|
|
1222
|
+
* type_qualifier single_type_qualifier
|
|
1223
|
+
* ```
|
|
1224
|
+
*
|
|
1225
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1226
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1227
|
+
*/
|
|
1228
|
+
type_qualifier: ($) => repeat1($.single_type_qualifier),
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
* ```bnf
|
|
1232
|
+
* single_type_qualifier :
|
|
1233
|
+
* storage_qualifier
|
|
1234
|
+
* layout_qualifier
|
|
1235
|
+
* precision_qualifier
|
|
1236
|
+
* interpolation_qualifier
|
|
1237
|
+
* invariant_qualifier
|
|
1238
|
+
* precise_qualifier
|
|
1239
|
+
* ```
|
|
1240
|
+
*
|
|
1241
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1242
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1243
|
+
*/
|
|
1244
|
+
single_type_qualifier: ($) =>
|
|
1245
|
+
choice(
|
|
1246
|
+
$.storage_qualifier,
|
|
1247
|
+
$.layout_qualifier,
|
|
1248
|
+
$.precision_qualifier,
|
|
1249
|
+
$.interpolation_qualifier,
|
|
1250
|
+
$.invariant_qualifier,
|
|
1251
|
+
$.precise_qualifier,
|
|
1252
|
+
...(OPT.MACRO_EXPANSION ?
|
|
1253
|
+
[prec.dynamic(-1, $.macro_invocation)] :
|
|
1254
|
+
[]),
|
|
1255
|
+
),
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* ```bnf
|
|
1259
|
+
* storage_qualifier :
|
|
1260
|
+
* CONST | IN | OUT | INOUT | CENTROID | PATCH | SAMPLE |
|
|
1261
|
+
* UNIFORM | BUFFER | SHARED | COHERENT | VOLATILE |
|
|
1262
|
+
* RESTRICT | READONLY | WRITEONLY |
|
|
1263
|
+
* SUBROUTINE | SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN
|
|
1264
|
+
* ```
|
|
1265
|
+
*
|
|
1266
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1267
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1268
|
+
*/
|
|
1269
|
+
storage_qualifier: ($) =>
|
|
1270
|
+
choice(
|
|
1271
|
+
...flattenKeywordGroups(STORAGE_QUALIFIER_KEYWORDS),
|
|
1272
|
+
seq('subroutine', '(', $.type_name_list, ')'),
|
|
1273
|
+
),
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* ```bnf
|
|
1277
|
+
* type_name_list :
|
|
1278
|
+
* TYPE_NAME
|
|
1279
|
+
* type_name_list COMMA TYPE_NAME
|
|
1280
|
+
* ```
|
|
1281
|
+
*
|
|
1282
|
+
* GLSL-only (subroutine).
|
|
1283
|
+
*
|
|
1284
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1285
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1286
|
+
*/
|
|
1287
|
+
type_name_list: ($) => commaSep1($.identifier),
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* ```bnf
|
|
1291
|
+
* layout_qualifier :
|
|
1292
|
+
* LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN
|
|
1293
|
+
* ```
|
|
1294
|
+
*
|
|
1295
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1296
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1297
|
+
*/
|
|
1298
|
+
layout_qualifier: ($) => seq('layout', '(', $._layout_arguments, ')'),
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* ```bnf
|
|
1302
|
+
* layout_qualifier_id_list :
|
|
1303
|
+
* layout_qualifier_id
|
|
1304
|
+
* layout_qualifier_id_list COMMA layout_qualifier_id
|
|
1305
|
+
* ```
|
|
1306
|
+
*
|
|
1307
|
+
* Hidden: transparent pass-through so layout_argument nodes
|
|
1308
|
+
* appear directly inside layout_qualifier.
|
|
1309
|
+
*
|
|
1310
|
+
* @param {GrammarSymbols<string>} $
|
|
1311
|
+
*/
|
|
1312
|
+
_layout_arguments: ($) => commaSep1($.layout_argument),
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* ```bnf
|
|
1316
|
+
* layout_qualifier_id :
|
|
1317
|
+
* IDENTIFIER
|
|
1318
|
+
* IDENTIFIER EQUAL constant_expression
|
|
1319
|
+
* SHARED
|
|
1320
|
+
* ```
|
|
1321
|
+
*
|
|
1322
|
+
* @param {GrammarSymbols<string>} $
|
|
1323
|
+
*/
|
|
1324
|
+
layout_argument: ($) =>
|
|
1325
|
+
choice(
|
|
1326
|
+
seq(
|
|
1327
|
+
field('name', $.identifier),
|
|
1328
|
+
'=',
|
|
1329
|
+
field('value', $._constant_expression),
|
|
1330
|
+
),
|
|
1331
|
+
$.identifier,
|
|
1332
|
+
'shared',
|
|
1333
|
+
),
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* ```bnf
|
|
1337
|
+
* precision_qualifier :
|
|
1338
|
+
* HIGH_PRECISION | MEDIUM_PRECISION | LOW_PRECISION
|
|
1339
|
+
* ```
|
|
1340
|
+
*
|
|
1341
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
1342
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1343
|
+
*/
|
|
1344
|
+
precision_qualifier: (_) =>
|
|
1345
|
+
choice(...flattenKeywordGroups(PRECISION_QUALIFIER_KEYWORDS)),
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* ```bnf
|
|
1349
|
+
* interpolation_qualifier :
|
|
1350
|
+
* SMOOTH | FLAT | NOPERSPECTIVE
|
|
1351
|
+
* ```
|
|
1352
|
+
*
|
|
1353
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
1354
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1355
|
+
*/
|
|
1356
|
+
interpolation_qualifier: (_) =>
|
|
1357
|
+
choice(...flattenKeywordGroups(INTERPOLATION_QUALIFIER_KEYWORDS)),
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* ```bnf
|
|
1361
|
+
* invariant_qualifier : INVARIANT
|
|
1362
|
+
* ```
|
|
1363
|
+
*
|
|
1364
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
1365
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1366
|
+
*/
|
|
1367
|
+
invariant_qualifier: (_) => 'invariant',
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* ```bnf
|
|
1371
|
+
* precise_qualifier : PRECISE
|
|
1372
|
+
* ```
|
|
1373
|
+
*
|
|
1374
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
1375
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1376
|
+
*/
|
|
1377
|
+
precise_qualifier: (_) => 'precise',
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* ```bnf
|
|
1381
|
+
* type_specifier :
|
|
1382
|
+
* type_specifier_nonarray
|
|
1383
|
+
* type_specifier_nonarray array_specifier
|
|
1384
|
+
* ```
|
|
1385
|
+
*
|
|
1386
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1387
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1388
|
+
*/
|
|
1389
|
+
type_specifier: ($) =>
|
|
1390
|
+
seq($._type_specifier_nonarray, optional($.array_specifier)),
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* ```bnf
|
|
1394
|
+
* array_specifier :
|
|
1395
|
+
* LEFT_BRACKET RIGHT_BRACKET
|
|
1396
|
+
* LEFT_BRACKET conditional_expression RIGHT_BRACKET
|
|
1397
|
+
* array_specifier LEFT_BRACKET RIGHT_BRACKET
|
|
1398
|
+
* array_specifier LEFT_BRACKET conditional_expression RIGHT_BRACKET
|
|
1399
|
+
* ```
|
|
1400
|
+
*
|
|
1401
|
+
* Tree-sitter compromise: uses repeat1() instead of left-recursion.
|
|
1402
|
+
*
|
|
1403
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1404
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1405
|
+
*/
|
|
1406
|
+
array_specifier: ($) =>
|
|
1407
|
+
repeat1(seq('[', optional($._conditional_expression), ']')),
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* ```bnf
|
|
1411
|
+
* type_specifier_nonarray :
|
|
1412
|
+
* VOID | FLOAT | DOUBLE | INT | UINT | BOOL |
|
|
1413
|
+
* VEC2..4 | DVEC2..4 | BVEC2..4 | IVEC2..4 | UVEC2..4 |
|
|
1414
|
+
* MAT2..4 | MAT2X2..MAT4X4 | DMAT2..4 | DMAT2X2..DMAT4X4 |
|
|
1415
|
+
* ATOMIC_UINT | <sampler types> | <image types> |
|
|
1416
|
+
* struct_specifier | TYPE_NAME
|
|
1417
|
+
* ```
|
|
1418
|
+
*
|
|
1419
|
+
* TYPE_NAME is an identifier that names a user-defined type.
|
|
1420
|
+
* Tree-sitter cannot distinguish TYPE_NAME from IDENTIFIER
|
|
1421
|
+
* semantically; here it is accepted as $._type_identifier.
|
|
1422
|
+
*
|
|
1423
|
+
* Extension: when OPT.MACRO_EXPANSION is enabled, a function-like macro
|
|
1424
|
+
* invocation is also accepted in type position so unexpanded forms like
|
|
1425
|
+
* `CONCAT(vec, 3)` can parse structurally. Bare identifiers remain
|
|
1426
|
+
* `type_identifier` because they are indistinguishable from user-defined
|
|
1427
|
+
* type names at parse time.
|
|
1428
|
+
*
|
|
1429
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1430
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1431
|
+
*/
|
|
1432
|
+
_type_specifier_nonarray: ($) =>
|
|
1433
|
+
choice(
|
|
1434
|
+
...flattenKeywordGroups(TYPE_KEYWORDS),
|
|
1435
|
+
$.struct_specifier,
|
|
1436
|
+
prec.dynamic(-1, $._type_identifier),
|
|
1437
|
+
...(OPT.MACRO_EXPANSION ?
|
|
1438
|
+
[
|
|
1439
|
+
prec.dynamic(
|
|
1440
|
+
-3,
|
|
1441
|
+
alias($._macro_function_call, $.macro_invocation),
|
|
1442
|
+
),
|
|
1443
|
+
] :
|
|
1444
|
+
[]),
|
|
1445
|
+
),
|
|
1446
|
+
|
|
1447
|
+
// ── Structs ── grammar.adoc ────────────────────────────────────────
|
|
1448
|
+
|
|
1449
|
+
/**
|
|
1450
|
+
* ```bnf
|
|
1451
|
+
* struct_specifier :
|
|
1452
|
+
* STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
|
1453
|
+
* STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE
|
|
1454
|
+
* ```
|
|
1455
|
+
*
|
|
1456
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1457
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1458
|
+
*/
|
|
1459
|
+
struct_specifier: ($) =>
|
|
1460
|
+
seq(
|
|
1461
|
+
'struct',
|
|
1462
|
+
optional(field('name', $.identifier)),
|
|
1463
|
+
'{',
|
|
1464
|
+
$.field_declaration_list,
|
|
1465
|
+
'}',
|
|
1466
|
+
),
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* ```bnf
|
|
1470
|
+
* struct_declaration_list :
|
|
1471
|
+
* struct_declaration
|
|
1472
|
+
* struct_declaration_list struct_declaration
|
|
1473
|
+
* ```
|
|
1474
|
+
*
|
|
1475
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1476
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1477
|
+
*/
|
|
1478
|
+
field_declaration_list: ($) =>
|
|
1479
|
+
repeat1(
|
|
1480
|
+
choice(
|
|
1481
|
+
$.field_declaration,
|
|
1482
|
+
// Extension: preprocessor directives inside struct bodies
|
|
1483
|
+
$.preproc_call,
|
|
1484
|
+
...(OPT.MACRO_PARSING ?
|
|
1485
|
+
[
|
|
1486
|
+
$.preproc_def,
|
|
1487
|
+
$.preproc_function_def,
|
|
1488
|
+
$.preproc_undef,
|
|
1489
|
+
alias($.preproc_if_in_struct_declaration, $.preproc_if),
|
|
1490
|
+
alias($.preproc_ifdef_in_struct_declaration, $.preproc_ifdef),
|
|
1491
|
+
] :
|
|
1492
|
+
[]),
|
|
1493
|
+
),
|
|
1494
|
+
),
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* ```bnf
|
|
1498
|
+
* struct_declaration :
|
|
1499
|
+
* type_specifier struct_declarator_list SEMICOLON
|
|
1500
|
+
* type_qualifier type_specifier struct_declarator_list SEMICOLON
|
|
1501
|
+
* ```
|
|
1502
|
+
*
|
|
1503
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1504
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1505
|
+
*/
|
|
1506
|
+
field_declaration: ($) =>
|
|
1507
|
+
seq(
|
|
1508
|
+
optional($.type_qualifier),
|
|
1509
|
+
$.type_specifier,
|
|
1510
|
+
$.field_declarator_list,
|
|
1511
|
+
';',
|
|
1512
|
+
),
|
|
1513
|
+
|
|
1514
|
+
/**
|
|
1515
|
+
* ```bnf
|
|
1516
|
+
* struct_declarator_list :
|
|
1517
|
+
* struct_declarator
|
|
1518
|
+
* struct_declarator_list COMMA struct_declarator
|
|
1519
|
+
* ```
|
|
1520
|
+
*
|
|
1521
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1522
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1523
|
+
*/
|
|
1524
|
+
field_declarator_list: ($) => commaSep1($.field_declarator),
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* ```bnf
|
|
1528
|
+
* struct_declarator :
|
|
1529
|
+
* IDENTIFIER
|
|
1530
|
+
* IDENTIFIER array_specifier
|
|
1531
|
+
* ```
|
|
1532
|
+
*
|
|
1533
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1534
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1535
|
+
*/
|
|
1536
|
+
field_declarator: ($) =>
|
|
1537
|
+
seq(field('name', $.identifier), optional($.array_specifier)),
|
|
1538
|
+
|
|
1539
|
+
// ── Declarations ── grammar.adoc ───────────────────────────────────
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* ```bnf
|
|
1543
|
+
* declaration :
|
|
1544
|
+
* function_prototype SEMICOLON
|
|
1545
|
+
* init_declarator_list SEMICOLON
|
|
1546
|
+
* PRECISION precision_qualifier type_specifier SEMICOLON
|
|
1547
|
+
* type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list
|
|
1548
|
+
* RIGHT_BRACE SEMICOLON
|
|
1549
|
+
* type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list
|
|
1550
|
+
* RIGHT_BRACE IDENTIFIER SEMICOLON
|
|
1551
|
+
* type_qualifier IDENTIFIER LEFT_BRACE struct_declaration_list
|
|
1552
|
+
* RIGHT_BRACE IDENTIFIER array_specifier SEMICOLON
|
|
1553
|
+
* type_qualifier SEMICOLON
|
|
1554
|
+
* type_qualifier identifier_list SEMICOLON
|
|
1555
|
+
* ```
|
|
1556
|
+
*
|
|
1557
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1558
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1559
|
+
*/
|
|
1560
|
+
declaration: ($) =>
|
|
1561
|
+
choice(
|
|
1562
|
+
seq($.function_declarator, ';'),
|
|
1563
|
+
seq($.declarator_list, ';'),
|
|
1564
|
+
seq('precision', $.precision_qualifier, $.type_specifier, ';'),
|
|
1565
|
+
// Interface blocks
|
|
1566
|
+
seq(
|
|
1567
|
+
$.type_qualifier,
|
|
1568
|
+
field('name', $.identifier),
|
|
1569
|
+
'{',
|
|
1570
|
+
$.field_declaration_list,
|
|
1571
|
+
'}',
|
|
1572
|
+
optional(
|
|
1573
|
+
seq(
|
|
1574
|
+
field('instance_name', $.identifier),
|
|
1575
|
+
optional($.array_specifier),
|
|
1576
|
+
),
|
|
1577
|
+
),
|
|
1578
|
+
';',
|
|
1579
|
+
),
|
|
1580
|
+
seq($.type_qualifier, ';'),
|
|
1581
|
+
seq($.type_qualifier, $.identifier_list, ';'),
|
|
1582
|
+
),
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* ```bnf
|
|
1586
|
+
* identifier_list :
|
|
1587
|
+
* IDENTIFIER
|
|
1588
|
+
* identifier_list COMMA IDENTIFIER
|
|
1589
|
+
* ```
|
|
1590
|
+
*
|
|
1591
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1592
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1593
|
+
*/
|
|
1594
|
+
identifier_list: ($) => commaSep1($.identifier),
|
|
1595
|
+
|
|
1596
|
+
/**
|
|
1597
|
+
* ```bnf
|
|
1598
|
+
* function_prototype : function_declarator RIGHT_PAREN
|
|
1599
|
+
*
|
|
1600
|
+
* function_declarator :
|
|
1601
|
+
* function_header
|
|
1602
|
+
* function_header_with_parameters
|
|
1603
|
+
*
|
|
1604
|
+
* function_header_with_parameters :
|
|
1605
|
+
* function_header parameter_declaration
|
|
1606
|
+
* function_header_with_parameters COMMA parameter_declaration
|
|
1607
|
+
*
|
|
1608
|
+
* function_header :
|
|
1609
|
+
* fully_specified_type IDENTIFIER LEFT_PAREN
|
|
1610
|
+
* ```
|
|
1611
|
+
*
|
|
1612
|
+
* Tree-sitter compromise: function_prototype is inlined and its
|
|
1613
|
+
* sub-production (closing RIGHT_PAREN) collapsed here. The spec splits
|
|
1614
|
+
* LEFT_PAREN and RIGHT_PAREN across function_header and
|
|
1615
|
+
* function_prototype. They're merged here so the delimiter pair lives in
|
|
1616
|
+
* one node.
|
|
1617
|
+
*
|
|
1618
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1619
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1620
|
+
*/
|
|
1621
|
+
function_declarator: ($) =>
|
|
1622
|
+
seq(
|
|
1623
|
+
field('return_type', $.type),
|
|
1624
|
+
field('name', $.identifier),
|
|
1625
|
+
'(',
|
|
1626
|
+
optional(field('parameters', $.parameter_list)),
|
|
1627
|
+
')',
|
|
1628
|
+
),
|
|
1629
|
+
|
|
1630
|
+
/**
|
|
1631
|
+
* Tree-sitter compromise: replaces the spec's
|
|
1632
|
+
* function_header_with_parameters left-recursive chain.
|
|
1633
|
+
*
|
|
1634
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1635
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1636
|
+
*/
|
|
1637
|
+
parameter_list: ($) => commaSep1($.parameter_declaration),
|
|
1638
|
+
|
|
1639
|
+
/**
|
|
1640
|
+
* ```bnf
|
|
1641
|
+
* parameter_declaration :
|
|
1642
|
+
* type_qualifier parameter_declarator
|
|
1643
|
+
* parameter_declarator
|
|
1644
|
+
* type_qualifier parameter_type_specifier
|
|
1645
|
+
* parameter_type_specifier
|
|
1646
|
+
* ```
|
|
1647
|
+
*
|
|
1648
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1649
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1650
|
+
*/
|
|
1651
|
+
parameter_declaration: ($) =>
|
|
1652
|
+
choice(
|
|
1653
|
+
seq(
|
|
1654
|
+
optional($.type_qualifier),
|
|
1655
|
+
field('type', $.type_specifier),
|
|
1656
|
+
field('name', $.identifier),
|
|
1657
|
+
optional($.array_specifier),
|
|
1658
|
+
),
|
|
1659
|
+
seq(optional($.type_qualifier), field('type', $.type_specifier)),
|
|
1660
|
+
),
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* ```bnf
|
|
1664
|
+
* init_declarator_list :
|
|
1665
|
+
* single_declaration
|
|
1666
|
+
* init_declarator_list COMMA IDENTIFIER
|
|
1667
|
+
* init_declarator_list COMMA IDENTIFIER array_specifier
|
|
1668
|
+
* init_declarator_list COMMA IDENTIFIER array_specifier EQUAL initializer
|
|
1669
|
+
* init_declarator_list COMMA IDENTIFIER EQUAL initializer
|
|
1670
|
+
* ```
|
|
1671
|
+
*
|
|
1672
|
+
* Tree-sitter compromise: subsequent declarators (which omit the
|
|
1673
|
+
* type in the BNF) are wrapped in `declarator` nodes without a
|
|
1674
|
+
* `type` child, so every name/value pair is uniformly grouped.
|
|
1675
|
+
*
|
|
1676
|
+
* @param {GrammarSymbols<string>} $
|
|
1677
|
+
*/
|
|
1678
|
+
declarator_list: ($) =>
|
|
1679
|
+
seq(
|
|
1680
|
+
$.declarator,
|
|
1681
|
+
repeat(
|
|
1682
|
+
seq(',', alias($._subsequent_declarator, $.declarator)),
|
|
1683
|
+
),
|
|
1684
|
+
),
|
|
1685
|
+
|
|
1686
|
+
/**
|
|
1687
|
+
* ```bnf
|
|
1688
|
+
* single_declaration :
|
|
1689
|
+
* fully_specified_type
|
|
1690
|
+
* fully_specified_type IDENTIFIER
|
|
1691
|
+
* fully_specified_type IDENTIFIER array_specifier
|
|
1692
|
+
* fully_specified_type IDENTIFIER array_specifier EQUAL initializer
|
|
1693
|
+
* fully_specified_type IDENTIFIER EQUAL initializer
|
|
1694
|
+
* ```
|
|
1695
|
+
*
|
|
1696
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1697
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1698
|
+
*/
|
|
1699
|
+
declarator: ($) =>
|
|
1700
|
+
seq(
|
|
1701
|
+
$.type,
|
|
1702
|
+
optional(
|
|
1703
|
+
seq(
|
|
1704
|
+
field('name', $.identifier),
|
|
1705
|
+
optional($.array_specifier),
|
|
1706
|
+
optional(seq('=', field('value', $._initializer))),
|
|
1707
|
+
),
|
|
1708
|
+
),
|
|
1709
|
+
),
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Subsequent declarator in a comma-separated list (no type).
|
|
1713
|
+
*
|
|
1714
|
+
* @param {GrammarSymbols<string>} $
|
|
1715
|
+
*/
|
|
1716
|
+
_subsequent_declarator: ($) =>
|
|
1717
|
+
seq(
|
|
1718
|
+
field('name', $.identifier),
|
|
1719
|
+
optional($.array_specifier),
|
|
1720
|
+
optional(seq('=', field('value', $._initializer))),
|
|
1721
|
+
),
|
|
1722
|
+
|
|
1723
|
+
// ── Initializers ── grammar.adoc ───────────────────────────────────
|
|
1724
|
+
|
|
1725
|
+
/**
|
|
1726
|
+
* ```bnf
|
|
1727
|
+
* initializer :
|
|
1728
|
+
* assignment_expression
|
|
1729
|
+
* LEFT_BRACE initializer_list RIGHT_BRACE
|
|
1730
|
+
* LEFT_BRACE initializer_list COMMA RIGHT_BRACE
|
|
1731
|
+
* ```
|
|
1732
|
+
*
|
|
1733
|
+
* Hidden: transparent pass-through for expressions; the aggregate
|
|
1734
|
+
* `{ ... }` form is extracted as the visible `initializer` node.
|
|
1735
|
+
*
|
|
1736
|
+
* @param {GrammarSymbols<string>} $
|
|
1737
|
+
*/
|
|
1738
|
+
_initializer: ($) =>
|
|
1739
|
+
OPT.ESSL ?
|
|
1740
|
+
$._assignment_expression :
|
|
1741
|
+
choice($._assignment_expression, $.initializer),
|
|
1742
|
+
|
|
1743
|
+
...(OPT.ESSL ? {} : {
|
|
1744
|
+
/**
|
|
1745
|
+
* Aggregate initializer: `{ initializer_list }`. GLSL-only.
|
|
1746
|
+
*
|
|
1747
|
+
* @param {GrammarSymbols<string>} $
|
|
1748
|
+
*/
|
|
1749
|
+
initializer: ($) => seq('{', $.initializer_list, '}'),
|
|
1750
|
+
}),
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* ```bnf
|
|
1754
|
+
* initializer_list :
|
|
1755
|
+
* initializer
|
|
1756
|
+
* initializer_list COMMA initializer
|
|
1757
|
+
* ```
|
|
1758
|
+
*
|
|
1759
|
+
* Trailing comma allowed per spec (`{ initializer_list COMMA }`).
|
|
1760
|
+
* GLSL-only (ESSL has no aggregate initializers).
|
|
1761
|
+
*
|
|
1762
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1763
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1764
|
+
*/
|
|
1765
|
+
...(OPT.ESSL ? {} : {
|
|
1766
|
+
initializer_list: ($) => seq(commaSep1($._initializer), optional(',')),
|
|
1767
|
+
}),
|
|
1768
|
+
|
|
1769
|
+
// ── Statements ── grammar.adoc ────────────────────────────────────
|
|
1770
|
+
|
|
1771
|
+
/**
|
|
1772
|
+
* ```bnf
|
|
1773
|
+
* declaration_statement : declaration
|
|
1774
|
+
* ```
|
|
1775
|
+
*
|
|
1776
|
+
* Hidden: 1:1 pass-through so local_declaration appears directly.
|
|
1777
|
+
*
|
|
1778
|
+
* @param {GrammarSymbols<string>} $
|
|
1779
|
+
*/
|
|
1780
|
+
_declaration_statement: ($) => prec.dynamic(-1, $.local_declaration),
|
|
1781
|
+
|
|
1782
|
+
/**
|
|
1783
|
+
* Block-scope declaration form.
|
|
1784
|
+
*
|
|
1785
|
+
* This reuses the ordinary declarator list instead of splitting block
|
|
1786
|
+
* declarations into a separate macro-filtered tree.
|
|
1787
|
+
*
|
|
1788
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1789
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1790
|
+
*/
|
|
1791
|
+
local_declaration: ($) => seq($.declarator_list, ';'),
|
|
1792
|
+
|
|
1793
|
+
/**
|
|
1794
|
+
* ```bnf
|
|
1795
|
+
* statement :
|
|
1796
|
+
* compound_statement
|
|
1797
|
+
* simple_statement
|
|
1798
|
+
* ```
|
|
1799
|
+
*
|
|
1800
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1801
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1802
|
+
*/
|
|
1803
|
+
statement: ($) => choice($.compound_statement, $.simple_statement),
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* ```bnf
|
|
1807
|
+
* simple_statement :
|
|
1808
|
+
* declaration_statement
|
|
1809
|
+
* expression_statement
|
|
1810
|
+
* selection_statement
|
|
1811
|
+
* switch_statement
|
|
1812
|
+
* case_label
|
|
1813
|
+
* iteration_statement
|
|
1814
|
+
* jump_statement
|
|
1815
|
+
* ```
|
|
1816
|
+
*
|
|
1817
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1818
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1819
|
+
*/
|
|
1820
|
+
simple_statement: ($) =>
|
|
1821
|
+
choice(
|
|
1822
|
+
$.expression_statement,
|
|
1823
|
+
$._declaration_statement,
|
|
1824
|
+
$.if_statement,
|
|
1825
|
+
$.switch_statement,
|
|
1826
|
+
$.case_label,
|
|
1827
|
+
$._iteration_statement,
|
|
1828
|
+
$._jump_statement,
|
|
1829
|
+
...extRule($, 'demote_statement'),
|
|
1830
|
+
// Extension: preprocessor directives in statement position
|
|
1831
|
+
$.preproc_call,
|
|
1832
|
+
...(OPT.MACRO_PARSING ?
|
|
1833
|
+
[
|
|
1834
|
+
$.preproc_def,
|
|
1835
|
+
$.preproc_function_def,
|
|
1836
|
+
$.preproc_undef,
|
|
1837
|
+
alias($.preproc_if_in_statement, $.preproc_if),
|
|
1838
|
+
alias($.preproc_ifdef_in_statement, $.preproc_ifdef),
|
|
1839
|
+
] :
|
|
1840
|
+
[]),
|
|
1841
|
+
),
|
|
1842
|
+
|
|
1843
|
+
/**
|
|
1844
|
+
* ```bnf
|
|
1845
|
+
* compound_statement :
|
|
1846
|
+
* LEFT_BRACE RIGHT_BRACE
|
|
1847
|
+
* LEFT_BRACE statement_list RIGHT_BRACE
|
|
1848
|
+
* ```
|
|
1849
|
+
*
|
|
1850
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1851
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1852
|
+
*/
|
|
1853
|
+
compound_statement: ($) => seq('{', optional($.statement_list), '}'),
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* ```bnf
|
|
1857
|
+
* statement_no_new_scope :
|
|
1858
|
+
* compound_statement_no_new_scope
|
|
1859
|
+
* simple_statement
|
|
1860
|
+
* ```
|
|
1861
|
+
*
|
|
1862
|
+
* Hidden: identical to `statement` (a supertype); tree-sitter does
|
|
1863
|
+
* not enforce scoping so the distinction adds no value.
|
|
1864
|
+
*
|
|
1865
|
+
* @param {GrammarSymbols<string>} $
|
|
1866
|
+
*/
|
|
1867
|
+
_statement_no_new_scope: ($) =>
|
|
1868
|
+
choice($.compound_statement, $.simple_statement),
|
|
1869
|
+
|
|
1870
|
+
/**
|
|
1871
|
+
* ```bnf
|
|
1872
|
+
* statement_list :
|
|
1873
|
+
* statement
|
|
1874
|
+
* statement_list statement
|
|
1875
|
+
* ```
|
|
1876
|
+
*
|
|
1877
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1878
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1879
|
+
*/
|
|
1880
|
+
statement_list: ($) => repeat1($.statement),
|
|
1881
|
+
|
|
1882
|
+
/**
|
|
1883
|
+
* ```bnf
|
|
1884
|
+
* expression_statement :
|
|
1885
|
+
* SEMICOLON
|
|
1886
|
+
* expression SEMICOLON
|
|
1887
|
+
* ```
|
|
1888
|
+
*
|
|
1889
|
+
* Extension: when OPT.MACRO_EXPANSION is enabled, a function-like
|
|
1890
|
+
* macro invocation may also stand alone as a semicolonless line.
|
|
1891
|
+
* This stays low-priority so real GLSL expression statements win.
|
|
1892
|
+
*
|
|
1893
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1894
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1895
|
+
*/
|
|
1896
|
+
expression_statement: ($) =>
|
|
1897
|
+
choice(
|
|
1898
|
+
prec.dynamic(1, seq(optional($._expression), ';')),
|
|
1899
|
+
...(OPT.MACRO_EXPANSION ?
|
|
1900
|
+
[prec.dynamic(-2, alias($._macro_function_call, $.function_call))] :
|
|
1901
|
+
[]),
|
|
1902
|
+
),
|
|
1903
|
+
|
|
1904
|
+
/**
|
|
1905
|
+
* ```bnf
|
|
1906
|
+
* selection_statement :
|
|
1907
|
+
* IF LEFT_PAREN expression RIGHT_PAREN
|
|
1908
|
+
* selection_rest_statement
|
|
1909
|
+
*
|
|
1910
|
+
* selection_rest_statement :
|
|
1911
|
+
* statement ELSE statement
|
|
1912
|
+
* statement
|
|
1913
|
+
* ```
|
|
1914
|
+
*
|
|
1915
|
+
* Tree-sitter compromise: selection_rest_statement is inlined.
|
|
1916
|
+
*
|
|
1917
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1918
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1919
|
+
*/
|
|
1920
|
+
if_statement: ($) =>
|
|
1921
|
+
prec.right(
|
|
1922
|
+
seq(
|
|
1923
|
+
'if',
|
|
1924
|
+
'(',
|
|
1925
|
+
field('condition', $._expression),
|
|
1926
|
+
')',
|
|
1927
|
+
field('consequence', $.statement),
|
|
1928
|
+
optional(field('alternative', $.else_clause)),
|
|
1929
|
+
),
|
|
1930
|
+
),
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* ```bnf
|
|
1934
|
+
* selection_rest_statement : statement ELSE statement | statement
|
|
1935
|
+
* ```
|
|
1936
|
+
*
|
|
1937
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1938
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1939
|
+
*/
|
|
1940
|
+
else_clause: ($) => seq('else', $.statement),
|
|
1941
|
+
|
|
1942
|
+
/**
|
|
1943
|
+
* ```bnf
|
|
1944
|
+
* condition :
|
|
1945
|
+
* expression
|
|
1946
|
+
* fully_specified_type IDENTIFIER EQUAL initializer
|
|
1947
|
+
* ```
|
|
1948
|
+
*
|
|
1949
|
+
* Hidden: transparent pass-through for expressions; the
|
|
1950
|
+
* declaration form is extracted as the visible `condition`
|
|
1951
|
+
* node (e.g. `for (int i = 0; ...)`).
|
|
1952
|
+
*
|
|
1953
|
+
* @param {GrammarSymbols<string>} $
|
|
1954
|
+
*/
|
|
1955
|
+
_condition: ($) =>
|
|
1956
|
+
choice(
|
|
1957
|
+
$._expression,
|
|
1958
|
+
$.condition,
|
|
1959
|
+
),
|
|
1960
|
+
|
|
1961
|
+
/**
|
|
1962
|
+
* Declaration inside a for/while condition: `type name = init`.
|
|
1963
|
+
*
|
|
1964
|
+
* @param {GrammarSymbols<string>} $
|
|
1965
|
+
*/
|
|
1966
|
+
condition: ($) =>
|
|
1967
|
+
seq($.type, field('name', $.identifier), '=', $._initializer),
|
|
1968
|
+
|
|
1969
|
+
/**
|
|
1970
|
+
* ```bnf
|
|
1971
|
+
* switch_statement :
|
|
1972
|
+
* SWITCH LEFT_PAREN expression RIGHT_PAREN
|
|
1973
|
+
* LEFT_BRACE switch_statement_list RIGHT_BRACE
|
|
1974
|
+
*
|
|
1975
|
+
* switch_statement_list :
|
|
1976
|
+
* /* empty * /
|
|
1977
|
+
* statement_list
|
|
1978
|
+
* ```
|
|
1979
|
+
*
|
|
1980
|
+
* Tree-sitter compromise: switch_statement_list is inlined
|
|
1981
|
+
* as optional(statement_list).
|
|
1982
|
+
*
|
|
1983
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
1984
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
1985
|
+
*/
|
|
1986
|
+
switch_statement: ($) =>
|
|
1987
|
+
seq(
|
|
1988
|
+
'switch',
|
|
1989
|
+
'(',
|
|
1990
|
+
field('condition', $._expression),
|
|
1991
|
+
')',
|
|
1992
|
+
'{',
|
|
1993
|
+
optional($.statement_list),
|
|
1994
|
+
'}',
|
|
1995
|
+
),
|
|
1996
|
+
|
|
1997
|
+
/**
|
|
1998
|
+
* ```bnf
|
|
1999
|
+
* case_label :
|
|
2000
|
+
* CASE expression COLON
|
|
2001
|
+
* DEFAULT COLON
|
|
2002
|
+
* ```
|
|
2003
|
+
*
|
|
2004
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2005
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2006
|
+
*/
|
|
2007
|
+
case_label: ($) =>
|
|
2008
|
+
choice(
|
|
2009
|
+
seq('case', field('value', $._expression), ':'),
|
|
2010
|
+
seq('default', ':'),
|
|
2011
|
+
),
|
|
2012
|
+
|
|
2013
|
+
/**
|
|
2014
|
+
* ```bnf
|
|
2015
|
+
* iteration_statement :
|
|
2016
|
+
* WHILE LEFT_PAREN condition RIGHT_PAREN
|
|
2017
|
+
* statement_no_new_scope
|
|
2018
|
+
* DO statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON
|
|
2019
|
+
* FOR LEFT_PAREN for_init_statement for_rest_statement
|
|
2020
|
+
* RIGHT_PAREN statement_no_new_scope
|
|
2021
|
+
* ```
|
|
2022
|
+
*
|
|
2023
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2024
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2025
|
+
*/
|
|
2026
|
+
_iteration_statement: ($) =>
|
|
2027
|
+
choice($.while_statement, $.do_statement, $.for_statement),
|
|
2028
|
+
|
|
2029
|
+
/**
|
|
2030
|
+
* ```bnf
|
|
2031
|
+
* iteration_statement : WHILE LEFT_PAREN condition RIGHT_PAREN
|
|
2032
|
+
* statement_no_new_scope
|
|
2033
|
+
* ```
|
|
2034
|
+
*
|
|
2035
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2036
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2037
|
+
*/
|
|
2038
|
+
while_statement: ($) =>
|
|
2039
|
+
seq(
|
|
2040
|
+
'while',
|
|
2041
|
+
'(',
|
|
2042
|
+
field('condition', $._condition),
|
|
2043
|
+
')',
|
|
2044
|
+
field('body', $._statement_no_new_scope),
|
|
2045
|
+
),
|
|
2046
|
+
|
|
2047
|
+
/**
|
|
2048
|
+
* ```bnf
|
|
2049
|
+
* iteration_statement : DO statement WHILE LEFT_PAREN expression
|
|
2050
|
+
* RIGHT_PAREN SEMICOLON
|
|
2051
|
+
* ```
|
|
2052
|
+
*
|
|
2053
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2054
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2055
|
+
*/
|
|
2056
|
+
do_statement: ($) =>
|
|
2057
|
+
seq(
|
|
2058
|
+
'do',
|
|
2059
|
+
field('body', $.statement),
|
|
2060
|
+
'while',
|
|
2061
|
+
'(',
|
|
2062
|
+
field('condition', $._expression),
|
|
2063
|
+
')',
|
|
2064
|
+
';',
|
|
2065
|
+
),
|
|
2066
|
+
|
|
2067
|
+
/**
|
|
2068
|
+
* ```bnf
|
|
2069
|
+
* iteration_statement : FOR LEFT_PAREN for_init_statement
|
|
2070
|
+
* for_rest_statement RIGHT_PAREN statement_no_new_scope
|
|
2071
|
+
*
|
|
2072
|
+
* for_init_statement :
|
|
2073
|
+
* expression_statement | declaration_statement
|
|
2074
|
+
*
|
|
2075
|
+
* for_rest_statement :
|
|
2076
|
+
* conditionopt SEMICOLON
|
|
2077
|
+
* conditionopt SEMICOLON expression
|
|
2078
|
+
*
|
|
2079
|
+
* conditionopt : /* empty * / | condition
|
|
2080
|
+
* ```
|
|
2081
|
+
*
|
|
2082
|
+
* Tree-sitter compromise: for_init_statement, for_rest_statement,
|
|
2083
|
+
* and conditionopt are inlined.
|
|
2084
|
+
*
|
|
2085
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2086
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2087
|
+
*/
|
|
2088
|
+
for_statement: ($) =>
|
|
2089
|
+
seq(
|
|
2090
|
+
'for',
|
|
2091
|
+
'(',
|
|
2092
|
+
field(
|
|
2093
|
+
'initializer',
|
|
2094
|
+
choice($.expression_statement, $._declaration_statement),
|
|
2095
|
+
),
|
|
2096
|
+
field('condition', optional($._condition)),
|
|
2097
|
+
';',
|
|
2098
|
+
field('update', optional($._expression)),
|
|
2099
|
+
')',
|
|
2100
|
+
field('body', $._statement_no_new_scope),
|
|
2101
|
+
),
|
|
2102
|
+
|
|
2103
|
+
/**
|
|
2104
|
+
* ```bnf
|
|
2105
|
+
* jump_statement :
|
|
2106
|
+
* CONTINUE SEMICOLON
|
|
2107
|
+
* BREAK SEMICOLON
|
|
2108
|
+
* RETURN SEMICOLON
|
|
2109
|
+
* RETURN expression SEMICOLON
|
|
2110
|
+
* DISCARD SEMICOLON
|
|
2111
|
+
* ```
|
|
2112
|
+
*
|
|
2113
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2114
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2115
|
+
*/
|
|
2116
|
+
_jump_statement: ($) =>
|
|
2117
|
+
choice(
|
|
2118
|
+
$.continue_statement,
|
|
2119
|
+
$.break_statement,
|
|
2120
|
+
$.return_statement,
|
|
2121
|
+
$.discard_statement,
|
|
2122
|
+
...extRule($, 'terminate_invocation_statement'),
|
|
2123
|
+
),
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* ```bnf
|
|
2127
|
+
* jump_statement : CONTINUE SEMICOLON
|
|
2128
|
+
* ```
|
|
2129
|
+
*
|
|
2130
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2131
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2132
|
+
*/
|
|
2133
|
+
continue_statement: (_) => seq('continue', ';'),
|
|
2134
|
+
|
|
2135
|
+
/**
|
|
2136
|
+
* ```bnf
|
|
2137
|
+
* jump_statement : BREAK SEMICOLON
|
|
2138
|
+
* ```
|
|
2139
|
+
*
|
|
2140
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2141
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2142
|
+
*/
|
|
2143
|
+
break_statement: (_) => seq('break', ';'),
|
|
2144
|
+
|
|
2145
|
+
/**
|
|
2146
|
+
* ```bnf
|
|
2147
|
+
* jump_statement : RETURN SEMICOLON | RETURN expression SEMICOLON
|
|
2148
|
+
* ```
|
|
2149
|
+
*
|
|
2150
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2151
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2152
|
+
*/
|
|
2153
|
+
return_statement: ($) => seq('return', optional($._expression), ';'),
|
|
2154
|
+
|
|
2155
|
+
/**
|
|
2156
|
+
* ```bnf
|
|
2157
|
+
* jump_statement : DISCARD SEMICOLON
|
|
2158
|
+
* ```
|
|
2159
|
+
*
|
|
2160
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2161
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2162
|
+
*/
|
|
2163
|
+
discard_statement: (_) => seq('discard', ';'),
|
|
2164
|
+
|
|
2165
|
+
// ── Lexical ── basics.adoc ─────────────────────────────────────────
|
|
2166
|
+
|
|
2167
|
+
/**
|
|
2168
|
+
* ```bnf
|
|
2169
|
+
* identifier :
|
|
2170
|
+
* nondigit
|
|
2171
|
+
* identifier nondigit
|
|
2172
|
+
* identifier digit
|
|
2173
|
+
* nondigit : one of
|
|
2174
|
+
* _ a-z A-Z
|
|
2175
|
+
* digit : one of
|
|
2176
|
+
* 0-9
|
|
2177
|
+
* ```
|
|
2178
|
+
*
|
|
2179
|
+
* Source: specification/chapters/basics.adoc §Identifiers
|
|
2180
|
+
*
|
|
2181
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2182
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2183
|
+
*/
|
|
2184
|
+
identifier: (_) => /[a-zA-Z_][a-zA-Z0-9_]*/,
|
|
2185
|
+
|
|
2186
|
+
/**
|
|
2187
|
+
* Extension of spec TYPE_NAME handling:
|
|
2188
|
+
* Tree-sitter cannot know whether an identifier denotes a user-defined
|
|
2189
|
+
* type or an ordinary variable/function name, so type-name uses are
|
|
2190
|
+
* accepted structurally via an identifier alias.
|
|
2191
|
+
*
|
|
2192
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2193
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2194
|
+
*/
|
|
2195
|
+
_type_identifier: ($) => alias($.identifier, $.type_identifier),
|
|
2196
|
+
|
|
2197
|
+
/**
|
|
2198
|
+
* Comments (specification/chapters/basics.adoc §Comments):
|
|
2199
|
+
* Line comments: // to end of line
|
|
2200
|
+
* Block comments: /* to * /
|
|
2201
|
+
* Comments cannot be nested.
|
|
2202
|
+
*
|
|
2203
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2204
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2205
|
+
*/
|
|
2206
|
+
comment: (_) =>
|
|
2207
|
+
token(
|
|
2208
|
+
choice(
|
|
2209
|
+
seq('//', /(\\+(.|\r?\n)|[^\\\n])*/),
|
|
2210
|
+
seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/'),
|
|
2211
|
+
),
|
|
2212
|
+
),
|
|
2213
|
+
|
|
2214
|
+
/**
|
|
2215
|
+
* ```bnf
|
|
2216
|
+
* integer-constant :
|
|
2217
|
+
* decimal-constant integer-suffix_opt
|
|
2218
|
+
* octal-constant integer-suffix_opt
|
|
2219
|
+
* hexadecimal-constant integer-suffix_opt
|
|
2220
|
+
* integer-suffix : one of
|
|
2221
|
+
* u U
|
|
2222
|
+
* decimal-constant :
|
|
2223
|
+
* nonzero-digit
|
|
2224
|
+
* decimal-constant digit
|
|
2225
|
+
* octal-constant :
|
|
2226
|
+
* 0
|
|
2227
|
+
* octal-constant octal-digit
|
|
2228
|
+
* hexadecimal-constant :
|
|
2229
|
+
* 0x hexadecimal-digit
|
|
2230
|
+
* 0X hexadecimal-digit
|
|
2231
|
+
* hexadecimal-constant hexadecimal-digit
|
|
2232
|
+
* ```
|
|
2233
|
+
*
|
|
2234
|
+
* ```bnf
|
|
2235
|
+
* floating-constant :
|
|
2236
|
+
* fractional-constant exponent-part_opt floating-suffix_opt
|
|
2237
|
+
* digit-sequence exponent-part floating-suffix_opt
|
|
2238
|
+
* fractional-constant :
|
|
2239
|
+
* digit-sequence . digit-sequence
|
|
2240
|
+
* digit-sequence .
|
|
2241
|
+
* . digit-sequence
|
|
2242
|
+
* exponent-part :
|
|
2243
|
+
* e sign_opt digit-sequence
|
|
2244
|
+
* E sign_opt digit-sequence
|
|
2245
|
+
* sign : one of
|
|
2246
|
+
* + -
|
|
2247
|
+
* floating-suffix : one of
|
|
2248
|
+
* f F lf LF
|
|
2249
|
+
* ```
|
|
2250
|
+
*
|
|
2251
|
+
* Source: specification/chapters/variables.adoc §Integers, §Floats
|
|
2252
|
+
*
|
|
2253
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2254
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2255
|
+
*/
|
|
2256
|
+
number_literal: (_) => {
|
|
2257
|
+
const decimalDigits = /[0-9]+/;
|
|
2258
|
+
const octalDigits = /[0-7]+/;
|
|
2259
|
+
const hexDigits = /[0-9a-fA-F]+/;
|
|
2260
|
+
|
|
2261
|
+
const integerConstant = choice(
|
|
2262
|
+
seq(/[1-9]/, optional(decimalDigits)), // decimal-constant
|
|
2263
|
+
seq('0', optional(octalDigits)), // octal-constant (includes bare 0)
|
|
2264
|
+
seq(choice('0x', '0X'), hexDigits), // hexadecimal-constant
|
|
2265
|
+
);
|
|
2266
|
+
|
|
2267
|
+
const exponentPart = seq(
|
|
2268
|
+
choice('e', 'E'),
|
|
2269
|
+
optional(choice('+', '-')),
|
|
2270
|
+
decimalDigits,
|
|
2271
|
+
);
|
|
2272
|
+
|
|
2273
|
+
const fractionalConstant = choice(
|
|
2274
|
+
seq(decimalDigits, '.', optional(decimalDigits)),
|
|
2275
|
+
seq('.', decimalDigits),
|
|
2276
|
+
);
|
|
2277
|
+
|
|
2278
|
+
const floatingConstant = choice(
|
|
2279
|
+
seq(fractionalConstant, optional(exponentPart)),
|
|
2280
|
+
seq(decimalDigits, exponentPart),
|
|
2281
|
+
);
|
|
2282
|
+
|
|
2283
|
+
return token(
|
|
2284
|
+
choice(
|
|
2285
|
+
seq(integerConstant, optional(choice('u', 'U'))),
|
|
2286
|
+
seq(floatingConstant, optional(choice('f', 'F', 'lf', 'LF'))),
|
|
2287
|
+
),
|
|
2288
|
+
);
|
|
2289
|
+
},
|
|
2290
|
+
|
|
2291
|
+
// ── Preprocessor ── basics.adoc §Preprocessor ──────────────────────
|
|
2292
|
+
|
|
2293
|
+
/**
|
|
2294
|
+
* Extension: #version directive.
|
|
2295
|
+
*
|
|
2296
|
+
* Not a formal BNF production in grammar.adoc, but defined in
|
|
2297
|
+
* basics.adoc §Preprocessor / §Version Declaration.
|
|
2298
|
+
* Form: #version <number> [profile]
|
|
2299
|
+
* where profile is one of: core, compatibility, es
|
|
2300
|
+
*
|
|
2301
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2302
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2303
|
+
*/
|
|
2304
|
+
preproc_version: (_) => seq(/#[ \t]*version/, /[^\n]*/),
|
|
2305
|
+
|
|
2306
|
+
/**
|
|
2307
|
+
* Extension: catch-all for unknown preprocessor directives.
|
|
2308
|
+
* When OPT.MACRO_PARSING is off, all directives (except #version
|
|
2309
|
+
* and bare #) fall through to this rule.
|
|
2310
|
+
*
|
|
2311
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2312
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2313
|
+
*/
|
|
2314
|
+
preproc_call: ($) =>
|
|
2315
|
+
seq(
|
|
2316
|
+
field('directive', $.preproc_directive),
|
|
2317
|
+
field('argument', optional($.preproc_arg)),
|
|
2318
|
+
token.immediate(/\r?\n/),
|
|
2319
|
+
),
|
|
2320
|
+
|
|
2321
|
+
/**
|
|
2322
|
+
* basics.adoc §Preprocessor:
|
|
2323
|
+
* "The number sign (#) on a line by itself is ignored."
|
|
2324
|
+
*
|
|
2325
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2326
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2327
|
+
*/
|
|
2328
|
+
preproc_nothing: (_) => seq(/#[ \t]*/, token.immediate(/\r?\n/)),
|
|
2329
|
+
|
|
2330
|
+
/**
|
|
2331
|
+
* Extension: opaque text payload for preprocessor directives.
|
|
2332
|
+
* Low precedence so structured tokens are preferred when possible.
|
|
2333
|
+
*
|
|
2334
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2335
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2336
|
+
*/
|
|
2337
|
+
preproc_arg: (_) => token(prec(-1, /\S([^/\n]|\/[^*]|\\\r?\n)*/)),
|
|
2338
|
+
|
|
2339
|
+
/**
|
|
2340
|
+
* Extension: directive token for preproc_call catch-all.
|
|
2341
|
+
* Matches `#` followed by an identifier (e.g. `#include`, `#pragma`).
|
|
2342
|
+
*
|
|
2343
|
+
* @param {GrammarSymbols<string>} _ Grammar symbols.
|
|
2344
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2345
|
+
*/
|
|
2346
|
+
preproc_directive: (_) => /#[ \t]*[a-zA-Z0-9]\w*/,
|
|
2347
|
+
|
|
2348
|
+
/**
|
|
2349
|
+
* Top-level translation-unit items, including preprocessor directives.
|
|
2350
|
+
*
|
|
2351
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2352
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2353
|
+
*/
|
|
2354
|
+
_top_level_item: ($) =>
|
|
2355
|
+
choice(
|
|
2356
|
+
$._external_declaration,
|
|
2357
|
+
$.preproc_version,
|
|
2358
|
+
$.preproc_call,
|
|
2359
|
+
$.preproc_nothing,
|
|
2360
|
+
...(OPT.MACRO_PARSING ?
|
|
2361
|
+
[
|
|
2362
|
+
...(OPT.MULTILINGUAL ?
|
|
2363
|
+
[
|
|
2364
|
+
$.preproc_language_if,
|
|
2365
|
+
$.preproc_language_ifdef,
|
|
2366
|
+
$.preproc_language_ifndef,
|
|
2367
|
+
] :
|
|
2368
|
+
[]),
|
|
2369
|
+
$.preproc_def,
|
|
2370
|
+
$.preproc_function_def,
|
|
2371
|
+
$.preproc_undef,
|
|
2372
|
+
$.preproc_error,
|
|
2373
|
+
$.preproc_pragma,
|
|
2374
|
+
$.preproc_extension,
|
|
2375
|
+
$.preproc_line,
|
|
2376
|
+
$.preproc_if,
|
|
2377
|
+
$.preproc_ifdef,
|
|
2378
|
+
] :
|
|
2379
|
+
[]),
|
|
2380
|
+
),
|
|
2381
|
+
},
|
|
2382
|
+
|
|
2383
|
+
// ── OPT.MACRO_PARSING ──────────────────────────────────────────────
|
|
2384
|
+
// Structured preprocessor directive parsing: specific rules for
|
|
2385
|
+
// #define, #undef, #if/#ifdef/#else/#endif, #error, #pragma,
|
|
2386
|
+
// #extension, #line, and preprocessor condition expressions.
|
|
2387
|
+
// When disabled, all directives (except #version and bare #)
|
|
2388
|
+
// fall through to the opaque preproc_call catch-all.
|
|
2389
|
+
|
|
2390
|
+
OPT.MACRO_PARSING ?
|
|
2391
|
+
{
|
|
2392
|
+
/**
|
|
2393
|
+
* Extension: #define directive.
|
|
2394
|
+
*
|
|
2395
|
+
* basics.adoc §Preprocessor: "#define and #undef functionality are
|
|
2396
|
+
* defined as is standard for C++ preprocessors for macro definitions
|
|
2397
|
+
* both with and without macro parameters."
|
|
2398
|
+
*
|
|
2399
|
+
* @param {*} $ Grammar symbols.
|
|
2400
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2401
|
+
*/
|
|
2402
|
+
preproc_def: ($) =>
|
|
2403
|
+
seq(
|
|
2404
|
+
preprocessor('define'),
|
|
2405
|
+
field('name', $.identifier),
|
|
2406
|
+
field('value', optional($.preproc_arg)),
|
|
2407
|
+
token.immediate(/\r?\n/),
|
|
2408
|
+
),
|
|
2409
|
+
|
|
2410
|
+
/**
|
|
2411
|
+
* Extension: #define with parameters (function-like macro).
|
|
2412
|
+
*
|
|
2413
|
+
* @param {*} $ Grammar symbols.
|
|
2414
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2415
|
+
*/
|
|
2416
|
+
preproc_function_def: ($) =>
|
|
2417
|
+
seq(
|
|
2418
|
+
preprocessor('define'),
|
|
2419
|
+
field('name', $.identifier),
|
|
2420
|
+
field('parameters', $.preproc_params),
|
|
2421
|
+
field('value', optional($.preproc_arg)),
|
|
2422
|
+
token.immediate(/\r?\n/),
|
|
2423
|
+
),
|
|
2424
|
+
|
|
2425
|
+
/**
|
|
2426
|
+
* Extension: parameter list for function-like #define.
|
|
2427
|
+
* token.immediate('(') ensures no space between macro name and '('.
|
|
2428
|
+
*
|
|
2429
|
+
* @param {*} $ Grammar symbols.
|
|
2430
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2431
|
+
*/
|
|
2432
|
+
preproc_params: ($) =>
|
|
2433
|
+
seq(
|
|
2434
|
+
token.immediate('('),
|
|
2435
|
+
commaSep(choice($.identifier, '...')),
|
|
2436
|
+
')',
|
|
2437
|
+
),
|
|
2438
|
+
|
|
2439
|
+
/**
|
|
2440
|
+
* Extension: #undef directive.
|
|
2441
|
+
*
|
|
2442
|
+
* @param {*} $ Grammar symbols.
|
|
2443
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2444
|
+
*/
|
|
2445
|
+
preproc_undef: ($) =>
|
|
2446
|
+
seq(
|
|
2447
|
+
preprocessor('undef'),
|
|
2448
|
+
field('name', $.identifier),
|
|
2449
|
+
token.immediate(/\r?\n/),
|
|
2450
|
+
),
|
|
2451
|
+
|
|
2452
|
+
/**
|
|
2453
|
+
* Extension: #error directive.
|
|
2454
|
+
*
|
|
2455
|
+
* basics.adoc §Preprocessor: "The message will be the tokens
|
|
2456
|
+
* following the #error directive, up to the first new-line."
|
|
2457
|
+
*
|
|
2458
|
+
* @param {*} $ Grammar symbols.
|
|
2459
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2460
|
+
*/
|
|
2461
|
+
preproc_error: ($) =>
|
|
2462
|
+
seq(
|
|
2463
|
+
preprocessor('error'),
|
|
2464
|
+
field('message', optional($.preproc_arg)),
|
|
2465
|
+
token.immediate(/\r?\n/),
|
|
2466
|
+
),
|
|
2467
|
+
|
|
2468
|
+
/**
|
|
2469
|
+
* Extension: #pragma directive.
|
|
2470
|
+
*
|
|
2471
|
+
* basics.adoc §Preprocessor: "Tokens following #pragma are not
|
|
2472
|
+
* subject to preprocessor macro expansion."
|
|
2473
|
+
*
|
|
2474
|
+
* @param {*} $ Grammar symbols.
|
|
2475
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2476
|
+
*/
|
|
2477
|
+
preproc_pragma: ($) =>
|
|
2478
|
+
seq(
|
|
2479
|
+
preprocessor('pragma'),
|
|
2480
|
+
field('argument', optional($.preproc_arg)),
|
|
2481
|
+
token.immediate(/\r?\n/),
|
|
2482
|
+
),
|
|
2483
|
+
|
|
2484
|
+
/**
|
|
2485
|
+
* Extension: #extension directive.
|
|
2486
|
+
*
|
|
2487
|
+
* basics.adoc §Preprocessor:
|
|
2488
|
+
* Form: #extension <extension_name> : <behavior>
|
|
2489
|
+
* #extension all : <behavior>
|
|
2490
|
+
*
|
|
2491
|
+
* @param {*} $ Grammar symbols.
|
|
2492
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2493
|
+
*/
|
|
2494
|
+
preproc_extension: ($) =>
|
|
2495
|
+
seq(
|
|
2496
|
+
preprocessor('extension'),
|
|
2497
|
+
field('argument', optional($.preproc_arg)),
|
|
2498
|
+
token.immediate(/\r?\n/),
|
|
2499
|
+
),
|
|
2500
|
+
|
|
2501
|
+
/**
|
|
2502
|
+
* Extension: #line directive.
|
|
2503
|
+
*
|
|
2504
|
+
* basics.adoc §Preprocessor:
|
|
2505
|
+
* Form: #line <line>
|
|
2506
|
+
* #line <line> <source-string-number>
|
|
2507
|
+
*
|
|
2508
|
+
* @param {*} $ Grammar symbols.
|
|
2509
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2510
|
+
*/
|
|
2511
|
+
preproc_line: ($) =>
|
|
2512
|
+
seq(
|
|
2513
|
+
preprocessor('line'),
|
|
2514
|
+
field('argument', optional($.preproc_arg)),
|
|
2515
|
+
token.immediate(/\r?\n/),
|
|
2516
|
+
),
|
|
2517
|
+
|
|
2518
|
+
/**
|
|
2519
|
+
* Preprocessor expressions for #if / #elif conditions.
|
|
2520
|
+
*
|
|
2521
|
+
* basics.adoc §Preprocessor: "Expressions following #if and #elif
|
|
2522
|
+
* are further restricted to expressions operating on literal integer
|
|
2523
|
+
* constants, plus identifiers consumed by the defined operator."
|
|
2524
|
+
*
|
|
2525
|
+
* @param {*} $ Grammar symbols.
|
|
2526
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2527
|
+
*/
|
|
2528
|
+
_preproc_expression: ($) =>
|
|
2529
|
+
choice(
|
|
2530
|
+
$.identifier,
|
|
2531
|
+
$.number_literal,
|
|
2532
|
+
$.preproc_defined,
|
|
2533
|
+
alias($.preproc_unary_expression, $.unary_expression),
|
|
2534
|
+
alias($.preproc_binary_expression, $.binary_expression),
|
|
2535
|
+
alias(
|
|
2536
|
+
$.preproc_parenthesized_expression,
|
|
2537
|
+
$.parenthesized_expression,
|
|
2538
|
+
),
|
|
2539
|
+
),
|
|
2540
|
+
|
|
2541
|
+
/**
|
|
2542
|
+
* Extension: parenthesized grouping in preprocessor expressions.
|
|
2543
|
+
* Aliased to parenthesized_expression in the tree.
|
|
2544
|
+
*
|
|
2545
|
+
* @param {*} $ Grammar symbols.
|
|
2546
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2547
|
+
*/
|
|
2548
|
+
preproc_parenthesized_expression: ($) =>
|
|
2549
|
+
seq('(', $._preproc_expression, ')'),
|
|
2550
|
+
|
|
2551
|
+
/**
|
|
2552
|
+
* ```bnf
|
|
2553
|
+
* defined identifier
|
|
2554
|
+
* defined ( identifier )
|
|
2555
|
+
* ```
|
|
2556
|
+
*
|
|
2557
|
+
* Source: basics.adoc §Preprocessor
|
|
2558
|
+
*
|
|
2559
|
+
* @param {GrammarSymbols<string>} $ Grammar symbols.
|
|
2560
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2561
|
+
*/
|
|
2562
|
+
preproc_defined: ($) =>
|
|
2563
|
+
choice(
|
|
2564
|
+
prec(1, seq('defined', '(', $.identifier, ')')),
|
|
2565
|
+
seq('defined', $.identifier),
|
|
2566
|
+
),
|
|
2567
|
+
|
|
2568
|
+
/**
|
|
2569
|
+
* Extension: unary operators in preprocessor expressions.
|
|
2570
|
+
* basics.adoc §Preprocessor allows !, ~, -, + on integer constants.
|
|
2571
|
+
* Aliased to unary_expression in the tree.
|
|
2572
|
+
*
|
|
2573
|
+
* @param {*} $ Grammar symbols.
|
|
2574
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2575
|
+
*/
|
|
2576
|
+
preproc_unary_expression: ($) =>
|
|
2577
|
+
prec.left(
|
|
2578
|
+
14,
|
|
2579
|
+
seq(
|
|
2580
|
+
field('operator', choice('!', '~', '-', '+')),
|
|
2581
|
+
field('argument', $._preproc_expression),
|
|
2582
|
+
),
|
|
2583
|
+
),
|
|
2584
|
+
|
|
2585
|
+
/**
|
|
2586
|
+
* Preprocessor binary operators (basics.adoc §Preprocessor, precedence table):
|
|
2587
|
+
* 3 multiplicative * / % LTR
|
|
2588
|
+
* 4 additive + - LTR
|
|
2589
|
+
* 5 bit-wise shift << >> LTR
|
|
2590
|
+
* 6 relational < > <= >= LTR
|
|
2591
|
+
* 7 equality == != LTR
|
|
2592
|
+
* 8 bit-wise and & LTR
|
|
2593
|
+
* 9 bit-wise xor ^ LTR
|
|
2594
|
+
* 10 bit-wise or | LTR
|
|
2595
|
+
* 11 logical and && LTR
|
|
2596
|
+
* 12 logical or || LTR
|
|
2597
|
+
*
|
|
2598
|
+
* @param {*} $ Grammar symbols.
|
|
2599
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2600
|
+
*/
|
|
2601
|
+
preproc_binary_expression: ($) => {
|
|
2602
|
+
/** @type {[number, RuleOrLiteral][]} */
|
|
2603
|
+
const table = [
|
|
2604
|
+
[11, choice('*', '/', '%')],
|
|
2605
|
+
[10, choice('+', '-')],
|
|
2606
|
+
[9, choice('<<', '>>')],
|
|
2607
|
+
[8, choice('<', '>', '<=', '>=')],
|
|
2608
|
+
[7, choice('==', '!=')],
|
|
2609
|
+
[6, '&'],
|
|
2610
|
+
[5, '^'],
|
|
2611
|
+
[4, '|'],
|
|
2612
|
+
[3, '&&'],
|
|
2613
|
+
[2, '||'],
|
|
2614
|
+
];
|
|
2615
|
+
return choice(
|
|
2616
|
+
...table.map(([precedence, operator]) =>
|
|
2617
|
+
prec.left(
|
|
2618
|
+
precedence,
|
|
2619
|
+
seq(
|
|
2620
|
+
field('left', $._preproc_expression),
|
|
2621
|
+
field('operator', operator),
|
|
2622
|
+
field('right', $._preproc_expression),
|
|
2623
|
+
),
|
|
2624
|
+
),
|
|
2625
|
+
),
|
|
2626
|
+
);
|
|
2627
|
+
},
|
|
2628
|
+
|
|
2629
|
+
// Conditional compilation: context-dependent variants.
|
|
2630
|
+
...preprocIf('', ($) => $._top_level_item),
|
|
2631
|
+
...preprocIf('_in_statement', ($) => $.statement),
|
|
2632
|
+
...preprocIf('_in_struct_declaration', ($) => $.field_declaration),
|
|
2633
|
+
} :
|
|
2634
|
+
{},
|
|
2635
|
+
|
|
2636
|
+
// ── OPT.MACRO_EXPANSION ────────────────────────────────────────────
|
|
2637
|
+
// Syntactic placeholders for unexpanded macro output. This accepts
|
|
2638
|
+
// identifiers or function-like macro invocations in positions where
|
|
2639
|
+
// macro expansion would yield standard GLSL qualifiers or type names.
|
|
2640
|
+
|
|
2641
|
+
OPT.MACRO_EXPANSION ?
|
|
2642
|
+
{
|
|
2643
|
+
/**
|
|
2644
|
+
* Extension: unexpanded macro used in ordinary GLSL syntax.
|
|
2645
|
+
*
|
|
2646
|
+
* Object-like macros appear as `(macro_invocation (identifier))`.
|
|
2647
|
+
* Function-like macros appear as `(macro_invocation (function_call ...))`.
|
|
2648
|
+
* The same node is reused in qualifier, type, and expression position.
|
|
2649
|
+
*
|
|
2650
|
+
* @param {*} $ Grammar symbols.
|
|
2651
|
+
* @returns {RuleOrLiteral} Rule definition.
|
|
2652
|
+
*/
|
|
2653
|
+
macro_invocation: ($) =>
|
|
2654
|
+
choice(
|
|
2655
|
+
alias($._macro_function_call, $.function_call),
|
|
2656
|
+
$.identifier,
|
|
2657
|
+
),
|
|
2658
|
+
|
|
2659
|
+
/**
|
|
2660
|
+
* Extension: internal function-like macro invocation.
|
|
2661
|
+
*
|
|
2662
|
+
* Unlike regular function_call which requires valid GLSL
|
|
2663
|
+
* expressions as arguments, macro arguments are arbitrary
|
|
2664
|
+
* token sequences separated by commas, with balanced
|
|
2665
|
+
* parentheses. This allows constructs like:
|
|
2666
|
+
* MACRO(.field = 1, .other = 2)
|
|
2667
|
+
* CONCAT(vec, 3)
|
|
2668
|
+
*
|
|
2669
|
+
* @param {GrammarSymbols<string>} $
|
|
2670
|
+
*/
|
|
2671
|
+
_macro_function_call: ($) =>
|
|
2672
|
+
seq(
|
|
2673
|
+
field('function', $.identifier),
|
|
2674
|
+
'(',
|
|
2675
|
+
optional(field('arguments', $.macro_argument_list)),
|
|
2676
|
+
')',
|
|
2677
|
+
),
|
|
2678
|
+
|
|
2679
|
+
/**
|
|
2680
|
+
* Comma-separated list of macro arguments.
|
|
2681
|
+
*
|
|
2682
|
+
* @param {GrammarSymbols<string>} $
|
|
2683
|
+
*/
|
|
2684
|
+
macro_argument_list: ($) =>
|
|
2685
|
+
seq($.macro_argument, repeat(seq(',', $.macro_argument))),
|
|
2686
|
+
|
|
2687
|
+
/**
|
|
2688
|
+
* A single macro argument: any token sequence without bare
|
|
2689
|
+
* `,` or unmatched `)`. Parenthesized sub-groups are allowed
|
|
2690
|
+
* and preserve commas inside them.
|
|
2691
|
+
*
|
|
2692
|
+
* @param {GrammarSymbols<string>} $
|
|
2693
|
+
*/
|
|
2694
|
+
macro_argument: ($) =>
|
|
2695
|
+
repeat1(choice(
|
|
2696
|
+
$._macro_paren_group,
|
|
2697
|
+
$._macro_token,
|
|
2698
|
+
)),
|
|
2699
|
+
|
|
2700
|
+
/**
|
|
2701
|
+
* Balanced parentheses inside a macro argument.
|
|
2702
|
+
*
|
|
2703
|
+
* @param {GrammarSymbols<string>} $
|
|
2704
|
+
*/
|
|
2705
|
+
_macro_paren_group: ($) =>
|
|
2706
|
+
seq('(', optional($._macro_paren_content), ')'),
|
|
2707
|
+
|
|
2708
|
+
/**
|
|
2709
|
+
* Content inside balanced parens: tokens and commas (no separation).
|
|
2710
|
+
*
|
|
2711
|
+
* @param {GrammarSymbols<string>} $
|
|
2712
|
+
*/
|
|
2713
|
+
_macro_paren_content: ($) =>
|
|
2714
|
+
repeat1(choice(
|
|
2715
|
+
$._macro_paren_group,
|
|
2716
|
+
$._macro_token,
|
|
2717
|
+
',',
|
|
2718
|
+
)),
|
|
2719
|
+
|
|
2720
|
+
/**
|
|
2721
|
+
* Any single token that isn't `,`, `(`, or `)`.
|
|
2722
|
+
*
|
|
2723
|
+
* @param {GrammarSymbols<string>} _
|
|
2724
|
+
*/
|
|
2725
|
+
_macro_token: (_) => token(prec(-1, /[^\s,()]+/)),
|
|
2726
|
+
} :
|
|
2727
|
+
{},
|
|
2728
|
+
|
|
2729
|
+
// ── OPT.MULTILINGUAL ──────────────────────────────────────────────
|
|
2730
|
+
// Mixed-language branch support for shared GLSL/C++ utility headers.
|
|
2731
|
+
// This keeps the outer preprocessor structure in GLSL while exposing the
|
|
2732
|
+
// host-language span for query-based injection.
|
|
2733
|
+
//
|
|
2734
|
+
// Two language families are recognized:
|
|
2735
|
+
// cpp: `__cplusplus`
|
|
2736
|
+
// c: `__STDC__`, `__GNUC__`, `__clang__`, `_MSC_VER`
|
|
2737
|
+
//
|
|
2738
|
+
// Each family generates a parallel set of rules (macro, check, condition,
|
|
2739
|
+
// negated condition, code block, else branch, markers). The helpers below
|
|
2740
|
+
// eliminate the duplication.
|
|
2741
|
+
|
|
2742
|
+
OPT.MULTILINGUAL ?
|
|
2743
|
+
{
|
|
2744
|
+
// ── Language macros ──
|
|
2745
|
+
|
|
2746
|
+
/** @param {GrammarSymbols<string>} _ @returns {RuleOrLiteral} */
|
|
2747
|
+
preproc_cpp_language_macro: (_) => '__cplusplus',
|
|
2748
|
+
/** @param {GrammarSymbols<string>} _ @returns {RuleOrLiteral} */
|
|
2749
|
+
preproc_c_language_macro: (_) =>
|
|
2750
|
+
choice('__STDC__', '__GNUC__', '__clang__', '_MSC_VER'),
|
|
2751
|
+
|
|
2752
|
+
// ── Language checks: `MACRO`, `defined MACRO`, `defined(MACRO)` ──
|
|
2753
|
+
|
|
2754
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2755
|
+
preproc_cpp_language_check: ($) => langCheck($.preproc_cpp_language_macro),
|
|
2756
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2757
|
+
preproc_c_language_check: ($) => langCheck($.preproc_c_language_macro),
|
|
2758
|
+
|
|
2759
|
+
// ── Positive conditions ──
|
|
2760
|
+
|
|
2761
|
+
/**
|
|
2762
|
+
* Condition selecting a C++ branch. Matches simple checks and
|
|
2763
|
+
* compound forms like `defined(__cplusplus) || defined(__STDC__)`.
|
|
2764
|
+
* If `__cplusplus` appears anywhere, the branch is treated as C++
|
|
2765
|
+
* since C++ is a usable superset for injected C syntax.
|
|
2766
|
+
*
|
|
2767
|
+
* @param {GrammarSymbols<string>} $
|
|
2768
|
+
*/
|
|
2769
|
+
preproc_cpp_condition: ($) =>
|
|
2770
|
+
choice(
|
|
2771
|
+
$.preproc_cpp_language_check,
|
|
2772
|
+
...langCompound(
|
|
2773
|
+
$.preproc_cpp_language_check,
|
|
2774
|
+
$.preproc_c_language_check,
|
|
2775
|
+
),
|
|
2776
|
+
),
|
|
2777
|
+
|
|
2778
|
+
/**
|
|
2779
|
+
* Condition selecting a C branch (simple check only).
|
|
2780
|
+
*
|
|
2781
|
+
* @param {GrammarSymbols<string>} $
|
|
2782
|
+
*/
|
|
2783
|
+
preproc_c_condition: ($) => $.preproc_c_language_check,
|
|
2784
|
+
|
|
2785
|
+
// ── Negated conditions ──
|
|
2786
|
+
|
|
2787
|
+
/**
|
|
2788
|
+
* `!defined(__cplusplus)` — body is GLSL, else is C++.
|
|
2789
|
+
*
|
|
2790
|
+
* @param {GrammarSymbols<string>} $
|
|
2791
|
+
*/
|
|
2792
|
+
preproc_not_cpp_condition: ($) => not($.preproc_cpp_language_check),
|
|
2793
|
+
|
|
2794
|
+
/**
|
|
2795
|
+
* `!defined(__STDC__)` — body is GLSL, else is C.
|
|
2796
|
+
*
|
|
2797
|
+
* @param {GrammarSymbols<string>} $
|
|
2798
|
+
*/
|
|
2799
|
+
preproc_not_c_condition: ($) => not($.preproc_c_language_check),
|
|
2800
|
+
|
|
2801
|
+
// ── Foreign-language code blocks ──
|
|
2802
|
+
|
|
2803
|
+
/**
|
|
2804
|
+
* Raw non-GLSL line. Stops before `#else`, `#elif`, `#endif`.
|
|
2805
|
+
*
|
|
2806
|
+
* @param {GrammarSymbols<string>} _
|
|
2807
|
+
*/
|
|
2808
|
+
multilingual_code_line: (_) =>
|
|
2809
|
+
token(prec(-1, /(?:[^\n]+\r?\n?|\r?\n)/)),
|
|
2810
|
+
|
|
2811
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2812
|
+
multilingual_cpp_code_block: ($) => repeat1($.multilingual_code_line),
|
|
2813
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2814
|
+
multilingual_c_code_block: ($) => repeat1($.multilingual_code_line),
|
|
2815
|
+
|
|
2816
|
+
// ── Language-aware #else branches ──
|
|
2817
|
+
|
|
2818
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2819
|
+
preproc_cpp_else: ($) =>
|
|
2820
|
+
seq(preprocessor('else'), field('body', $.multilingual_cpp_code_block)),
|
|
2821
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2822
|
+
preproc_c_else: ($) =>
|
|
2823
|
+
seq(preprocessor('else'), field('body', $.multilingual_c_code_block)),
|
|
2824
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2825
|
+
preproc_glsl_else: ($) =>
|
|
2826
|
+
seq(preprocessor('else'), repeat($._top_level_item)),
|
|
2827
|
+
|
|
2828
|
+
// ── Internal markers (condition → body pairs) ──
|
|
2829
|
+
|
|
2830
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2831
|
+
_found_cpp_marker: ($) =>
|
|
2832
|
+
langForeignBody($.preproc_cpp_condition, $.multilingual_cpp_code_block),
|
|
2833
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2834
|
+
_found_c_marker: ($) =>
|
|
2835
|
+
langForeignBody($.preproc_c_condition, $.multilingual_c_code_block),
|
|
2836
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2837
|
+
_found_not_cpp_marker: ($) =>
|
|
2838
|
+
langGlslBody($, $.preproc_not_cpp_condition, $.preproc_cpp_else),
|
|
2839
|
+
/** @param {GrammarSymbols<string>} $ @returns {RuleOrLiteral} */
|
|
2840
|
+
_found_not_c_marker: ($) =>
|
|
2841
|
+
langGlslBody($, $.preproc_not_c_condition, $.preproc_c_else),
|
|
2842
|
+
|
|
2843
|
+
// ── Top-level language guard directives ──
|
|
2844
|
+
|
|
2845
|
+
/**
|
|
2846
|
+
* `#ifdef __cplusplus` / `#ifdef __STDC__`
|
|
2847
|
+
*
|
|
2848
|
+
* @param {GrammarSymbols<string>} $
|
|
2849
|
+
*/
|
|
2850
|
+
preproc_language_ifdef: ($) =>
|
|
2851
|
+
seq(
|
|
2852
|
+
preprocessor('ifdef'),
|
|
2853
|
+
choice(
|
|
2854
|
+
langIfdefArm($, $.preproc_cpp_language_macro, $.multilingual_cpp_code_block, $.preproc_glsl_else),
|
|
2855
|
+
langIfdefArm($, $.preproc_c_language_macro, $.multilingual_c_code_block, $.preproc_glsl_else),
|
|
2856
|
+
),
|
|
2857
|
+
preprocessor('endif'),
|
|
2858
|
+
),
|
|
2859
|
+
|
|
2860
|
+
/**
|
|
2861
|
+
* `#ifndef __cplusplus` / `#ifndef __STDC__`
|
|
2862
|
+
*
|
|
2863
|
+
* @param {GrammarSymbols<string>} $
|
|
2864
|
+
*/
|
|
2865
|
+
preproc_language_ifndef: ($) =>
|
|
2866
|
+
seq(
|
|
2867
|
+
preprocessor('ifndef'),
|
|
2868
|
+
choice(
|
|
2869
|
+
langIfndefArm($, $.preproc_cpp_language_macro, $.preproc_cpp_else),
|
|
2870
|
+
langIfndefArm($, $.preproc_c_language_macro, $.preproc_c_else),
|
|
2871
|
+
),
|
|
2872
|
+
preprocessor('endif'),
|
|
2873
|
+
),
|
|
2874
|
+
|
|
2875
|
+
/**
|
|
2876
|
+
* `#elif defined(__cplusplus)` / `#elif defined(__STDC__)` —
|
|
2877
|
+
* recursive chain for multi-language guards.
|
|
2878
|
+
*
|
|
2879
|
+
* @param {GrammarSymbols<string>} $
|
|
2880
|
+
*/
|
|
2881
|
+
preproc_language_elif: ($) =>
|
|
2882
|
+
seq(
|
|
2883
|
+
preprocessor('elif'),
|
|
2884
|
+
choice($._found_cpp_marker, $._found_c_marker),
|
|
2885
|
+
field(
|
|
2886
|
+
'alternative',
|
|
2887
|
+
optional(
|
|
2888
|
+
choice(
|
|
2889
|
+
alias($.preproc_language_elif, $.preproc_elif),
|
|
2890
|
+
alias($.preproc_glsl_else, $.preproc_else),
|
|
2891
|
+
),
|
|
2892
|
+
),
|
|
2893
|
+
),
|
|
2894
|
+
),
|
|
2895
|
+
|
|
2896
|
+
/**
|
|
2897
|
+
* `#if defined(__cplusplus)` / `#if !defined(__cplusplus)` —
|
|
2898
|
+
* top-level language guard with positive or negated condition.
|
|
2899
|
+
*
|
|
2900
|
+
* @param {GrammarSymbols<string>} $
|
|
2901
|
+
*/
|
|
2902
|
+
preproc_language_if: ($) =>
|
|
2903
|
+
seq(
|
|
2904
|
+
preprocessor('if'),
|
|
2905
|
+
choice(
|
|
2906
|
+
// Positive: body is foreign code
|
|
2907
|
+
seq(
|
|
2908
|
+
choice($._found_cpp_marker, $._found_c_marker),
|
|
2909
|
+
field(
|
|
2910
|
+
'alternative',
|
|
2911
|
+
optional(
|
|
2912
|
+
choice(
|
|
2913
|
+
alias($.preproc_language_elif, $.preproc_elif),
|
|
2914
|
+
alias($.preproc_glsl_else, $.preproc_else),
|
|
2915
|
+
),
|
|
2916
|
+
),
|
|
2917
|
+
),
|
|
2918
|
+
),
|
|
2919
|
+
// Negated: body is GLSL
|
|
2920
|
+
choice($._found_not_cpp_marker, $._found_not_c_marker),
|
|
2921
|
+
),
|
|
2922
|
+
preprocessor('endif'),
|
|
2923
|
+
),
|
|
2924
|
+
} :
|
|
2925
|
+
{},
|
|
2926
|
+
|
|
2927
|
+
// ── Extension grammar rules ──────────────────────────────────────────
|
|
2928
|
+
EXTENSION_RULES,
|
|
2929
|
+
),
|
|
2930
|
+
});
|
|
2931
|
+
|
|
2932
|
+
export {PRECEDENCE as PREC, preprocIf, preprocessor, commaSep, commaSep1};
|