`assert( )` narrows the current scope sequentially. */
| 2064 | |
| 2065 | /* `assert(<predicate>)` narrows the current scope sequentially. */ |
| 2066 | static void apply_assert_narrowing(PHPLSPContext *ctx, TSNode call) { |
| 2067 | TSNode fn = ts_node_child_by_field_name(call, "function", 8); |
| 2068 | if (ts_node_is_null(fn)) |
| 2069 | return; |
| 2070 | char *name = php_node_text(ctx, fn); |
| 2071 | if (!name || strcmp(name, "assert") != 0) |
| 2072 | return; |
| 2073 | TSNode args = ts_node_child_by_field_name(call, "arguments", 9); |
| 2074 | if (ts_node_is_null(args)) |
| 2075 | return; |
| 2076 | uint32_t anc = ts_node_child_count(args); |
| 2077 | for (uint32_t i = 0; i < anc; i++) { |
| 2078 | TSNode a = ts_node_child(args, i); |
| 2079 | if (ts_node_is_null(a) || !ts_node_is_named(a)) |
| 2080 | continue; |
| 2081 | TSNode predicate = a; |
| 2082 | if (strcmp(ts_node_type(a), "argument") == 0) { |
| 2083 | uint32_t bnc = ts_node_child_count(a); |
| 2084 | for (uint32_t j = 0; j < bnc; j++) { |
| 2085 | TSNode b = ts_node_child(a, j); |
| 2086 | if (!ts_node_is_null(b) && ts_node_is_named(b)) { |
| 2087 | predicate = b; |
| 2088 | break; |
| 2089 | } |
| 2090 | } |
| 2091 | } |
| 2092 | php_narrowing_t nw = {0}; |
| 2093 | if (parse_narrowing(ctx, predicate, &nw) && nw.var_name && nw.type) { |
| 2094 | cbm_scope_bind(ctx->current_scope, nw.var_name, nw.type); |
| 2095 | } |
| 2096 | return; |
| 2097 | } |
| 2098 | } |
| 2099 | |
| 2100 | /* Walk a body subtree under a narrowed scope (with up to N bindings), then |
| 2101 | * restore. */ |
no test coverage detected