use crate::CompilerState;
use leo_ast::*;
use leo_span::{Span, Symbol};
use indexmap::IndexMap;
pub struct OptionLoweringVisitor<'a> {
pub state: &'a mut CompilerState,
pub program: Symbol,
pub module: Vec<Symbol>,
pub function: Option<Symbol>,
pub new_structs: IndexMap<Location, Composite>,
pub reconstructed_composites: IndexMap<Location, Composite>,
}
impl OptionLoweringVisitor<'_> {
pub fn in_module_scope<T>(&mut self, module: &[Symbol], func: impl FnOnce(&mut Self) -> T) -> T {
let parent_module = self.module.clone();
self.module = module.to_vec();
let result = func(self);
self.module = parent_module;
result
}
pub fn wrap_optional_value(&mut self, expr: Expression, ty: Type) -> Expression {
let is_some_expr = Expression::Literal(Literal {
span: Span::default(),
id: self.state.node_builder.next_id(),
variant: LiteralVariant::Boolean(true),
});
let lowered_inner_type = self.reconstruct_type(ty).0;
let struct_name = self.insert_optional_wrapper_struct(&lowered_inner_type);
let struct_expr = CompositeExpression {
path: Path::from(Identifier::new(struct_name, self.state.node_builder.next_id()))
.to_global(Location::new(self.program, vec![struct_name])),
const_arguments: vec![],
members: vec![
CompositeFieldInitializer {
identifier: Identifier::new(Symbol::intern("is_some"), self.state.node_builder.next_id()),
expression: Some(is_some_expr),
span: Span::default(),
id: self.state.node_builder.next_id(),
},
CompositeFieldInitializer {
identifier: Identifier::new(Symbol::intern("val"), self.state.node_builder.next_id()),
expression: Some(expr),
span: Span::default(),
id: self.state.node_builder.next_id(),
},
],
span: Span::default(),
id: self.state.node_builder.next_id(),
};
struct_expr.into()
}
pub fn wrap_none(&mut self, inner_ty: &Type) -> Expression {
let is_some_expr = Expression::Literal(Literal {
span: Span::default(),
id: self.state.node_builder.next_id(),
variant: LiteralVariant::Boolean(false),
});
let lowered_inner_type = self.reconstruct_type(inner_ty.clone()).0;
let reconstructed_composites = &self.reconstructed_composites;
let struct_lookup = |loc: &Location| {
reconstructed_composites
.get(loc) .or_else(|| self.new_structs.get(loc)) .expect("must exist by construction")
.members
.iter()
.map(|mem| (mem.identifier.name, mem.type_.clone()))
.collect()
};
let zero_val_expr =
Expression::zero(&lowered_inner_type, Span::default(), &self.state.node_builder, &struct_lookup)
.expect("this must work if type checking was successful");
let struct_name = self.insert_optional_wrapper_struct(&lowered_inner_type);
let struct_expr = CompositeExpression {
path: Path::from(Identifier::new(struct_name, self.state.node_builder.next_id()))
.to_global(Location::new(self.program, vec![struct_name])),
const_arguments: vec![],
members: vec![
CompositeFieldInitializer {
identifier: Identifier::new(Symbol::intern("is_some"), self.state.node_builder.next_id()),
expression: Some(is_some_expr.clone()),
span: Span::default(),
id: self.state.node_builder.next_id(),
},
CompositeFieldInitializer {
identifier: Identifier::new(Symbol::intern("val"), self.state.node_builder.next_id()),
expression: Some(zero_val_expr.clone()),
span: Span::default(),
id: self.state.node_builder.next_id(),
},
],
span: Span::default(),
id: self.state.node_builder.next_id(),
};
struct_expr.into()
}
pub fn insert_optional_wrapper_struct(&mut self, ty: &Type) -> Symbol {
let struct_name = crate::make_optional_struct_symbol(ty);
self.new_structs.entry(Location::new(self.program, vec![struct_name])).or_insert_with(|| Composite {
identifier: Identifier::new(struct_name, self.state.node_builder.next_id()),
const_parameters: vec![], members: vec![
Member {
mode: Mode::None,
identifier: Identifier::new(Symbol::intern("is_some"), self.state.node_builder.next_id()),
type_: Type::Boolean,
span: Span::default(),
id: self.state.node_builder.next_id(),
},
Member {
mode: Mode::None,
identifier: Identifier::new(Symbol::intern("val"), self.state.node_builder.next_id()),
type_: ty.clone(),
span: Span::default(),
id: self.state.node_builder.next_id(),
},
],
is_record: false,
span: Span::default(),
id: self.state.node_builder.next_id(),
});
struct_name
}
}