Renames what was previously called `__yeast_ctx` into just `ctx`, and
adds a new field `user_ctx` to this context. Said field can contain a
struct of any user type (necessitating making various parts of the
implementation generic in said type).
Through some Deref magic, field accesses are delegated to the inner
struct (assuming they are not already defined on `ctx`), which should
hopefully make the interface a bit more ergonomic.
Adds a new defaulted signature predicates to the shared CFG library:
- getLoopElse: `else` block of a loop statement, if
any (used by Python's `while-else` / `for-else` constructs).
The predicate defaults to `none()`, so behaviour is unchanged for any
language that doesn't override it (verified by re-running
java/ql/test/library-tests/controlflow/).
The Make0 succession rules are extended:
- WhileStmt/ForeachStmt: route the loop-exit edge through the else
block before reaching the after-position.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously, when a node was synthesized it would always take the
location from the node that matched the current rule. This resulted
in overly broad locations however.
For (foo #{bar}) we now take the location of the 'bar' node.
For non-leaf nodes we merge all its child node locations.
When a field pattern has a bare capture with no preceding pattern
atom (i.e. `foo: @bar`), implicitly use a true wildcard (`_`,
match_unnamed: true) as the node pattern, making it equivalent to
`foo: _ @bar`.
This is a convenience shorthand: in practice every `field: _ @cap`
in the Swift rules can now be written more concisely as `field: @cap`.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A left fold over an iterable where the first element seeds the accumulator:
- first -> init : converts the first element to the initial accumulator
- acc, elem -> fold : fold step; acc = current accumulator, elem = next element
- Empty iterable produces nothing (0-element splice)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
After a {expr} or {..expr} placeholder, an optional chain of
.<builtin>() calls may follow. Currently the only builtin is:
.map(param -> template)
which applies the template to each element of the iterable and
collects the resulting node IDs. A chain auto-splices into the
enclosing field/child position.
Example:
path: {parts}.map(p -> (identifier #{p}))
The framework is extensible: additional builtins can be added by
matching on the method name in parse_chain_suffix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>