leo_passes/symbol_table_creation/
mod.rs1use crate::{CompilerState, Pass, VariableSymbol, VariableType};
18
19use leo_ast::{
20 AstVisitor,
21 Composite,
22 ConstDeclaration,
23 Function,
24 FunctionStub,
25 Location,
26 Mapping,
27 MappingType,
28 Module,
29 Program,
30 ProgramScope,
31 ProgramVisitor,
32 Stub,
33 Type,
34 Variant,
35};
36use leo_errors::{AstError, LeoError, Result};
37use leo_span::Symbol;
38
39use indexmap::IndexSet;
40
41pub struct SymbolTableCreation;
45
46impl Pass for SymbolTableCreation {
47 type Input = ();
48 type Output = ();
49
50 const NAME: &'static str = "SymbolTableCreation";
51
52 fn do_pass(_input: Self::Input, state: &mut CompilerState) -> Result<Self::Output> {
53 let ast = std::mem::take(&mut state.ast);
54 let mut visitor = SymbolTableCreationVisitor {
55 state,
56 structs: IndexSet::new(),
57 program_name: Symbol::intern(""),
58 module: vec![],
59 is_stub: false,
60 };
61 visitor.visit_program(ast.as_repr());
62 visitor.state.handler.last_err().map_err(|e| *e)?;
63 visitor.state.ast = ast;
64 Ok(())
65 }
66}
67
68struct SymbolTableCreationVisitor<'a> {
69 state: &'a mut CompilerState,
71 program_name: Symbol,
73 module: Vec<Symbol>,
75 is_stub: bool,
77 structs: IndexSet<Vec<Symbol>>,
79}
80
81impl SymbolTableCreationVisitor<'_> {
82 pub fn in_module_scope<T>(&mut self, module: &[Symbol], func: impl FnOnce(&mut Self) -> T) -> T {
84 let parent_module = self.module.clone();
85 self.module = module.to_vec();
86 let result = func(self);
87 self.module = parent_module;
88 result
89 }
90}
91
92impl AstVisitor for SymbolTableCreationVisitor<'_> {
93 type AdditionalInput = ();
94 type Output = ();
95
96 fn visit_const(&mut self, input: &ConstDeclaration) {
97 let const_path: Vec<Symbol> = self.module.iter().cloned().chain(std::iter::once(input.place.name)).collect();
100 if let Err(err) = self.state.symbol_table.insert_variable(self.program_name, &const_path, VariableSymbol {
101 type_: input.type_.clone(),
102 span: input.place.span,
103 declaration: VariableType::Const,
104 }) {
105 self.state.handler.emit_err(err);
106 }
107 }
108}
109
110impl ProgramVisitor for SymbolTableCreationVisitor<'_> {
111 fn visit_program_scope(&mut self, input: &ProgramScope) {
112 self.program_name = input.program_id.name.name;
114 self.is_stub = false;
115
116 input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
118 input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
119 input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
120 input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));
121 if let Some(c) = input.constructor.as_ref() {
122 self.visit_constructor(c);
123 }
124 }
125
126 fn visit_module(&mut self, input: &Module) {
127 self.program_name = input.program_name;
128 self.in_module_scope(&input.path.clone(), |slf| {
129 input.structs.iter().for_each(|(_, c)| (slf.visit_struct(c)));
130 input.functions.iter().for_each(|(_, c)| (slf.visit_function(c)));
131 input.consts.iter().for_each(|(_, c)| (slf.visit_const(c)));
132 })
133 }
134
135 fn visit_import(&mut self, input: &Program) {
136 self.visit_program(input)
137 }
138
139 fn visit_struct(&mut self, input: &Composite) {
140 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
142
143 if !input.is_record && !self.structs.insert(full_name.clone()) {
144 return self.state.handler.emit_err::<LeoError>(AstError::shadowed_struct(input.name(), input.span).into());
145 }
146 if input.is_record {
147 let program_name = input.external.unwrap_or(self.program_name);
150 if let Err(err) =
151 self.state.symbol_table.insert_record(Location::new(program_name, full_name), input.clone())
152 {
153 self.state.handler.emit_err(err);
154 }
155 } else if let Err(err) = self.state.symbol_table.insert_struct(self.program_name, &full_name, input.clone()) {
156 self.state.handler.emit_err(err);
157 }
158 }
159
160 fn visit_mapping(&mut self, input: &Mapping) {
161 if let Err(err) = self.state.symbol_table.insert_global(
163 Location::new(self.program_name, vec![input.identifier.name]),
164 VariableSymbol {
165 type_: Type::Mapping(MappingType {
166 key: Box::new(input.key_type.clone()),
167 value: Box::new(input.value_type.clone()),
168 program: self.program_name,
169 }),
170 span: input.span,
171 declaration: VariableType::Mut,
172 },
173 ) {
174 self.state.handler.emit_err(err);
175 }
176 }
177
178 fn visit_function(&mut self, input: &Function) {
179 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
180 if let Err(err) =
181 self.state.symbol_table.insert_function(Location::new(self.program_name, full_name), input.clone())
182 {
183 self.state.handler.emit_err(err);
184 }
185 }
186
187 fn visit_stub(&mut self, input: &Stub) {
188 self.is_stub = true;
189 self.program_name = input.stub_id.name.name;
190 input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
191 input.structs.iter().for_each(|(_, c)| (self.visit_struct_stub(c)));
192 input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
193 }
194
195 fn visit_function_stub(&mut self, input: &FunctionStub) {
196 let location = Location::new(self.program_name, vec![input.name()]);
198 if let Err(err) = self.state.symbol_table.insert_function(location.clone(), Function::from(input.clone())) {
200 self.state.handler.emit_err(err);
201 }
202
203 if matches!(input.variant, Variant::AsyncTransition) {
208 let name = Symbol::intern(&format!("finalize/{}", input.name()));
210 if let Err(err) = self.state.symbol_table.attach_finalizer(
211 location,
212 Location::new(self.program_name, vec![name]),
213 Vec::new(),
214 Vec::new(),
215 ) {
216 self.state.handler.emit_err(err);
217 }
218 }
219 }
220
221 fn visit_struct_stub(&mut self, input: &Composite) {
222 if let Some(program) = input.external {
223 assert_eq!(program, self.program_name);
224 }
225
226 if input.is_record {
227 let program_name = input.external.unwrap_or(self.program_name);
228 if let Err(err) =
229 self.state.symbol_table.insert_record(Location::new(program_name, vec![input.name()]), input.clone())
230 {
231 self.state.handler.emit_err(err);
232 }
233 } else if let Err(err) =
234 self.state.symbol_table.insert_struct(self.program_name, &[input.name()], input.clone())
235 {
236 self.state.handler.emit_err(err);
237 }
238 }
239}