kodept_interpret/
semantic_analyzer.rs1use tracing::debug;
2
3use kodept_ast::{
4 AbstFnDecl, BodyFnDecl, EnumDecl, ModDecl,
5 StructDecl, TyParam, TyName, NonTyParam, VarDecl,
6};
7use kodept_ast::graph::{ChangeSet, AnyNode};
8use kodept_ast::traits::Identifiable;
9use kodept_ast::utils::Execution;
10use kodept_ast::visit_side::{VisitGuard, VisitSide};
11use kodept_inference::r#type::MonomorphicType::Constant;
12use kodept_macros::Macro;
13use kodept_macros::traits::Context;
14
15use crate::scope::{ScopeError, ScopeTree};
16
17pub struct ScopeAnalyzer(ScopeTree);
18
19impl Default for ScopeAnalyzer {
20 fn default() -> Self {
21 Self(ScopeTree::new())
22 }
23}
24
25impl ScopeAnalyzer {
26 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn into_inner(self) -> ScopeTree {
31 self.0
32 }
33
34 fn divide_by_scopes(
35 &mut self,
36 node: &AnyNode,
37 side: VisitSide,
38 ) -> Result<(), ScopeError> {
39 let divide = match node {
40 AnyNode::ModDecl(ModDecl { name, .. }) => Some(Some(name)),
41 AnyNode::StructDecl(StructDecl { name, .. }) => Some(Some(name)),
42 AnyNode::EnumDecl(EnumDecl { name, .. }) => Some(Some(name)),
43 AnyNode::AbstFnDecl(AbstFnDecl { name, .. }) => {
44 Some(Some(name))
45 }
46 AnyNode::BodyFnDecl(BodyFnDecl { name, .. }) => {
47 Some(Some(name))
48 }
49 AnyNode::FileDecl(_) => Some(None),
50 AnyNode::Exprs(_) => Some(None),
51 AnyNode::Lambda(_) => Some(None),
52 AnyNode::IfExpr(_) => Some(None),
53 AnyNode::ElifExpr(_) => Some(None),
54 AnyNode::ElseExpr(_) => Some(None),
55 _ => None,
56 };
57
58 if let Some(name) = divide {
59 if side == VisitSide::Entering {
60 self.0.push_scope(node, name)
61 }
62 if side == VisitSide::Exiting {
63 self.0.pop_scope()?
64 }
65 }
66 Ok(())
67 }
68}
69
70impl Macro for ScopeAnalyzer {
71 type Error = ScopeError;
72 type Node = AnyNode;
73
74 fn transform(
75 &mut self,
76 guard: VisitGuard<Self::Node>,
77 context: &mut impl Context,
78 ) -> Execution<Self::Error, ChangeSet> {
79 let (node, side) = guard.allow_all();
80
81 if side == VisitSide::Exiting {
82 debug!("{:#?}", self.0);
83 }
84
85 self.divide_by_scopes(&node, side)?;
86
87 if !matches!(side, VisitSide::Exiting | VisitSide::Leaf) {
88 return Execution::Skipped;
89 }
90
91 let Ok(scope) = self.0.current_mut() else {
92 return Execution::Skipped;
93 };
94 let Some(tree) = context.tree().upgrade() else {
95 return Execution::Skipped;
96 };
97 match &*node {
98 AnyNode::StructDecl(StructDecl { name, .. }) => {
99 scope.insert_type(name, Constant(name.clone()))?;
100 }
101 AnyNode::TyParam(TyParam { name, .. }) => {
102 scope.insert_var(node.get_id(), name)?;
103 }
104 AnyNode::NonTyParam(NonTyParam { name, .. }) => {
105 scope.insert_var(node.get_id(), name)?;
106 }
107 AnyNode::TyName(TyName { name, .. }) => {
108 if let Some(AnyNode::EnumDecl(_)) = tree.parent_of(node.get_id(), node.token()) {
109 scope.insert_type(name, Constant(name.clone()))?;
110 }
111 }
112 AnyNode::EnumDecl(EnumDecl { name, .. }) => {
113 scope.insert_type(name, Constant(name.clone()))?;
114 }
115 AnyNode::VarDecl(VarDecl { name, .. }) => scope.insert_var(node.get_id(), name)?,
116 AnyNode::BodyFnDecl(BodyFnDecl { name, .. }) => {
117 scope.insert_var(node.get_id(), name)?;
118 }
119 AnyNode::AbstFnDecl(AbstFnDecl { name, .. }) => {
120 scope.insert_var(node.get_id(), name)?
121 }
122 _ => {}
123 }
124
125 Execution::Completed(ChangeSet::new())
126 }
127}