big-code-analysis 2.0.0

Tool to compute and export code metrics
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
// Per-language `kind_id`-set and alias macros.
//
// Split out of `macros.rs` (now `macros/mod.rs`) so that file is no
// longer dominated, by line count, by these ~20 near-identical
// match-pattern bundles (which sank its maintainability index). These
// macros MUST stay `macro_rules!`: each expands to a `|`-separated
// list of per-language `kind_id` enum variants consumed inside
// `matches!()` at the call site, where a `use <Lang>::*` glob brings
// the variants into scope. They carry no logic -- only the variant
// membership -- and every per-call grammar rationale comment travels
// with its macro (see `.claude/rules/macro-comments.md`).
//
// Re-exported below via `pub(crate) use` and again from
// `macros/mod.rs`, so every existing `crate::macros::<name>` import in
// `checker.rs`, `metrics/npa.rs`, and `metrics/abc.rs` keeps resolving
// unchanged.

// Aliased C# `kind_id` unions. The C# tree-sitter grammar emits multiple
// numbered variants for several rules (lesson #2 in
// `docs/development/lessons_learned.md`); centralizing the alias sets
// here keeps every match site in lockstep, so a future grammar bump that
// adds another numbered variant is a one-line edit instead of a scatter
// of 4-5 sites.
macro_rules! csharp_invocation_expr_kinds {
    () => {
        $crate::Csharp::InvocationExpression
            | $crate::Csharp::InvocationExpression2
            | $crate::Csharp::InvocationExpression3
    };
}

macro_rules! csharp_paren_expr_kinds {
    () => {
        $crate::Csharp::ParenthesizedExpression
            | $crate::Csharp::ParenthesizedExpression2
            | $crate::Csharp::ParenthesizedExpression3
    };
}

macro_rules! csharp_prefix_unary_expr_kinds {
    () => {
        $crate::Csharp::PrefixUnaryExpression | $crate::Csharp::PrefixUnaryExpression2
    };
}

// Terminal-bool operand kinds recognised by ABC condition counting for
// the C# grammar. Anything in this set, when it appears in a known-
// boolean context (if / while / do / for / ternary / binary), counts
// as one condition. The set bundles `csharp_invocation_expr_kinds!()`
// with the bare `Identifier` / `BooleanLiteral` leaves *and* the five
// expression kinds whose evaluated value is implicitly boolean in any
// idiomatic codebase:
//
// - `MemberAccessExpression` — `cfg.Enabled`, `Request.IsHttps`
// - `AwaitExpression`        — `await CheckAsync()`
// - `CastExpression`         — `(bool)v`, `(IDisposable)x is not null`
// - `IsPatternExpression`    — `x is null`, `x is not Foo f`
// - `ElementAccessExpression` — `flags[0]`, `dict["key"]`
//
// Before #372 only the first three (invocation / identifier /
// boolean) were recognised, so all five kinds above silently scored
// zero conditions in `if` / `while` / `do` / ternary contexts.
macro_rules! csharp_bool_terminal_kinds {
    () => {
        $crate::Csharp::InvocationExpression
            | $crate::Csharp::InvocationExpression2
            | $crate::Csharp::InvocationExpression3
            | $crate::Csharp::Identifier
            | $crate::Csharp::BooleanLiteral
            | $crate::Csharp::MemberAccessExpression
            | $crate::Csharp::AwaitExpression
            | $crate::Csharp::CastExpression
            | $crate::Csharp::IsPatternExpression
            | $crate::Csharp::ElementAccessExpression
    };
}

macro_rules! csharp_var_decl_kinds {
    () => {
        $crate::Csharp::VariableDeclaration | $crate::Csharp::VariableDeclaration2
    };
}

macro_rules! csharp_var_declarator_kinds {
    () => {
        $crate::Csharp::VariableDeclarator | $crate::Csharp::VariableDeclarator2
    };
}

