leo_passes/symbol_table_creation/
mod.rs1use crate::{CompilerState, Pass, SymbolTable, 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 OptionalType,
30 Program,
31 ProgramScope,
32 ProgramVisitor,
33 StorageVariable,
34 Stub,
35 Type,
36 Variant,
37};
38use leo_errors::Result;
39use leo_span::{Span, Symbol};
40
41use indexmap::IndexMap;
42
43pub struct SymbolTableCreation;
47
48impl Pass for SymbolTableCreation {
49 type Input = ();
50 type Output = ();
51
52 const NAME: &'static str = "SymbolTableCreation";
53
54 fn do_pass(_input: Self::Input, state: &mut CompilerState) -> Result<Self::Output> {
55 let ast = std::mem::take(&mut state.ast);
56 let mut visitor = SymbolTableCreationVisitor {
57 state,
58 structs: IndexMap::new(),
59 program_name: Symbol::intern(""),
60 module: vec![],
61 is_stub: false,
62 };
63 visitor.visit_program(ast.as_repr());
64 visitor.state.handler.last_err()?;
65 visitor.state.ast = ast;
66 Ok(())
67 }
68}
69
70struct SymbolTableCreationVisitor<'a> {
71 state: &'a mut CompilerState,
73 program_name: Symbol,
75 module: Vec<Symbol>,
77 is_stub: bool,
79 structs: IndexMap<Vec<Symbol>, Span>,
81}
82
83impl SymbolTableCreationVisitor<'_> {
84 pub fn in_module_scope<T>(&mut self, module: &[Symbol], func: impl FnOnce(&mut Self) -> T) -> T {
86 let parent_module = self.module.clone();
87 self.module = module.to_vec();
88 let result = func(self);
89 self.module = parent_module;
90 result
91 }
92}
93
94impl AstVisitor for SymbolTableCreationVisitor<'_> {
95 type AdditionalInput = ();
96 type Output = ();
97
98 fn visit_const(&mut self, input: &ConstDeclaration) {
99 let const_path: Vec<Symbol> = self.module.iter().cloned().chain(std::iter::once(input.place.name)).collect();
102 if let Err(err) = self.state.symbol_table.insert_variable(self.program_name, &const_path, VariableSymbol {
103 type_: input.type_.clone(),
104 span: input.place.span,
105 declaration: VariableType::Const,
106 }) {
107 self.state.handler.emit_err(err);
108 }
109 }
110}
111
112impl ProgramVisitor for SymbolTableCreationVisitor<'_> {
113 fn visit_program_scope(&mut self, input: &ProgramScope) {
114 self.program_name = input.program_id.name.name;
116 self.is_stub = false;
117
118 input.consts.iter().for_each(|(_, c)| self.visit_const(c));
120 input.structs.iter().for_each(|(_, c)| self.visit_struct(c));
121 input.mappings.iter().for_each(|(_, c)| self.visit_mapping(c));
122 input.storage_variables.iter().for_each(|(_, c)| self.visit_storage_variable(c));
123 input.functions.iter().for_each(|(_, c)| self.visit_function(c));
124 if let Some(c) = input.constructor.as_ref() {
125 self.visit_constructor(c);
126 }
127 }
128
129 fn visit_module(&mut self, input: &Module) {
130 self.program_name = input.program_name;
131 self.in_module_scope(&input.path.clone(), |slf| {
132 input.structs.iter().for_each(|(_, c)| slf.visit_struct(c));
133 input.functions.iter().for_each(|(_, c)| slf.visit_function(c));
134 input.consts.iter().for_each(|(_, c)| slf.visit_const(c));
135 })
136 }
137
138 fn visit_import(&mut self, input: &Program) {
139 self.visit_program(input)
140 }
141
142 fn visit_struct(&mut self, input: &Composite) {
143 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
145
146 if !input.is_record {
147 if let Some(prev_span) = self.structs.get(&full_name) {
148 return self.state.handler.emit_err(SymbolTable::emit_shadow_error(
150 input.identifier.name,
151 input.identifier.span,
152 *prev_span,
153 ));
154 }
155
156 self.structs.insert(full_name.clone(), input.identifier.span);
157 }
158
159 if input.is_record {
160 let program_name = input.external.unwrap_or(self.program_name);
163 if let Err(err) =
164 self.state.symbol_table.insert_record(Location::new(program_name, full_name), input.clone())
165 {
166 self.state.handler.emit_err(err);
167 }
168 } else if let Err(err) = self.state.symbol_table.insert_struct(self.program_name, &full_name, input.clone()) {
169 self.state.handler.emit_err(err);
170 }
171 }
172
173 fn visit_mapping(&mut self, input: &Mapping) {
174 if let Err(err) = self.state.symbol_table.insert_global(
176 Location::new(self.program_name, vec![input.identifier.name]),
177 VariableSymbol {
178 type_: Type::Mapping(MappingType {
179 key: Box::new(input.key_type.clone()),
180 value: Box::new(input.value_type.clone()),
181 program: self.program_name,
182 }),
183 span: input.span,
184 declaration: VariableType::Storage,
185 },
186 ) {
187 self.state.handler.emit_err(err);
188 }
189 }
190
191 fn visit_storage_variable(&mut self, input: &StorageVariable) {
192 let type_ = match input.type_ {
196 Type::Vector(_) => input.type_.clone(),
197 _ => Type::Optional(OptionalType { inner: Box::new(input.type_.clone()) }),
198 };
199
200 if let Err(err) = self.state.symbol_table.insert_global(
201 Location::new(self.program_name, vec![input.identifier.name]),
202 VariableSymbol { type_, span: input.span, declaration: VariableType::Storage },
203 ) {
204 self.state.handler.emit_err(err);
205 }
206 }
207
208 fn visit_function(&mut self, input: &Function) {
209 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
210 if let Err(err) =
211 self.state.symbol_table.insert_function(Location::new(self.program_name, full_name), input.clone())
212 {
213 self.state.handler.emit_err(err);
214 }
215 }
216
217 fn visit_stub(&mut self, input: &Stub) {
218 self.is_stub = true;
219 self.program_name = input.stub_id.name.name;
220 input.functions.iter().for_each(|(_, c)| self.visit_function_stub(c));
221 input.structs.iter().for_each(|(_, c)| self.visit_struct_stub(c));
222 input.mappings.iter().for_each(|(_, c)| self.visit_mapping(c));
223 }
224
225 fn visit_function_stub(&mut self, input: &FunctionStub) {
226 let location = Location::new(self.program_name, vec![input.name()]);
228 if let Err(err) = self.state.symbol_table.insert_function(location.clone(), Function::from(input.clone())) {
230 self.state.handler.emit_err(err);
231 }
232
233 if matches!(input.variant, Variant::AsyncTransition) {
238 let name = Symbol::intern(&format!("finalize/{}", input.name()));
240 if let Err(err) = self.state.symbol_table.attach_finalizer(
241 location,
242 Location::new(self.program_name, vec![name]),
243 Vec::new(),
244 Vec::new(),
245 ) {
246 self.state.handler.emit_err(err);
247 }
248 }
249 }
250
251 fn visit_struct_stub(&mut self, input: &Composite) {
252 if let Some(program) = input.external {
253 assert_eq!(program, self.program_name);
254 }
255
256 if input.is_record {
257 let program_name = input.external.unwrap_or(self.program_name);
258 if let Err(err) =
259 self.state.symbol_table.insert_record(Location::new(program_name, vec![input.name()]), input.clone())
260 {
261 self.state.handler.emit_err(err);
262 }
263 } else if let Err(err) =
264 self.state.symbol_table.insert_struct(self.program_name, &[input.name()], input.clone())
265 {
266 self.state.handler.emit_err(err);
267 }
268 }
269}