llmcc_rust/descriptor/
variable.rs

1use llmcc_core::context::CompileUnit;
2use llmcc_core::ir::{HirId, HirNode};
3use tree_sitter::Node;
4
5use super::function::parse_type_expr;
6
7/// Classification for a variable-like binding.
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum VariableKind {
10    Let,
11    Const,
12    Static,
13}
14
15/// Scope in which a variable lives.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum VariableScope {
18    Global,
19    Local,
20}
21
22/// Metadata captured for `let` bindings, `const` items, and `static` items.
23#[derive(Debug, Clone)]
24pub struct VariableDescriptor {
25    /// HIR identifier associated with the binding.
26    pub hir_id: HirId,
27    /// Name as written in source.
28    pub name: String,
29    /// Fully-qualified name derived from the current scope chain.
30    pub fqn: String,
31    /// Binding kind (`let`, `const`, or `static`).
32    pub kind: VariableKind,
33    /// Whether the binding is declared mutable.
34    pub is_mut: bool,
35    /// Whether the binding lives at module scope or inside a function.
36    pub scope: VariableScope,
37    /// Optional parsed type annotation.
38    pub ty: Option<super::function::TypeExpr>,
39}
40
41impl VariableDescriptor {
42    pub(crate) fn from_let<'tcx>(
43        unit: CompileUnit<'tcx>,
44        node: &HirNode<'tcx>,
45        name: String,
46        fqn: String,
47    ) -> Self {
48        let ts_node = node.inner_ts_node();
49        let ty = ts_node
50            .child_by_field_name("type")
51            .map(|n| parse_type_expr(unit, n));
52        let is_mut = has_mutable_specifier(ts_node);
53
54        VariableDescriptor {
55            hir_id: node.hir_id(),
56            name,
57            fqn,
58            kind: VariableKind::Let,
59            is_mut,
60            scope: VariableScope::Local,
61            ty,
62        }
63    }
64
65    pub(crate) fn from_const_item<'tcx>(
66        unit: CompileUnit<'tcx>,
67        node: &HirNode<'tcx>,
68        name: String,
69        fqn: String,
70    ) -> Self {
71        let ts_node = node.inner_ts_node();
72        let ty = ts_node
73            .child_by_field_name("type")
74            .map(|n| parse_type_expr(unit, n));
75
76        VariableDescriptor {
77            hir_id: node.hir_id(),
78            name,
79            fqn,
80            kind: VariableKind::Const,
81            is_mut: false,
82            scope: VariableScope::Global,
83            ty,
84        }
85    }
86
87    pub(crate) fn from_static_item<'tcx>(
88        unit: CompileUnit<'tcx>,
89        node: &HirNode<'tcx>,
90        name: String,
91        fqn: String,
92    ) -> Self {
93        let ts_node = node.inner_ts_node();
94        let ty = ts_node
95            .child_by_field_name("type")
96            .map(|n| parse_type_expr(unit, n));
97        let is_mut = has_mutable_specifier(ts_node);
98
99        VariableDescriptor {
100            hir_id: node.hir_id(),
101            name,
102            fqn,
103            kind: VariableKind::Static,
104            is_mut,
105            scope: VariableScope::Global,
106            ty,
107        }
108    }
109}
110
111fn has_mutable_specifier(ts_node: Node<'_>) -> bool {
112    if ts_node.child_by_field_name("mutable_specifier").is_some() {
113        return true;
114    }
115    let mut cursor = ts_node.walk();
116    if cursor.goto_first_child() {
117        loop {
118            if cursor.node().kind() == "mutable_specifier" {
119                return true;
120            }
121            if !cursor.goto_next_sibling() {
122                break;
123            }
124        }
125    }
126    false
127}