// Terminal-bool operand kinds recognised by ABC condition counting for
// the Java grammar. Sister of `csharp_bool_terminal_kinds!()` — bundles
// the four "bare boolean leaf" kinds (`MethodInvocation`, `Identifier`,
// `True`, `False`) with the four bool-evaluating expression kinds
// surfaced by #372 / lesson #19:
//
// - `FieldAccess`          — `cfg.flag`
// - `CastExpression`       — `(boolean) v`
// - `ArrayAccess`          — `flags[0]`
// - `InstanceofExpression` — `x instanceof Foo`
//
// Used by `java_inspect_container`, `java_count_unary_conditions`,
// `java_walk_ternary`, and the two branches of `java_walk_for_statement`
// (the latter ORs in `SEMI | RPAREN` at the call site to also recognise
// the empty-condition `for (;;)` form).
macro_rules! java_bool_terminal_kinds {
    () => {
        $crate::Java::MethodInvocation
            | $crate::Java::Identifier
            | $crate::Java::True
            | $crate::Java::False
            | $crate::Java::FieldAccess
            | $crate::Java::CastExpression
            | $crate::Java::ArrayAccess
            | $crate::Java::InstanceofExpression
    };
}

// Terminal-bool operand kinds recognised by ABC condition counting for
// the dekobon Groovy grammar. Sister of `java_bool_terminal_kinds!()`,
// with Groovy-specific replacements: `CommandChain` for the parens-less
// call form `println foo`, `BooleanLiteral` (the named wrapper around
// the leaf `True` / `False` tokens, see `groovy_count_condition`), and
// `ParenthesizedTypeCast` for the Java-style `(boolean) v` form (the
// grammar represents it as its own kind rather than nesting
// `cast_expression` inside `parenthesized_expression`). The set bundles
// the bool-evaluating terminals added by #372 (`FieldAccess`,
// `CastExpression`, `ParenthesizedTypeCast`, `InstanceofExpression`);
// the dekobon Groovy grammar has no `await` or `array_access`
// analogues, so those collapse out of the C# set.
macro_rules! groovy_bool_terminal_kinds {
    () => {
        $crate::Groovy::MethodInvocation
            | $crate::Groovy::CommandChain
            | $crate::Groovy::Identifier
            | $crate::Groovy::BooleanLiteral
            | $crate::Groovy::FieldAccess
            | $crate::Groovy::CastExpression
            | $crate::Groovy::ParenthesizedTypeCast
            | $crate::Groovy::InstanceofExpression
    };
}

// Terminal-bool operand kinds for the Phase-2 unary-conditional walker
// (issue #403). Each `<lang>_bool_terminal_kinds!()` macro lists the
// expression kinds whose evaluated value is implicitly boolean in an
// `if` / `while` / `&&` / `||` operand slot for that language. Each
// per-language walker pair (`<lang>_inspect_container` +
// `<lang>_count_unary_conditions`) consumes the same set in both
// helpers, so hoisting to a macro removes the literal duplication.

macro_rules! rust_bool_terminal_kinds {
    // `ScopedIdentifier` (`crate::FLAG`, `ns::flag`) and
    // `AwaitExpression` (`ready().await`) are both idiomatic shapes
    // for a boolean-valued condition operand. Adding them mirrors
    // the C# fix in #372 (lesson 19), which closed the same gap
    // for `CastExpression`, `MemberAccessExpression`, and
    // `AwaitExpression` on the C# side.
    () => {
        $crate::Rust::Identifier
            | $crate::Rust::BooleanLiteral
            | $crate::Rust::CallExpression
            | $crate::Rust::FieldExpression
            | $crate::Rust::IndexExpression
            | $crate::Rust::ScopedIdentifier
            | $crate::Rust::AwaitExpression
    };
}

macro_rules! go_bool_terminal_kinds {
    // Aliased Identifier kind_ids (lesson #2): tree-sitter-go emits
    // `identifier` under three numeric ids (1, 60, 61) depending on
    // the production rule path. Halstead's getter already matches all
    // three (the `G::Identifier | G::Identifier2 | G::Identifier3` arm
    // in `impl Getter for GoCode::get_op_type`, `src/getter.rs`).
    () => {
        $crate::Go::Identifier
            | $crate::Go::Identifier2
            | $crate::Go::Identifier3
            | $crate::Go::True
            | $crate::Go::False
            | $crate::Go::CallExpression
            | $crate::Go::SelectorExpression
            | $crate::Go::IndexExpression
            | $crate::Go::TypeAssertionExpression
    };
}

