use indexmap::IndexSet;
use leo_ast::*;
use leo_errors::{AstError, LeoError, emitter::Handler};
use leo_span::Symbol;
use crate::{SymbolTable, VariableSymbol, VariableType};
pub struct SymbolTableCreator<'a> {
pub(crate) symbol_table: SymbolTable,
handler: &'a Handler,
program_name: Option<Symbol>,
is_stub: bool,
structs: IndexSet<Symbol>,
}
impl<'a> SymbolTableCreator<'a> {
pub fn new(handler: &'a Handler) -> Self {
Self { symbol_table: Default::default(), handler, program_name: None, is_stub: false, structs: IndexSet::new() }
}
}
impl<'a> ExpressionVisitor<'a> for SymbolTableCreator<'a> {
type AdditionalInput = ();
type Output = ();
}
impl<'a> StatementVisitor<'a> for SymbolTableCreator<'a> {}
impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
fn visit_program_scope(&mut self, input: &'a ProgramScope) {
self.program_name = Some(input.program_id.name.name);
self.is_stub = false;
input.structs.iter().for_each(|(_, c)| (self.visit_struct(c)));
input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
input.functions.iter().for_each(|(_, c)| (self.visit_function(c)));
input.consts.iter().for_each(|(_, c)| (self.visit_const(c)));
}
fn visit_import(&mut self, input: &'a Program) {
self.visit_program(input)
}
fn visit_struct(&mut self, input: &'a Composite) {
if !input.is_record && !self.structs.insert(input.name()) {
return self.handler.emit_err::<LeoError>(AstError::shadowed_struct(input.name(), input.span).into());
}
if let Err(err) = self.symbol_table.insert_struct(Location::new(input.external, input.name()), input) {
self.handler.emit_err(err);
}
}
fn visit_mapping(&mut self, input: &'a Mapping) {
let program = match self.is_stub {
true => self.program_name,
false => None,
};
if let Err(err) =
self.symbol_table.insert_variable(Location::new(program, input.identifier.name), VariableSymbol {
type_: Type::Mapping(MappingType {
key: Box::new(input.key_type.clone()),
value: Box::new(input.value_type.clone()),
program: self.program_name.unwrap(),
}),
span: input.span,
declaration: VariableType::Mut,
})
{
self.handler.emit_err(err);
}
}
fn visit_function(&mut self, input: &'a Function) {
if let Err(err) = self.symbol_table.insert_fn(Location::new(self.program_name, input.name()), input) {
self.handler.emit_err(err);
}
}
fn visit_stub(&mut self, input: &'a Stub) {
self.is_stub = true;
self.program_name = Some(input.stub_id.name.name);
input.functions.iter().for_each(|(_, c)| (self.visit_function_stub(c)));
input.structs.iter().for_each(|(_, c)| (self.visit_struct_stub(c)));
input.mappings.iter().for_each(|(_, c)| (self.visit_mapping(c)));
}
fn visit_function_stub(&mut self, input: &'a FunctionStub) {
if let Err(err) =
self.symbol_table.insert_fn(Location::new(self.program_name, input.name()), &Function::from(input.clone()))
{
self.handler.emit_err(err);
}
}
fn visit_struct_stub(&mut self, input: &'a Composite) {
if let Err(err) = self.symbol_table.insert_struct(Location::new(input.external, input.name()), input) {
self.handler.emit_err(err);
}
}
}