`assert( )` narrows the current scope sequentially. */
| 1882 | |
| 1883 | /* `assert(<predicate>)` narrows the current scope sequentially. */ |
| 1884 | static void apply_assert_narrowing(PHPLSPContext *ctx, TSNode call) { |
| 1885 | TSNode fn = ts_node_child_by_field_name(call, "function", 8); |
| 1886 | if (ts_node_is_null(fn)) |
| 1887 | return; |
| 1888 | char *name = php_node_text(ctx, fn); |
| 1889 | if (!name || strcmp(name, "assert") != 0) |
| 1890 | return; |
| 1891 | TSNode args = ts_node_child_by_field_name(call, "arguments", 9); |
| 1892 | if (ts_node_is_null(args)) |
| 1893 | return; |
| 1894 | uint32_t anc = ts_node_child_count(args); |
| 1895 | for (uint32_t i = 0; i < anc; i++) { |
| 1896 | TSNode a = ts_node_child(args, i); |
| 1897 | if (ts_node_is_null(a) || !ts_node_is_named(a)) |
| 1898 | continue; |
| 1899 | TSNode predicate = a; |
| 1900 | if (strcmp(ts_node_type(a), "argument") == 0) { |
| 1901 | uint32_t bnc = ts_node_child_count(a); |
| 1902 | for (uint32_t j = 0; j < bnc; j++) { |
| 1903 | TSNode b = ts_node_child(a, j); |
| 1904 | if (!ts_node_is_null(b) && ts_node_is_named(b)) { |
| 1905 | predicate = b; |
| 1906 | break; |
| 1907 | } |
| 1908 | } |
| 1909 | } |
| 1910 | php_narrowing_t nw = {0}; |
| 1911 | if (parse_narrowing(ctx, predicate, &nw) && nw.var_name && nw.type) { |
| 1912 | cbm_scope_bind(ctx->current_scope, nw.var_name, nw.type); |
| 1913 | } |
| 1914 | return; |
| 1915 | } |
| 1916 | } |
| 1917 | |
| 1918 | /* Walk a body subtree under a narrowed scope (with up to N bindings), then |
| 1919 | * restore. */ |
no test coverage detected