macro_rules! cpp_bool_terminal_kinds {
    // Matches on node-kind NAMES, not one grammar's enum discriminants,
    // so it is correct for every C-family grammar: the shared ABC helpers
    // run over both upstream `Cpp` and the Mozilla `Mozcpp` fork (#720),
    // which assign *different* kind_ids to the same kinds (#732, mirroring
    // the npa fix in #731). `qualified_identifier` has four numeric ids
    // (573..576) in tree-sitter-cpp's production-rule path, but all four
    // render to the one base name, so a single arm covers them — the
    // ABC walker needs them so `if (ns::flag) {}` reaches the terminal
    // count. `cast_expression` (`(bool)v`) evaluates to a boolean in
    // idiomatic C++ — mirrors the C# fix in #372 (lesson 19).
    () => {
        "identifier"
            | "true"
            | "false"
            | "call_expression"
            | "field_expression"
            | "subscript_expression"
            | "cast_expression"
            | "qualified_identifier"
    };
}

macro_rules! php_bool_terminal_kinds {
    // Aliased kind_ids (lesson 2):
    //   - `name` has two ids (1, 211)
    //   - `member_access_expression` has three (328, 329, 360)
    //   - `nullsafe_member_access_expression` has two (330, 331)
    //   - `scoped_property_access_expression` has two (332, 333)
    //   - `subscript_expression` has three (351, 352, 363)
    // The matching `*_call_expression` kinds remain singular at the
    // pinned grammar version. Including the property-access form
    // (`$x?->y`, `$x->y`, and `Cls::$x`) closes the bool-typed-
    // property-access gap that the call-form alone left open.
    () => {
        $crate::Php::Name
            | $crate::Php::Name2
            | $crate::Php::VariableName
            | $crate::Php::Boolean
            | $crate::Php::FunctionCallExpression
            | $crate::Php::MemberCallExpression
            | $crate::Php::ScopedCallExpression
            | $crate::Php::NullsafeMemberCallExpression
            | $crate::Php::ObjectCreationExpression
            | $crate::Php::MemberAccessExpression
            | $crate::Php::MemberAccessExpression2
            | $crate::Php::MemberAccessExpression3
            | $crate::Php::NullsafeMemberAccessExpression
            | $crate::Php::NullsafeMemberAccessExpression2
            | $crate::Php::ScopedPropertyAccessExpression
            | $crate::Php::ScopedPropertyAccessExpression2
            | $crate::Php::SubscriptExpression
            | $crate::Php::SubscriptExpression2
            | $crate::Php::SubscriptExpression3
    };
}

macro_rules! python_bool_terminal_kinds {
    // `Await` (`await ready()`) evaluates to a boolean in idiomatic
    // async Python — mirrors the C# fix in #372 (lesson 19) which
    // closed the same gap for `AwaitExpression`.
    //
    // `Integer` / `Float` are numeric-truthy operands: Python treats
    // every non-zero number as truthy, so `if 5:` / `x and 5` each
    // count their numeric literal as a Fitzpatrick unary condition.
    // Mirrors the Lua `Number` fix (#772). Statically-typed languages
    // omit numerics (a bare int in a bool slot is a type error); a
    // dynamically-typed language must count them.
    () => {
        $crate::Python::Identifier
            | $crate::Python::True
            | $crate::Python::False
            | $crate::Python::Integer
            | $crate::Python::Float
            | $crate::Python::Call
            | $crate::Python::Attribute
            | $crate::Python::Subscript
            | $crate::Python::Await
    };
}

macro_rules! perl_bool_terminal_kinds {
    () => {
        $crate::Perl::Identifier
            | $crate::Perl::Boolean
            | $crate::Perl::True
            | $crate::Perl::False
            | $crate::Perl::ScalarVariable
            | $crate::Perl::ArrayVariable
            | $crate::Perl::HashVariable
            | $crate::Perl::ArrayAccessVariable
            | $crate::Perl::HashAccessVariable
            | $crate::Perl::HashAccessVariableSimple
            | $crate::Perl::CallExpressionWithSpacedArgs
            | $crate::Perl::CallExpressionWithSub
            | $crate::Perl::CallExpressionWithArgsWithBrackets
            | $crate::Perl::CallExpressionWithVariable
            | $crate::Perl::CallExpressionRecursive
            | $crate::Perl::CallExpressionWithBareword
            | $crate::Perl::MethodInvocation
    };
}

