big_code_analysis_ast/lang_helpers/python.rs
1//! Python: the aliased `block` and `lambda` kind sets.
2
3use crate::Python;
4use crate::node::Node;
5
6/// Whether `node` is a Python `lambda` expression, under either of the
7/// grammar's two aliased kind_ids: `Lambda` (196, the concrete
8/// production emitted today) and `Lambda2` (197, the currently-unseen
9/// hidden alias). `Lambda3` (73) is the `lambda` *keyword* token, not a
10/// closure node, and is intentionally excluded.
11///
12/// This is the single normalization chokepoint for the lambda-alias set
13/// — mirroring [`python_is_block`] for the block aliases (#419). It
14/// is reused by `PythonCode::is_closure` here and by the cognitive
15/// lambda-scope walks in `big-code-analysis`, so a future grammar bump
16/// that promotes `Lambda2` to a concrete node is handled in exactly one
17/// place rather than drifting across sites (#422). The
18/// `python_hidden_block_and_lambda_aliases_stay_unseen` drift guard in
19/// `checker.rs` trips on such a bump.
20#[inline]
21#[must_use]
22pub fn python_is_lambda(node: &Node) -> bool {
23 matches!(node.kind_id().into(), Python::Lambda | Python::Lambda2)
24}
25
26/// Single normalization point for Python's aliased `block` kind_ids.
27///
28/// tree-sitter-python lists two `kind_id`s that both stringify to
29/// `"block"`: `Block` (135, the hidden `_block` supertype) and
30/// `Block2` (160, the concrete production). Empirically only `Block2`
31/// is ever emitted for real block bodies (function, class, if/for,
32/// while/try/with), so `Block` is dead today — but a future grammar
33/// bump could promote the supertype to a concrete node. Routing every
34/// "is this a block?" check through here means such a bump is handled
35/// at one site instead of silently undercounting at several (issue
36/// #419; lesson 2 / 34 / 56 in docs/development/lessons_learned.md).
37#[inline]
38#[must_use]
39pub fn python_is_block(node: &Node) -> bool {
40 matches!(node.kind_id().into(), Python::Block | Python::Block2)
41}