Python constant resolution: NAME = "value" (assignment node). */
| 134 | |
| 135 | /* Python constant resolution: NAME = "value" (assignment node). */ |
| 136 | static void scan_string_consts_python(CBMExtractCtx *ctx, chan_const_table_t *tbl) { |
| 137 | TSNodeStack stack; |
| 138 | ts_nstack_init(&stack, ctx->arena, CHAN_STACK_CAP); |
| 139 | ts_nstack_push(&stack, ctx->arena, ctx->root); |
| 140 | |
| 141 | while (stack.count > 0 && tbl->count < CHAN_CONST_CAP) { |
| 142 | TSNode node = ts_nstack_pop(&stack); |
| 143 | const char *kind = ts_node_type(node); |
| 144 | |
| 145 | if (strcmp(kind, "assignment") == 0) { |
| 146 | TSNode left = ts_node_child_by_field_name(node, TS_FIELD("left")); |
| 147 | TSNode right = ts_node_child_by_field_name(node, TS_FIELD("right")); |
| 148 | if (!ts_node_is_null(left) && !ts_node_is_null(right) && |
| 149 | strcmp(ts_node_type(left), "identifier") == 0 && |
| 150 | strcmp(ts_node_type(right), "string") == 0) { |
| 151 | char *name = cbm_node_text(ctx->arena, left, ctx->source); |
| 152 | const char *val = literal_from_arg(ctx, right); |
| 153 | if (!val) { |
| 154 | val = literal_from_first_child(ctx, right); |
| 155 | } |
| 156 | if (name && val) { |
| 157 | tbl->items[tbl->count].name = name; |
| 158 | tbl->items[tbl->count].value = val; |
| 159 | tbl->count++; |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | uint32_t count = ts_node_child_count(node); |
| 165 | for (int i = (int)count - SKIP_ONE; i >= 0; i--) { |
| 166 | ts_nstack_push(&stack, ctx->arena, ts_node_child(node, (uint32_t)i)); |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | /* Resolve an identifier against the constant table. Returns NULL on miss. */ |
| 172 | static const char *resolve_identifier(const chan_const_table_t *tbl, const char *name) { |
no test coverage detected