macro_rules! lua_bool_terminal_kinds {
    () => {
        $crate::Lua::Identifier
            | $crate::Lua::True
            | $crate::Lua::False
            | $crate::Lua::Nil
            | $crate::Lua::Number
            | $crate::Lua::FunctionCall
            | $crate::Lua::DotIndexExpression
            | $crate::Lua::DotIndexExpression2
            | $crate::Lua::BracketIndexExpression
            | $crate::Lua::MethodIndexExpression
            | $crate::Lua::MethodIndexExpression2
    };
}

macro_rules! tcl_bool_terminal_kinds {
    () => {
        $crate::Tcl::SimpleWord
            | $crate::Tcl::BracedWord
            | $crate::Tcl::BracedWordSimple
            | $crate::Tcl::QuotedWord
            | $crate::Tcl::VariableSubstitution
            | $crate::Tcl::CommandSubstitution
            | $crate::Tcl::Boolean
            | $crate::Tcl::Number
    };
}

// iRules counterpart of `tcl_bool_terminal_kinds!` (the grammar is a Tcl
// dialect, so the terminal-operand set is the same shape).
macro_rules! irules_bool_terminal_kinds {
    () => {
        $crate::Irules::SimpleWord
            | $crate::Irules::BracedWord
            | $crate::Irules::BracedWordSimple
            | $crate::Irules::QuotedWord
            | $crate::Irules::VariableSubstitution
            | $crate::Irules::CommandSubstitution
            | $crate::Irules::Boolean
            | $crate::Irules::Number
    };
}

// The JS-family languages diverge on which aliased `kind_id`s the
// grammar emits — JavaScript, Mozjs, and Tsx have `Identifier2`,
// TypeScript does not; TypeScript has `MemberExpression4` /
// `CallExpression4` / `SubscriptExpression2` that the others do not.
// Per lesson #2, every alias the grammar emits at runtime must be
// matched at compile time. Four per-language macros below replace
// the original single `js_family_bool_terminal_kinds!($Lang)`
// generic, which silently dropped `MemberExpression2` (the kind
// runtime emits for `obj.foo`) for all four languages.

macro_rules! javascript_bool_terminal_kinds {
    // `AwaitExpression` (`await ready()`) is in the terminal set
    // mirroring the C# reference (lesson 19). `Number` is a
    // numeric-truthy operand: JS treats every non-zero number as
    // truthy, so `while (5)` / `x && 5` count their numeric literal
    // as a Fitzpatrick unary condition (#772, mirrors the Lua fix).
    () => {
        $crate::Javascript::Identifier
            | $crate::Javascript::Identifier2
            | $crate::Javascript::True
            | $crate::Javascript::False
            | $crate::Javascript::Number
            | $crate::Javascript::CallExpression
            | $crate::Javascript::CallExpression2
            | $crate::Javascript::NewExpression
            | $crate::Javascript::MemberExpression
            | $crate::Javascript::MemberExpression2
            | $crate::Javascript::MemberExpression3
            | $crate::Javascript::SubscriptExpression
            | $crate::Javascript::AwaitExpression
    };
}

macro_rules! mozjs_bool_terminal_kinds {
    // `AwaitExpression` (`await ready()`) is in the terminal set
    // mirroring the C# reference (lesson 19). `Number` is a
    // numeric-truthy operand (#772, mirrors the Lua fix) — see
    // `javascript_bool_terminal_kinds!`.
    () => {
        $crate::Mozjs::Identifier
            | $crate::Mozjs::Identifier2
            | $crate::Mozjs::True
            | $crate::Mozjs::False
            | $crate::Mozjs::Number
            | $crate::Mozjs::CallExpression
            | $crate::Mozjs::CallExpression2
            | $crate::Mozjs::NewExpression
            | $crate::Mozjs::MemberExpression
            | $crate::Mozjs::MemberExpression2
            | $crate::Mozjs::MemberExpression3
            | $crate::Mozjs::SubscriptExpression
            | $crate::Mozjs::AwaitExpression
    };
}

