use super::OptionLoweringVisitor;
use leo_ast::{
AstReconstructor,
ConstParameter,
Function,
Input,
Location,
Module,
Output,
Program,
ProgramReconstructor,
ProgramScope,
Statement,
};
use leo_span::Symbol;
impl ProgramReconstructor for OptionLoweringVisitor<'_> {
fn reconstruct_program(&mut self, input: Program) -> Program {
self.program =
*input.program_scopes.first().expect("a program must have a single program scope at this time.").0;
for (_, scope) in &input.program_scopes {
self.program = scope.program_id.name.name;
for (_, c) in &scope.composites {
let new_composite = self.reconstruct_composite(c.clone());
self.reconstructed_composites
.insert(Location::new(scope.program_id.name.name, vec![new_composite.name()]), new_composite);
}
}
for (module_path, module) in &input.modules {
self.program = module.program_name;
for (_, c) in &module.composites {
let full_name = module_path.iter().cloned().chain(std::iter::once(c.name())).collect::<Vec<Symbol>>();
let new_composite = self.reconstruct_composite(c.clone());
self.reconstructed_composites
.insert(Location::new(module.program_name, full_name), new_composite.clone());
}
}
Program {
modules: input.modules.into_iter().map(|(id, module)| (id, self.reconstruct_module(module))).collect(),
imports: input.imports,
stubs: input.stubs.into_iter().map(|(id, stub)| (id, self.reconstruct_stub(stub))).collect(),
program_scopes: input
.program_scopes
.into_iter()
.map(|(id, scope)| (id, self.reconstruct_program_scope(scope)))
.collect(),
}
}
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
self.program = input.program_id.name.name;
let mut program = ProgramScope {
consts: input
.consts
.into_iter()
.map(|(i, c)| match self.reconstruct_const(c) {
(Statement::Const(decl), _) => (i, decl),
_ => panic!("`reconstruct_const` can only return `Statement::Const`"),
})
.collect(),
composites: self
.reconstructed_composites
.iter()
.filter_map(|(loc, c)| {
loc.path
.split_last()
.filter(|(_, rest)| rest.is_empty() && loc.program == self.program)
.map(|(last, _)| (*last, c.clone()))
})
.collect(),
mappings: input.mappings.into_iter().map(|(id, m)| (id, self.reconstruct_mapping(m))).collect(),
storage_variables: input
.storage_variables
.into_iter()
.map(|(id, v)| (id, self.reconstruct_storage_variable(v)))
.collect(),
functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function(f))).collect(),
constructor: input.constructor.map(|c| self.reconstruct_constructor(c)),
..input
};
program.composites.extend(self.new_structs.drain(..).map(|(location, composite)| {
assert_eq!(location.program, self.program);
assert_eq!(location.path.len(), 1);
let symbol = location.path[0];
(symbol, composite)
}));
program
}
fn reconstruct_module(&mut self, input: Module) -> Module {
self.program = input.program_name;
self.in_module_scope(&input.path.clone(), |slf| Module {
consts: input
.consts
.into_iter()
.map(|(i, c)| match slf.reconstruct_const(c) {
(Statement::Const(declaration), _) => (i, declaration),
_ => panic!("`reconstruct_const` can only return `Statement::Const`"),
})
.collect(),
composites: slf
.reconstructed_composites
.iter()
.filter_map(|(loc, c)| {
loc.path
.split_last()
.filter(|(_, rest)| *rest == input.path && loc.program == slf.program)
.map(|(last, _)| (*last, c.clone()))
})
.collect(),
functions: input.functions.into_iter().map(|(i, f)| (i, slf.reconstruct_function(f))).collect(),
..input
})
}
fn reconstruct_function(&mut self, input: Function) -> Function {
self.function = Some(input.identifier.name);
Function {
const_parameters: input
.const_parameters
.iter()
.map(|param| ConstParameter { type_: self.reconstruct_type(param.type_.clone()).0, ..param.clone() })
.collect(),
input: input
.input
.iter()
.map(|input| Input { type_: self.reconstruct_type(input.type_.clone()).0, ..input.clone() })
.collect(),
output: input
.output
.iter()
.map(|output| Output { type_: self.reconstruct_type(output.type_.clone()).0, ..output.clone() })
.collect(),
output_type: self.reconstruct_type(input.output_type).0,
block: self.reconstruct_block(input.block).0,
..input
}
}
}