leo_passes/symbol_table_creation/
mod.rs1use crate::{CompilerState, Pass, VariableSymbol, VariableType};
18
19use leo_ast::{
20 Composite,
21 ExpressionVisitor,
22 Function,
23 FunctionStub,
24 Location,
25 Mapping,
26 MappingType,
27 Program,
28 ProgramScope,
29 ProgramVisitor,
30 StatementVisitor,
31 Stub,
32 Type,
33 TypeVisitor,
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 is_stub: false,
59 };
60 visitor.visit_program(ast.as_repr());
61 visitor.state.handler.last_err().map_err(|e| *e)?;
62 visitor.state.ast = ast;
63 Ok(())
64 }
65}
66
67struct SymbolTableCreationVisitor<'a> {
68 state: &'a mut CompilerState,
70 program_name: Symbol,
72 is_stub: bool,
74 structs: IndexSet<Symbol>,
76}
77
78impl ExpressionVisitor for SymbolTableCreationVisitor<'_> {
79 type AdditionalInput = ();
80 type Output = ();
81}
82
83impl TypeVisitor for SymbolTableCreationVisitor<'_> {}
84
85impl StatementVisitor for SymbolTableCreationVisitor<'_> {}
86
87impl ProgramVisitor for SymbolTableCreationVisitor<'_> {
88 fn visit_program_scope(&mut self, input: &ProgramScope) {
89 self.program_name = input.program_id.name.name;
91 self.is_stub = false;
92
93 input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
95 input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
96 input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));
97 input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
98 }
99
100 fn visit_import(&mut self, input: &Program) {
101 self.visit_program(input)
102 }
103
104 fn visit_struct(&mut self, input: &Composite) {
105 if !input.is_record && !self.structs.insert(input.name()) {
107 return self.state.handler.emit_err::<LeoError>(AstError::shadowed_struct(input.name(), input.span).into());
108 }
109 if input.is_record {
110 let program_name = input.external.unwrap_or(self.program_name);
111 if let Err(err) =
112 self.state.symbol_table.insert_record(Location::new(program_name, input.name()), input.clone())
113 {
114 self.state.handler.emit_err(err);
115 }
116 } else if let Err(err) = self.state.symbol_table.insert_struct(self.program_name, input.name(), input.clone()) {
117 self.state.handler.emit_err(err);
118 }
119 }
120
121 fn visit_mapping(&mut self, input: &Mapping) {
122 if let Err(err) = self.state.symbol_table.insert_global(
124 Location::new(self.program_name, input.identifier.name),
125 VariableSymbol {
126 type_: Type::Mapping(MappingType {
127 key: Box::new(input.key_type.clone()),
128 value: Box::new(input.value_type.clone()),
129 program: self.program_name,
130 }),
131 span: input.span,
132 declaration: VariableType::Mut,
133 },
134 ) {
135 self.state.handler.emit_err(err);
136 }
137 }
138
139 fn visit_function(&mut self, input: &Function) {
140 if let Err(err) =
141 self.state.symbol_table.insert_function(Location::new(self.program_name, input.name()), input.clone())
142 {
143 self.state.handler.emit_err(err);
144 }
145 }
146
147 fn visit_stub(&mut self, input: &Stub) {
148 self.is_stub = true;
149 self.program_name = input.stub_id.name.name;
150 input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
151 input.structs.iter().for_each(|(_, c)| (self.visit_struct_stub(c)));
152 input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
153 }
154
155 fn visit_function_stub(&mut self, input: &FunctionStub) {
156 let location = Location::new(self.program_name, input.name());
158 if let Err(err) = self.state.symbol_table.insert_function(location, Function::from(input.clone())) {
160 self.state.handler.emit_err(err);
161 }
162
163 if matches!(input.variant, Variant::AsyncTransition) {
168 let name = Symbol::intern(&format!("finalize/{}", input.name()));
170 if let Err(err) = self.state.symbol_table.attach_finalizer(
171 location,
172 Location::new(self.program_name, name),
173 Vec::new(),
174 Vec::new(),
175 ) {
176 self.state.handler.emit_err(err);
177 }
178 }
179 }
180
181 fn visit_struct_stub(&mut self, input: &Composite) {
182 if let Some(program) = input.external {
183 assert_eq!(program, self.program_name);
184 }
185
186 if input.is_record {
187 let program_name = input.external.unwrap_or(self.program_name);
188 if let Err(err) =
189 self.state.symbol_table.insert_record(Location::new(program_name, input.name()), input.clone())
190 {
191 self.state.handler.emit_err(err);
192 }
193 } else if let Err(err) = self.state.symbol_table.insert_struct(self.program_name, input.name(), input.clone()) {
194 self.state.handler.emit_err(err);
195 }
196 }
197}