| 1657 | } |
| 1658 | |
| 1659 | static const char *lexical_binding_key(CBMExtractCtx *ctx, WalkState *state, const char *name) { |
| 1660 | if (!ctx || !name) { |
| 1661 | return name; |
| 1662 | } |
| 1663 | /* Preserve language namespaces: Perl sigils and Vim prefixes distinguish |
| 1664 | * different variables. Tcl's grammar is asymmetric (`name` versus |
| 1665 | * `$name`), so unwrap only that language-defined reference sigil. */ |
| 1666 | if (ctx->language == CBM_LANG_TCL && name[0] == '$') { |
| 1667 | name++; |
| 1668 | } |
| 1669 | if (!lexical_identifier_case_insensitive(ctx->language)) { |
| 1670 | return name; |
| 1671 | } |
| 1672 | size_t n = strlen(name); |
| 1673 | char *folded = (char *)cbm_arena_alloc(ctx->arena, n + 1U); |
| 1674 | if (!folded) { |
| 1675 | if (state) { |
| 1676 | state->lexical_binding_tracking_failed = true; |
| 1677 | } |
| 1678 | return NULL; |
| 1679 | } |
| 1680 | for (size_t i = 0; i < n; i++) { |
| 1681 | folded[i] = (char)tolower((unsigned char)name[i]); |
| 1682 | } |
| 1683 | folded[n] = '\0'; |
| 1684 | return folded; |
| 1685 | } |
| 1686 | |
| 1687 | static void stamp_usage_site(CBMExtractCtx *ctx, CBMUsage *usage, TSNode node, const char *name, |
| 1688 | WalkState *state) { |
no test coverage detected