leo_passes/symbol_table_creation/
mod.rsuse crate::{Pass, SymbolTable, VariableSymbol, VariableType};
use leo_ast::{
Ast,
Composite,
ExpressionVisitor,
Function,
FunctionStub,
Location,
Mapping,
MappingType,
Program,
ProgramScope,
ProgramVisitor,
StatementVisitor,
Stub,
Type,
Variant,
};
use leo_errors::{AstError, LeoError, Result, emitter::Handler};
use leo_span::Symbol;
use indexmap::IndexSet;
pub struct SymbolTableCreator<'a> {
symbol_table: SymbolTable,
handler: &'a Handler,
program_name: 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: Symbol::intern(""),
is_stub: false,
structs: IndexSet::new(),
}
}
}
impl ExpressionVisitor for SymbolTableCreator<'_> {
type AdditionalInput = ();
type Output = ();
}
impl StatementVisitor for SymbolTableCreator<'_> {}
impl ProgramVisitor for SymbolTableCreator<'_> {
fn visit_program_scope(&mut self, input: &ProgramScope) {
self.program_name = 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: &Program) {
self.visit_program(input)
}
fn visit_struct(&mut self, input: &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 input.is_record {
let program_name = input.external.unwrap_or(self.program_name);
if let Err(err) = self.symbol_table.insert_record(Location::new(program_name, input.name()), input.clone())
{
self.handler.emit_err(err);
}
} else if let Err(err) = self.symbol_table.insert_struct(self.program_name, input.name(), input.clone()) {
self.handler.emit_err(err);
}
}
fn visit_mapping(&mut self, input: &Mapping) {
if let Err(err) =
self.symbol_table.insert_global(Location::new(self.program_name, 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,
}),
span: input.span,
declaration: VariableType::Mut,
})
{
self.handler.emit_err(err);
}
}
fn visit_function(&mut self, input: &Function) {
if let Err(err) =
self.symbol_table.insert_function(Location::new(self.program_name, input.name()), input.clone())
{
self.handler.emit_err(err);
}
}
fn visit_stub(&mut self, input: &Stub) {
self.is_stub = true;
self.program_name = 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: &FunctionStub) {
let location = Location::new(self.program_name, input.name());
if let Err(err) = self.symbol_table.insert_function(location, Function::from(input.clone())) {
self.handler.emit_err(err);
}
if matches!(input.variant, Variant::AsyncTransition) {
let name = Symbol::intern(&format!("finalize/{}", input.name()));
if let Err(err) = self.symbol_table.attach_finalizer(
location,
Location::new(self.program_name, name),
Vec::new(),
Vec::new(),
) {
self.handler.emit_err(err);
}
}
}
fn visit_struct_stub(&mut self, input: &Composite) {
if let Some(program) = input.external {
assert_eq!(program, self.program_name);
}
if input.is_record {
let program_name = input.external.unwrap_or(self.program_name);
if let Err(err) = self.symbol_table.insert_record(Location::new(program_name, input.name()), input.clone())
{
self.handler.emit_err(err);
}
} else if let Err(err) = self.symbol_table.insert_struct(self.program_name, input.name(), input.clone()) {
self.handler.emit_err(err);
}
}
}
impl<'a> Pass for SymbolTableCreator<'a> {
type Input = (&'a Ast, &'a Handler);
type Output = Result<SymbolTable>;
fn do_pass((ast, handler): Self::Input) -> Self::Output {
let mut visitor = SymbolTableCreator::new(handler);
visitor.visit_program(ast.as_repr());
handler.last_err().map_err(|e| *e)?;
Ok(visitor.symbol_table)
}
}