macro_rules! typescript_bool_terminal_kinds {
    // `AwaitExpression` (`await ready()`) is in the terminal set
    // mirroring the C# reference (lesson 19). `Number` (the numeric
    // *literal*, id 110) is a numeric-truthy operand (#772). The
    // grammar's other `number` alias, `Number2` (id 133), is the
    // `predefined_type` keyword `number` in a type annotation — NOT a
    // value — so it is deliberately omitted from the terminal-bool set.
    () => {
        $crate::Typescript::Identifier
            | $crate::Typescript::True
            | $crate::Typescript::False
            | $crate::Typescript::Number
            | $crate::Typescript::CallExpression
            | $crate::Typescript::CallExpression2
            | $crate::Typescript::CallExpression3
            | $crate::Typescript::CallExpression4
            | $crate::Typescript::NewExpression
            | $crate::Typescript::MemberExpression
            | $crate::Typescript::MemberExpression2
            | $crate::Typescript::MemberExpression3
            | $crate::Typescript::MemberExpression4
            | $crate::Typescript::SubscriptExpression
            | $crate::Typescript::SubscriptExpression2
            | $crate::Typescript::AwaitExpression
    };
}

macro_rules! tsx_bool_terminal_kinds {
    // `AwaitExpression` (`await ready()`) is in the terminal set
    // mirroring the C# reference (lesson 19). `Number` (the numeric
    // *literal*, id 116) is a numeric-truthy operand (#772). The
    // grammar's other `number` alias, `Number2` (id 139), is the
    // `predefined_type` keyword `number` in a type annotation — NOT a
    // value — so it is deliberately omitted from the terminal-bool set.
    () => {
        $crate::Tsx::Identifier
            | $crate::Tsx::Identifier2
            | $crate::Tsx::True
            | $crate::Tsx::False
            | $crate::Tsx::Number
            | $crate::Tsx::CallExpression
            | $crate::Tsx::CallExpression2
            | $crate::Tsx::CallExpression3
            | $crate::Tsx::CallExpression4
            | $crate::Tsx::NewExpression
            | $crate::Tsx::MemberExpression
            | $crate::Tsx::MemberExpression2
            | $crate::Tsx::MemberExpression3
            | $crate::Tsx::MemberExpression4
            | $crate::Tsx::SubscriptExpression
            | $crate::Tsx::SubscriptExpression2
            | $crate::Tsx::AwaitExpression
    };
}

// Terminal-bool operand kinds for Kotlin's ABC unary-conditional walker
// (Fitzpatrick Rule 9; issue #557). tree-sitter-kotlin-ng parses `a &&
// b` as a flat `binary_expression` with `&&` / `||` operator tokens, so
// bare boolean operands surface as leaf expressions: `identifier` (which
// also covers the `true` / `false` keyword literals — the grammar emits
// them as `identifier`, verified by AST dump), `call_expression`
// (`ready()`), `navigation_expression` (`o.flag`), `index_expression`
// (`arr[0]`), and `this_expression`. Comparison operands (`x > 0`) are
// themselves `binary_expression` nodes, so they are absent from this set
// and contribute nothing — matching the paper's "only unary conditions".
macro_rules! kotlin_bool_terminal_kinds {
    () => {
        $crate::Kotlin::Identifier
            | $crate::Kotlin::CallExpression
            | $crate::Kotlin::NavigationExpression
            | $crate::Kotlin::IndexExpression
            | $crate::Kotlin::ThisExpression
    };
}

