Iterative env access walker — explicit stack
| 139 | |
| 140 | // Iterative env access walker — explicit stack |
| 141 | static void walk_env_accesses(CBMExtractCtx *ctx, TSNode root, const CBMLangSpec *spec) { |
| 142 | TSNodeStack stack; |
| 143 | ts_nstack_init(&stack, ctx->arena, 4096); |
| 144 | ts_nstack_push(&stack, ctx->arena, root); |
| 145 | |
| 146 | while (stack.count > 0) { |
| 147 | TSNode node = ts_nstack_pop(&stack); |
| 148 | const char *kind = ts_node_type(node); |
| 149 | const char *env_key = NULL; |
| 150 | |
| 151 | if (cbm_kind_in_set(node, spec->call_node_types)) { |
| 152 | env_key = extract_env_key_from_call(ctx, node, spec); |
| 153 | } else if (strcmp(kind, "member_expression") == 0 || strcmp(kind, "subscript") == 0 || |
| 154 | strcmp(kind, "attribute") == 0) { |
| 155 | env_key = extract_env_key_from_member(ctx, node, spec); |
| 156 | } |
| 157 | |
| 158 | if (env_key && env_key[0] && is_env_var_name(env_key)) { |
| 159 | CBMEnvAccess ea; |
| 160 | ea.env_key = env_key; |
| 161 | ea.enclosing_func_qn = cbm_enclosing_func_qn_cached(ctx, node); |
| 162 | cbm_envaccess_push(&ctx->result->env_accesses, ctx->arena, ea); |
| 163 | continue; // don't push children (avoid double-counting) |
| 164 | } |
| 165 | |
| 166 | ts_nstack_push_children(&stack, ctx->arena, node); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | void cbm_extract_env_accesses(CBMExtractCtx *ctx) { |
| 171 | const CBMLangSpec *spec = cbm_lang_spec(ctx->language); |
no test coverage detected