// Terminal-bool operand kinds for Ruby's ABC unary-conditional walker
// (Fitzpatrick Rule 9; issue #557). tree-sitter-ruby parses `a && b` as
// a `binary` node with `&&` / `||` / `and` / `or` operator tokens. Bare
// boolean operands surface as: `identifier`, every `call` alias
// (`Call`..`Call4` — lesson #2; a bare predicate method `ready?` is a
// `call`), the literals `true` / `false` / `nil`, the variable sigils
// (`@ivar`, `@@cvar`, `$gvar`), `constant`, `element_reference`
// (`items[0]`), and `integer`. Comparison operands (`x > 0`) are nested
// `binary` nodes, so they are absent here and contribute nothing.
macro_rules! ruby_bool_terminal_kinds {
    () => {
        $crate::Ruby::Identifier
            | $crate::Ruby::Call
            | $crate::Ruby::Call2
            | $crate::Ruby::Call3
            | $crate::Ruby::Call4
            | $crate::Ruby::True
            | $crate::Ruby::False
            | $crate::Ruby::Nil
            | $crate::Ruby::InstanceVariable
            | $crate::Ruby::ClassVariable
            | $crate::Ruby::GlobalVariable
            | $crate::Ruby::Constant
            | $crate::Ruby::ElementReference
            | $crate::Ruby::Integer
    };
}

// Terminal-bool operand kinds for Elixir's ABC unary-conditional walker
// (Fitzpatrick Rule 9; issue #557). tree-sitter-elixir parses `a && b`
// as a `binary_operator` (aliased `BinaryOperator`..`BinaryOperator3`,
// lesson #2) with `&&` / `||` / `and` / `or` operator tokens. Bare
// boolean operands surface as: `identifier`, `call` (both `ready?()` and
// the no-paren dot access `cfg.enabled` parse as `call`), `dot`
// (`Mod.fun` reference), the `boolean` literal wrapper (`true` / `false`
// parse as `boolean`, verified by AST dump), `nil`, `atom`, `integer`,
// and `access_call` (`xs[i]`). Comparison operands are nested
// `binary_operator` nodes and so contribute nothing.
macro_rules! elixir_bool_terminal_kinds {
    () => {
        $crate::Elixir::Identifier
            | $crate::Elixir::Call
            // `dot` is an alias family (`Dot`/`Dot2`/`Dot3`, lesson #2): a
            // `Mod.fun` reference used as a bare `&&`/`||` operand parses to
            // a different alias by position, so all three must count or the
            // operand silently contributes 0 (mirrors Ruby's `Call..Call4`).
            | $crate::Elixir::Dot
            | $crate::Elixir::Dot2
            | $crate::Elixir::Dot3
            | $crate::Elixir::Boolean
            | $crate::Elixir::Nil
            | $crate::Elixir::Atom
            | $crate::Elixir::Integer
            | $crate::Elixir::AccessCall
    };
}

// Legacy single-macro form, no longer consumed by the walker after
// the per-language split above. Kept here strictly for documentation
// of the former (Identifier|True|False|CallExpression|NewExpression|
// MemberExpression|SubscriptExpression) intersection that all four
// JS-family languages share — every per-language macro above is a
// strict superset (the per-language sets have since grown
// `AwaitExpression` and other shapes; this body is the historical
// floor, not the current set).
#[allow(unused_macros)]
macro_rules! js_family_bool_terminal_kinds {
    ($Lang:ident) => {
        $crate::$Lang::Identifier
            | $crate::$Lang::True
            | $crate::$Lang::False
            | $crate::$Lang::CallExpression
            | $crate::$Lang::NewExpression
            | $crate::$Lang::MemberExpression
            | $crate::$Lang::SubscriptExpression
    };
}

pub(crate) use {
    cpp_bool_terminal_kinds, csharp_bool_terminal_kinds, csharp_invocation_expr_kinds,
    csharp_paren_expr_kinds, csharp_prefix_unary_expr_kinds, csharp_var_decl_kinds,
    csharp_var_declarator_kinds, elixir_bool_terminal_kinds, go_bool_terminal_kinds,
    groovy_bool_terminal_kinds, irules_bool_terminal_kinds, java_bool_terminal_kinds,
    javascript_bool_terminal_kinds, kotlin_bool_terminal_kinds, lua_bool_terminal_kinds,
    mozjs_bool_terminal_kinds, perl_bool_terminal_kinds, php_bool_terminal_kinds,
    python_bool_terminal_kinds, ruby_bool_terminal_kinds, rust_bool_terminal_kinds,
    tcl_bool_terminal_kinds, tsx_bool_terminal_kinds, typescript_bool_terminal_kinds,
};