aiken/crates/lang/src/uplc_two.rs

2102 lines
83 KiB
Rust

use std::{collections::HashMap, ops::Deref, sync::Arc, vec};
use indexmap::IndexMap;
use itertools::Itertools;
use uplc::{
ast::{
builder::{self, constr_index_exposer, CONSTR_FIELDS_EXPOSER, CONSTR_GET_FIELD},
Constant, Name, Program, Term,
},
builtins::DefaultFunction,
parser::interner::Interner,
BigInt, PlutusData,
};
use crate::{
ast::{ArgName, AssignmentKind, BinOp, DataType, Function, Pattern, Span, TypedArg},
expr::TypedExpr,
ir::IR,
tipo::{self, Type, TypeInfo, ValueConstructor, ValueConstructorVariant},
uplc::{DataTypeKey, FunctionAccessKey},
IdGenerator,
};
#[derive(Clone, Debug)]
pub struct FuncComponents {
ir: Vec<IR>,
dependencies: Vec<FunctionAccessKey>,
args: Vec<String>,
recursive: bool,
}
// #[derive(Clone, Debug)]
// pub struct FuncIndex {
// index: usize,
// scope: Vec<u8>,
// occurrences: Vec<String>,
// }
pub struct CodeGenerator<'a> {
defined_functions: HashMap<FunctionAccessKey, ()>,
functions: &'a HashMap<FunctionAccessKey, &'a Function<Arc<tipo::Type>, TypedExpr>>,
// type_aliases: &'a HashMap<(String, String), &'a TypeAlias<Arc<tipo::Type>>>,
data_types: &'a HashMap<DataTypeKey, &'a DataType<Arc<tipo::Type>>>,
// imports: &'a HashMap<(String, String), &'a Use<String>>,
// constants: &'a HashMap<(String, String), &'a ModuleConstant<Arc<tipo::Type>, String>>,
module_types: &'a HashMap<String, TypeInfo>,
id_gen: IdGenerator,
needs_field_access: bool,
}
impl<'a> CodeGenerator<'a> {
pub fn new(
functions: &'a HashMap<FunctionAccessKey, &'a Function<Arc<tipo::Type>, TypedExpr>>,
// type_aliases: &'a HashMap<(String, String), &'a TypeAlias<Arc<tipo::Type>>>,
data_types: &'a HashMap<DataTypeKey, &'a DataType<Arc<tipo::Type>>>,
// imports: &'a HashMap<(String, String), &'a Use<String>>,
// constants: &'a HashMap<(String, String), &'a ModuleConstant<Arc<tipo::Type>, String>>,
module_types: &'a HashMap<String, TypeInfo>,
) -> Self {
CodeGenerator {
defined_functions: HashMap::new(),
functions,
// type_aliases,
data_types,
// imports,
// constants,
module_types,
id_gen: IdGenerator::new(),
needs_field_access: false,
}
}
pub fn generate(&mut self, body: TypedExpr, arguments: Vec<TypedArg>) -> Program<Name> {
let mut ir_stack = vec![];
let scope = vec![self.id_gen.next()];
self.build_ir(&body, &mut ir_stack, scope);
println!("{ir_stack:#?}");
self.define_ir(&mut ir_stack);
println!("{ir_stack:#?}");
let mut term = self.uplc_code_gen(&mut ir_stack);
if self.needs_field_access {
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
}
// Wrap the validator body if ifThenElse term unit error
term = builder::final_wrapper(term);
for arg in arguments.iter().rev() {
term = Term::Lambda {
parameter_name: uplc::ast::Name {
text: arg.arg_name.get_variable_name().unwrap_or("_").to_string(),
unique: 0.into(),
},
body: term.into(),
}
}
let mut program = Program {
version: (1, 0, 0),
term,
};
let mut interner = Interner::new();
println!("{}", program.to_pretty());
interner.program(&mut program);
program
}
pub(crate) fn build_ir(&mut self, body: &TypedExpr, ir_stack: &mut Vec<IR>, scope: Vec<u64>) {
match body {
TypedExpr::Int { value, .. } => ir_stack.push(IR::Int {
scope,
value: value.to_string(),
}),
TypedExpr::String { value, .. } => ir_stack.push(IR::String {
scope,
value: value.to_string(),
}),
TypedExpr::ByteArray { bytes, .. } => ir_stack.push(IR::ByteArray {
scope,
bytes: bytes.to_vec(),
}),
TypedExpr::Sequence { expressions, .. } => {
for expr in expressions {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
self.build_ir(expr, ir_stack, scope);
}
}
TypedExpr::Pipeline { expressions, .. } => {
for expr in expressions {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
self.build_ir(expr, ir_stack, scope);
}
}
TypedExpr::Var {
constructor, name, ..
} => {
ir_stack.push(IR::Var {
scope,
constructor: constructor.clone(),
name: name.clone(),
});
}
TypedExpr::Fn { .. } => todo!(),
TypedExpr::List {
elements,
tail,
tipo,
..
} => {
ir_stack.push(IR::List {
scope: scope.clone(),
count: if tail.is_some() {
elements.len() + 1
} else {
elements.len()
},
tipo: tipo.clone(),
tail: tail.is_some(),
});
for element in elements {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
self.build_ir(element, ir_stack, scope.clone())
}
if let Some(tail) = tail {
let mut scope = scope;
scope.push(self.id_gen.next());
ir_stack.push(IR::Tail {
scope: scope.clone(),
count: 1,
});
self.build_ir(tail, ir_stack, scope);
}
}
TypedExpr::Call { fun, args, .. } => {
ir_stack.push(IR::Call {
scope: scope.clone(),
count: args.len() + 1,
});
let mut scope_fun = scope.clone();
scope_fun.push(self.id_gen.next());
self.build_ir(fun, ir_stack, scope_fun);
for arg in args {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
self.build_ir(&arg.value, ir_stack, scope);
}
}
TypedExpr::BinOp {
name, left, right, ..
} => {
ir_stack.push(IR::BinOp {
scope: scope.clone(),
name: *name,
count: 2,
tipo: left.tipo(),
});
let mut scope_left = scope.clone();
scope_left.push(self.id_gen.next());
let mut scope_right = scope;
scope_right.push(self.id_gen.next());
self.build_ir(left, ir_stack, scope_left);
self.build_ir(right, ir_stack, scope_right);
}
TypedExpr::Assignment {
value,
pattern,
kind,
tipo,
..
} => {
let mut define_vec: Vec<IR> = vec![];
let mut value_vec: Vec<IR> = vec![];
let mut pattern_vec: Vec<IR> = vec![];
let mut value_scope = scope.clone();
value_scope.push(self.id_gen.next());
self.build_ir(value, &mut value_vec, value_scope);
self.assignment_ir(
pattern,
&mut pattern_vec,
&mut value_vec,
tipo,
*kind,
scope,
);
ir_stack.append(&mut define_vec);
ir_stack.append(&mut pattern_vec);
}
TypedExpr::Trace { .. } => todo!(),
TypedExpr::When {
subjects, clauses, ..
} => {
let subject_name = format!("__subject_name_{}", self.id_gen.next());
let constr_var = format!("__constr_name_{}", self.id_gen.next());
// assuming one subject at the moment
let subject = subjects[0].clone();
let mut needs_constr_var = false;
if let Some((last_clause, clauses)) = clauses.split_last() {
let mut clauses_vec = vec![];
let mut pattern_vec = vec![];
for clause in clauses {
let mut scope = scope.clone();
scope.push(self.id_gen.next());
pattern_vec.push(IR::Clause {
scope: scope.clone(),
count: 2,
tipo: subject.tipo().clone(),
subject_name: subject_name.clone(),
});
self.build_ir(&clause.then, &mut clauses_vec, scope.clone());
self.when_ir(
&clause.pattern[0],
&mut pattern_vec,
&mut clauses_vec,
&subject.tipo(),
constr_var.clone(),
&mut needs_constr_var,
scope,
);
}
let last_pattern = &last_clause.pattern[0];
let mut final_scope = scope.clone();
final_scope.push(self.id_gen.next());
pattern_vec.push(IR::Finally {
scope: final_scope.clone(),
});
self.build_ir(&last_clause.then, &mut clauses_vec, final_scope.clone());
self.when_ir(
last_pattern,
&mut pattern_vec,
&mut clauses_vec,
&subject.tipo(),
constr_var.clone(),
&mut needs_constr_var,
final_scope,
);
if needs_constr_var {
ir_stack.push(IR::Lam {
scope: scope.clone(),
name: constr_var.clone(),
});
self.build_ir(&subject, ir_stack, scope.clone());
ir_stack.push(IR::When {
scope: scope.clone(),
count: clauses.len() + 1,
subject_name,
tipo: subject.tipo(),
});
let mut scope = scope;
scope.push(self.id_gen.next());
ir_stack.push(IR::Var {
scope,
constructor: ValueConstructor::public(
subject.tipo(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: constr_var,
})
} else {
ir_stack.push(IR::When {
scope: scope.clone(),
count: clauses.len() + 1,
subject_name,
tipo: subject.tipo(),
});
let mut scope = scope;
scope.push(self.id_gen.next());
self.build_ir(&subject, ir_stack, scope);
}
ir_stack.append(&mut pattern_vec);
};
}
TypedExpr::If { .. } => {
todo!()
}
TypedExpr::RecordAccess {
record,
index,
tipo,
..
} => {
self.needs_field_access = true;
ir_stack.push(IR::RecordAccess {
scope: scope.clone(),
index: *index,
tipo: tipo.clone(),
});
self.build_ir(record, ir_stack, scope);
}
TypedExpr::ModuleSelect {
constructor,
module_name,
..
} => match constructor {
tipo::ModuleValueConstructor::Record { .. } => todo!(),
tipo::ModuleValueConstructor::Fn { name, .. } => {
let func = self.functions.get(&FunctionAccessKey {
module_name: module_name.clone(),
function_name: name.clone(),
});
if let Some(_func) = func {
todo!()
} else {
let type_info = self.module_types.get(module_name).unwrap();
let value = type_info.values.get(name).unwrap();
match &value.variant {
ValueConstructorVariant::ModuleFn { builtin, .. } => {
let builtin = builtin.unwrap();
ir_stack.push(IR::Builtin {
func: builtin,
scope,
});
}
_ => unreachable!(),
}
}
}
tipo::ModuleValueConstructor::Constant { .. } => todo!(),
},
TypedExpr::Todo { .. } => todo!(),
TypedExpr::RecordUpdate { .. } => todo!(),
TypedExpr::Negate { .. } => todo!(),
TypedExpr::Tuple { .. } => todo!(),
}
}
fn assignment_ir(
&mut self,
pattern: &Pattern<tipo::PatternConstructor, Arc<Type>>,
pattern_vec: &mut Vec<IR>,
value_vec: &mut Vec<IR>,
_tipo: &Type,
kind: AssignmentKind,
scope: Vec<u64>,
) {
match pattern {
Pattern::Int { .. } => todo!(),
Pattern::String { .. } => todo!(),
Pattern::Var { name, .. } => {
pattern_vec.push(IR::Assignment {
name: name.clone(),
kind,
scope,
});
pattern_vec.append(value_vec);
}
Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => todo!(),
list @ Pattern::List { .. } => {
self.pattern_ir(list, pattern_vec, value_vec, scope);
}
Pattern::Constructor { .. } => todo!(),
Pattern::Tuple { .. } => todo!(),
}
}
fn when_ir(
&mut self,
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
pattern_vec: &mut Vec<IR>,
values: &mut Vec<IR>,
tipo: &Type,
constr_var: String,
needs_constr_var: &mut bool,
scope: Vec<u64>,
) {
match pattern {
Pattern::Int { value, .. } => {
pattern_vec.push(IR::Int {
scope,
value: value.clone(),
});
pattern_vec.append(values);
}
Pattern::String { .. } => todo!(),
Pattern::Var { name, .. } => {
pattern_vec.push(IR::Var {
scope,
name: name.clone(),
constructor: ValueConstructor::public(
tipo.clone().into(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
});
pattern_vec.append(values);
}
Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => {
pattern_vec.push(IR::Discard { scope });
pattern_vec.append(values);
}
Pattern::List { .. } => todo!(),
Pattern::Constructor { arguments, .. } => {
let mut needs_access_to_constr_var = false;
for arg in arguments {
match arg.value {
Pattern::Var { .. }
| Pattern::List { .. }
| Pattern::Constructor { .. } => {
needs_access_to_constr_var = true;
}
_ => {}
}
}
let mut new_vec = vec![IR::Var {
constructor: ValueConstructor::public(
tipo.clone().into(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: constr_var,
scope: scope.clone(),
}];
if needs_access_to_constr_var {
*needs_constr_var = true;
new_vec.append(values);
self.pattern_ir(pattern, pattern_vec, &mut new_vec, scope);
} else {
self.pattern_ir(pattern, pattern_vec, values, scope);
}
}
Pattern::Tuple { .. } => todo!(),
}
}
fn pattern_ir(
&mut self,
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
pattern_vec: &mut Vec<IR>,
values: &mut Vec<IR>,
scope: Vec<u64>,
) {
match pattern {
Pattern::Int { .. } => todo!(),
Pattern::String { .. } => todo!(),
Pattern::Var { .. } => todo!(),
Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(),
Pattern::Discard { .. } => {
pattern_vec.push(IR::Discard { scope });
pattern_vec.append(values);
}
Pattern::List { elements, tail, .. } => {
let mut elements_vec = vec![];
let mut names = vec![];
for element in elements {
match element {
Pattern::Var { name, .. } => {
names.push(name.clone());
}
a @ Pattern::List { .. } => {
let mut var_vec = vec![];
let item_name = format!("list_item_id_{}", self.id_gen.next());
names.push(item_name.clone());
var_vec.push(IR::Var {
constructor: ValueConstructor::public(
Type::App {
public: true,
module: String::new(),
name: String::new(),
args: vec![],
}
.into(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: item_name,
scope: scope.clone(),
});
self.pattern_ir(a, &mut elements_vec, &mut var_vec, scope.clone());
}
_ => todo!(),
}
}
if let Some(tail) = tail {
match &**tail {
Pattern::Var { name, .. } => names.push(name.clone()),
Pattern::Discard { .. } => {}
_ => unreachable!(),
}
}
pattern_vec.push(IR::ListAccessor {
names,
tail: tail.is_some(),
scope,
});
pattern_vec.append(values);
pattern_vec.append(&mut elements_vec);
}
Pattern::Constructor {
is_record,
name: constr_name,
arguments,
constructor,
tipo,
..
} => {
let data_type_key = match tipo.as_ref() {
Type::Fn { ret, .. } => match &**ret {
Type::App { module, name, .. } => DataTypeKey {
module_name: module.clone(),
defined_type: name.clone(),
},
_ => unreachable!(),
},
Type::App { module, name, .. } => DataTypeKey {
module_name: module.clone(),
defined_type: name.clone(),
},
_ => unreachable!(),
};
let data_type = self.data_types.get(&data_type_key).unwrap();
let (index, constructor_type) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, dt)| &dt.name == constr_name)
.unwrap();
// push constructor Index
pattern_vec.push(IR::Int {
value: index.to_string(),
scope: scope.clone(),
});
if *is_record {
let field_map = match constructor {
tipo::PatternConstructor::Record { field_map, .. } => {
field_map.clone().unwrap()
}
};
let mut type_map: HashMap<String, Arc<Type>> = HashMap::new();
for arg in &constructor_type.arguments {
let label = arg.label.clone().unwrap();
let field_type = arg.tipo.clone();
type_map.insert(label, field_type);
}
let arguments_index = arguments
.iter()
.map(|item| {
let label = item.label.clone().unwrap_or_default();
let field_index = field_map.fields.get(&label).unwrap_or(&0);
let (discard, var_name) = match &item.value {
Pattern::Var { name, .. } => (false, name.clone()),
Pattern::Discard { .. } => (true, "".to_string()),
Pattern::List { .. } => todo!(),
Pattern::Constructor { .. } => todo!(),
_ => todo!(),
};
(label, var_name, *field_index, discard)
})
.filter(|(_, _, _, discard)| !discard)
.sorted_by(|item1, item2| item1.2.cmp(&item2.2))
.collect::<Vec<(String, String, usize, bool)>>();
if !arguments_index.is_empty() {
pattern_vec.push(IR::FieldsExpose {
count: arguments_index.len() + 2,
indices: arguments_index
.iter()
.map(|(label, var_name, index, _)| {
let field_type = type_map.get(label).unwrap();
(*index, var_name.clone(), field_type.clone())
})
.collect_vec(),
scope,
});
}
} else {
let mut type_map: HashMap<usize, Arc<Type>> = HashMap::new();
for (index, arg) in constructor_type.arguments.iter().enumerate() {
let field_type = arg.tipo.clone();
type_map.insert(index, field_type);
}
let arguments_index = arguments
.iter()
.enumerate()
.map(|(index, item)| {
let (discard, var_name) = match &item.value {
Pattern::Var { name, .. } => (false, name.clone()),
Pattern::Discard { .. } => (true, "".to_string()),
Pattern::List { .. } => todo!(),
Pattern::Constructor { .. } => todo!(),
_ => todo!(),
};
(var_name, index, discard)
})
.filter(|(_, _, discard)| !discard)
.collect::<Vec<(String, usize, bool)>>();
if !arguments_index.is_empty() {
pattern_vec.push(IR::FieldsExpose {
count: arguments_index.len() + 2,
indices: arguments_index
.iter()
.map(|(name, index, _)| {
let field_type = type_map.get(index).unwrap();
(*index, name.clone(), field_type.clone())
})
.collect_vec(),
scope,
});
}
}
pattern_vec.append(values);
}
Pattern::Tuple { .. } => todo!(),
}
}
fn uplc_code_gen(&mut self, ir_stack: &mut Vec<IR>) -> Term<Name> {
let mut arg_stack: Vec<Term<Name>> = vec![];
while let Some(ir_element) = ir_stack.pop() {
self.gen_uplc(ir_element, &mut arg_stack);
}
arg_stack[0].clone()
}
fn gen_uplc(&mut self, ir: IR, arg_stack: &mut Vec<Term<Name>>) {
match ir {
IR::Int { value, .. } => {
let integer = value.parse().unwrap();
let term = Term::Constant(Constant::Integer(integer));
arg_stack.push(term);
}
IR::String { value, .. } => {
let term = Term::Constant(Constant::String(value));
arg_stack.push(term);
}
IR::ByteArray { bytes, .. } => {
let term = Term::Constant(Constant::ByteString(bytes));
arg_stack.push(term);
}
IR::Var {
name, constructor, ..
} => match constructor.variant {
ValueConstructorVariant::LocalVariable { .. } => arg_stack.push(Term::Var(Name {
text: name,
unique: 0.into(),
})),
ValueConstructorVariant::ModuleConstant { .. } => todo!(),
ValueConstructorVariant::ModuleFn { .. } => arg_stack.push(Term::Var(Name {
text: name,
unique: 0.into(),
})),
ValueConstructorVariant::Record {
name: constr_name, ..
} => {
let data_type_key = match &*constructor.tipo {
Type::App { module, name, .. } => DataTypeKey {
module_name: module.to_string(),
defined_type: name.to_string(),
},
Type::Fn { ret, .. } => match ret.deref() {
Type::App { module, name, .. } => DataTypeKey {
module_name: module.to_string(),
defined_type: name.to_string(),
},
_ => unreachable!(),
},
Type::Var { .. } => todo!(),
Type::Tuple { .. } => todo!(),
};
if data_type_key.defined_type == "Bool" {
arg_stack.push(Term::Constant(Constant::Bool(constr_name == "True")));
} else {
let data_type = self.data_types.get(&data_type_key).unwrap();
let (constr_index, _constr) = data_type
.constructors
.iter()
.enumerate()
.find(|(_, x)| x.name == *constr_name)
.unwrap();
let term = Term::Apply {
function: Term::Builtin(DefaultFunction::ConstrData).into(),
argument: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::MkPairData).into(),
argument: Term::Constant(Constant::Data(PlutusData::BigInt(
BigInt::Int((constr_index as i128).try_into().unwrap()),
)))
.into(),
}
.into(),
argument: Term::Constant(Constant::Data(PlutusData::Array(vec![])))
.into(),
}
.into(),
};
arg_stack.push(term);
}
}
},
IR::Discard { .. } => {
arg_stack.push(Term::Constant(Constant::Unit));
}
IR::List {
count, tipo, tail, ..
} => {
let mut args = vec![];
for _ in 0..count {
let arg = arg_stack.pop().unwrap();
args.push(arg);
}
let mut constants = vec![];
for arg in &args {
if let Term::Constant(c) = arg {
constants.push(c.clone())
}
}
let list_type = match tipo.deref() {
Type::App { args, .. } => &args[0],
_ => unreachable!(),
};
if constants.len() == args.len() && !tail {
let list =
Term::Constant(Constant::ProtoList(list_type.get_uplc_type(), constants));
arg_stack.push(list);
} else {
let mut term = if tail {
arg_stack.pop().unwrap()
} else {
Term::Constant(Constant::ProtoList(list_type.get_uplc_type(), vec![]))
};
for arg in args {
term = Term::Apply {
function: Term::Apply {
function: Term::Force(
Term::Builtin(DefaultFunction::MkCons).into(),
)
.into(),
argument: arg.into(),
}
.into(),
argument: term.into(),
};
}
arg_stack.push(term);
}
}
IR::Tail { .. } => todo!(),
IR::ListAccessor { names, tail, .. } => {
let value = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
let mut id_list = vec![];
for _ in 0..names.len() {
id_list.push(self.id_gen.next());
}
let current_index = 0;
let (first_name, names) = names.split_first().unwrap();
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: first_name.clone(),
unique: 0.into(),
},
body: Term::Apply {
function: list_access_to_uplc(
names,
&id_list,
tail,
current_index,
term,
)
.into(),
argument: Term::Apply {
function: Term::Force(
Term::Builtin(DefaultFunction::TailList).into(),
)
.into(),
argument: value.clone().into(),
}
.into(),
}
.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into())
.into(),
argument: value.into(),
}
.into(),
};
arg_stack.push(term);
}
IR::Call { count, .. } => {
if count >= 2 {
let mut term = arg_stack.pop().unwrap();
for _ in 0..count - 1 {
let arg = arg_stack.pop().unwrap();
term = Term::Apply {
function: term.into(),
argument: arg.into(),
};
}
arg_stack.push(term);
} else {
todo!()
}
}
IR::Builtin { func, .. } => {
let mut term = Term::Builtin(func);
for _ in 0..func.force_count() {
term = Term::Force(term.into());
}
arg_stack.push(term);
}
IR::BinOp { name, tipo, .. } => {
let left = arg_stack.pop().unwrap();
let right = arg_stack.pop().unwrap();
let term = match name {
BinOp::And => todo!(),
BinOp::Or => todo!(),
BinOp::Eq => {
let default_builtin = match tipo.deref() {
Type::App { name, .. } => {
if name == "Int" {
Term::Builtin(DefaultFunction::EqualsInteger)
} else if name == "String" {
Term::Builtin(DefaultFunction::EqualsString)
} else if name == "ByteArray" {
Term::Builtin(DefaultFunction::EqualsByteString)
} else if name == "Bool" {
let term = Term::Force(
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(
Term::Builtin(DefaultFunction::IfThenElse)
.into(),
)
.into(),
argument: left.into(),
}
.into(),
argument: Term::Delay(
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(
Term::Builtin(
DefaultFunction::IfThenElse,
)
.into(),
)
.into(),
argument: right.clone().into(),
}
.into(),
argument: Term::Constant(
Constant::Bool(true),
)
.into(),
}
.into(),
argument: Term::Constant(Constant::Bool(
false,
))
.into(),
}
.into(),
)
.into(),
}
.into(),
argument: Term::Delay(
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(
Term::Builtin(
DefaultFunction::IfThenElse,
)
.into(),
)
.into(),
argument: right.into(),
}
.into(),
argument: Term::Constant(Constant::Bool(
false,
))
.into(),
}
.into(),
argument: Term::Constant(Constant::Bool(true))
.into(),
}
.into(),
)
.into(),
}
.into(),
);
arg_stack.push(term);
return;
} else {
Term::Builtin(DefaultFunction::EqualsData)
}
}
_ => unreachable!(),
};
Term::Apply {
function: Term::Apply {
function: default_builtin.into(),
argument: left.into(),
}
.into(),
argument: right.into(),
}
}
BinOp::NotEq => todo!(),
BinOp::LtInt => Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::LessThanInteger).into(),
argument: left.into(),
}
.into(),
argument: right.into(),
},
BinOp::LtEqInt => todo!(),
BinOp::GtEqInt => todo!(),
BinOp::GtInt => Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::LessThanInteger).into(),
argument: right.into(),
}
.into(),
argument: left.into(),
},
BinOp::AddInt => Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::AddInteger).into(),
argument: left.into(),
}
.into(),
argument: right.into(),
},
BinOp::SubInt => todo!(),
BinOp::MultInt => todo!(),
BinOp::DivInt => todo!(),
BinOp::ModInt => todo!(),
};
arg_stack.push(term);
}
IR::Assignment { name, .. } => {
let right_hand = arg_stack.pop().unwrap();
let lam_body = arg_stack.pop().unwrap();
let term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: name,
unique: 0.into(),
},
body: lam_body.into(),
}
.into(),
argument: right_hand.into(),
};
arg_stack.push(term);
}
IR::DefineFunc {
func_name,
params,
recursive,
..
} => {
let mut func_body = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
for param in params.iter().rev() {
func_body = Term::Lambda {
parameter_name: Name {
text: param.clone(),
unique: 0.into(),
},
body: func_body.into(),
};
}
if !recursive {
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: func_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: func_body.into(),
};
arg_stack.push(term);
} else {
func_body = Term::Lambda {
parameter_name: Name {
text: func_name.clone(),
unique: 0.into(),
},
body: func_body.into(),
};
let mut boostrap_recurse = Term::Apply {
function: Term::Var(Name {
text: "__recurse".to_string(),
unique: 0.into(),
})
.into(),
argument: Term::Var(Name {
text: "__recurse".to_string(),
unique: 0.into(),
})
.into(),
};
for param in params.iter() {
boostrap_recurse = Term::Apply {
function: boostrap_recurse.into(),
argument: Term::Var(Name {
text: param.clone(),
unique: 0.into(),
})
.into(),
};
}
func_body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: "__recurse".to_string(),
unique: 0.into(),
},
body: boostrap_recurse.into(),
}
.into(),
argument: func_body.into(),
};
for param in params.iter().rev() {
func_body = Term::Lambda {
parameter_name: Name {
text: param.clone(),
unique: 0.into(),
},
body: func_body.into(),
};
}
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: func_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: func_body.into(),
};
arg_stack.push(term);
}
}
IR::DefineConst { .. } => todo!(),
IR::DefineConstrFields { .. } => todo!(),
IR::DefineConstrFieldAccess { .. } => todo!(),
IR::Lam { name, .. } => {
let arg = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: arg.into(),
};
arg_stack.push(term);
}
IR::When {
subject_name, tipo, ..
} => {
let subject = arg_stack.pop().unwrap();
let mut term = arg_stack.pop().unwrap();
term = if tipo.is_int() || tipo.is_bytearray() || tipo.is_string() || tipo.is_list()
{
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: subject_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: subject.into(),
}
} else {
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: subject_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: constr_index_exposer(subject).into(),
}
};
arg_stack.push(term);
}
IR::Clause {
tipo, subject_name, ..
} => {
// clause to compare
let clause = arg_stack.pop().unwrap();
// the body to be run if the clause matches
let body = arg_stack.pop().unwrap();
// the final branch in the when expression
let mut term = arg_stack.pop().unwrap();
let checker = if tipo.is_int() {
Term::Apply {
function: DefaultFunction::EqualsInteger.into(),
argument: Term::Var(Name {
text: subject_name,
unique: 0.into(),
})
.into(),
}
} else if tipo.is_bytearray() {
Term::Apply {
function: DefaultFunction::EqualsByteString.into(),
argument: Term::Var(Name {
text: subject_name,
unique: 0.into(),
})
.into(),
}
} else if tipo.is_bool() {
todo!()
} else if tipo.is_string() {
Term::Apply {
function: DefaultFunction::EqualsString.into(),
argument: Term::Var(Name {
text: subject_name,
unique: 0.into(),
})
.into(),
}
} else if tipo.is_list() {
todo!()
} else {
Term::Apply {
function: DefaultFunction::EqualsInteger.into(),
argument: Term::Var(Name {
text: subject_name,
unique: 0.into(),
})
.into(),
}
};
term = Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Force(DefaultFunction::IfThenElse.into()).into(),
argument: Term::Apply {
function: checker.into(),
argument: clause.into(),
}
.into(),
}
.into(),
argument: Term::Delay(body.into()).into(),
}
.into(),
argument: Term::Delay(term.into()).into(),
}
.force_wrap();
arg_stack.push(term);
}
IR::Finally { .. } => {
let _clause = arg_stack.pop().unwrap();
}
IR::If { .. } => todo!(),
IR::Constr { .. } => todo!(),
IR::Fields { .. } => todo!(),
IR::RecordAccess { index, tipo, .. } => {
let constr = arg_stack.pop().unwrap();
let mut term = Term::Apply {
function: Term::Apply {
function: Term::Var(Name {
text: CONSTR_GET_FIELD.to_string(),
unique: 0.into(),
})
.into(),
argument: Term::Apply {
function: Term::Var(Name {
text: CONSTR_FIELDS_EXPOSER.to_string(),
unique: 0.into(),
})
.into(),
argument: constr.into(),
}
.into(),
}
.into(),
argument: Term::Constant(Constant::Integer(index.into())).into(),
};
if tipo.is_int() {
term = Term::Apply {
function: Term::Builtin(DefaultFunction::UnIData).into(),
argument: term.into(),
};
} else if tipo.is_bytearray() {
term = Term::Apply {
function: Term::Builtin(DefaultFunction::UnBData).into(),
argument: term.into(),
};
} else if tipo.is_list() {
term = Term::Apply {
function: Term::Builtin(DefaultFunction::UnListData).into(),
argument: term.into(),
};
}
arg_stack.push(term);
}
IR::FieldsExpose {
count: _count,
indices,
..
} => {
self.needs_field_access = true;
let constr_var = arg_stack.pop().unwrap();
let mut body = arg_stack.pop().unwrap();
let mut indices = indices.into_iter().rev();
let highest = indices.next().unwrap();
let mut id_list = vec![];
for _ in 0..highest.0 {
id_list.push(self.id_gen.next());
}
let constr_name_lam = format!("__constr_fields_{}", self.id_gen.next());
let highest_loop_index = highest.0 as i32 - 1;
let last_prev_tail = Term::Var(Name {
text: if highest_loop_index == -1 {
constr_name_lam.clone()
} else {
format!(
"__tail_{}_{}",
highest_loop_index, id_list[highest_loop_index as usize]
)
},
unique: 0.into(),
});
let unwrapper = if highest.2.is_int() {
Term::Apply {
function: DefaultFunction::UnIData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else if highest.2.is_bytearray() {
Term::Apply {
function: DefaultFunction::UnBData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else if highest.2.is_list() {
Term::Apply {
function: DefaultFunction::UnListData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
.into(),
}
} else {
Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: last_prev_tail.into(),
}
};
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: highest.1,
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: unwrapper.into(),
};
let mut current_field = None;
for index in (0..highest.0).rev() {
let current_tail_index = index;
let previous_tail_index = if index == 0 { 0 } else { index - 1 };
let current_tail_id = id_list[index];
let previous_tail_id = if index == 0 { 0 } else { id_list[index - 1] };
if current_field.is_none() {
current_field = indices.next();
}
let prev_tail = if index == 0 {
Term::Var(Name {
text: constr_name_lam.clone(),
unique: 0.into(),
})
} else {
Term::Var(Name {
text: format!("__tail_{previous_tail_index}_{previous_tail_id}"),
unique: 0.into(),
})
};
if let Some(ref field) = current_field {
if field.0 == index {
let unwrapper = if field.2.is_int() {
Term::Apply {
function: DefaultFunction::UnIData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else if field.2.is_bytearray() {
Term::Apply {
function: DefaultFunction::UnBData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else if field.2.is_list() {
Term::Apply {
function: DefaultFunction::UnListData.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
.into(),
}
} else {
Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList)
.force_wrap()
.into(),
argument: prev_tail.clone().into(),
}
};
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: field.1.clone(),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!(
"__tail_{current_tail_index}_{current_tail_id}"
),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
.into(),
}
.into(),
argument: unwrapper.into(),
};
current_field = None;
} else {
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!(
"__tail_{current_tail_index}_{current_tail_id}"
),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
}
} else {
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: format!("__tail_{current_tail_index}_{current_tail_id}"),
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList)
.force_wrap()
.force_wrap()
.into(),
argument: prev_tail.into(),
}
.into(),
}
}
}
body = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: constr_name_lam,
unique: 0.into(),
},
body: body.into(),
}
.into(),
argument: Term::Apply {
function: Term::Var(Name {
text: CONSTR_FIELDS_EXPOSER.to_string(),
unique: 0.into(),
})
.into(),
argument: constr_var.into(),
}
.into(),
};
arg_stack.push(body);
}
IR::Todo { .. } => todo!(),
IR::RecordUpdate { .. } => todo!(),
IR::Negate { .. } => todo!(),
}
}
pub(crate) fn define_ir(&mut self, ir_stack: &mut Vec<IR>) {
let mut func_components = IndexMap::new();
let mut func_index_map = IndexMap::new();
let recursion_func_map = IndexMap::new();
self.define_recurse_ir(
ir_stack,
&mut func_components,
&mut func_index_map,
recursion_func_map,
);
let mut final_func_dep_ir = IndexMap::new();
println!("GOT HERE");
for func in func_index_map.clone() {
if self.defined_functions.contains_key(&func.0) {
continue;
}
let mut funt_comp = func_components.get(&func.0).unwrap().clone();
let func_scope = func_index_map.get(&func.0).unwrap();
let mut dep_ir = vec![];
while let Some(dependency) = funt_comp.dependencies.pop() {
if self.defined_functions.contains_key(&dependency) {
continue;
}
let depend_comp = func_components.get(&dependency).unwrap();
let dep_scope = func_index_map.get(&dependency).unwrap();
if get_common_ancestor(dep_scope, func_scope) == func_scope.clone() {
funt_comp
.dependencies
.extend(depend_comp.dependencies.clone());
let mut temp_ir = vec![IR::DefineFunc {
scope: func_scope.clone(),
func_name: dependency.function_name.clone(),
module_name: dependency.module_name.clone(),
params: depend_comp.args.clone(),
recursive: depend_comp.recursive,
}];
temp_ir.extend(depend_comp.ir.clone());
temp_ir.append(&mut dep_ir);
dep_ir = temp_ir;
self.defined_functions.insert(dependency, ());
}
}
final_func_dep_ir.insert(func.0, dep_ir);
}
for (index, ir) in ir_stack.clone().into_iter().enumerate().rev() {
match ir {
IR::Var { constructor, .. } => {
if let ValueConstructorVariant::ModuleFn { .. } = &constructor.variant {}
}
a => {
let temp_func_index_map = func_index_map.clone();
let to_insert = temp_func_index_map
.iter()
.filter(|func| {
func.1.clone() == a.scope()
&& !self.defined_functions.contains_key(func.0)
})
.collect_vec();
for item in to_insert.into_iter() {
func_index_map.remove(item.0);
self.defined_functions.insert(item.0.clone(), ());
let mut full_func_ir = final_func_dep_ir.get(item.0).unwrap().clone();
let funt_comp = func_components.get(item.0).unwrap();
full_func_ir.push(IR::DefineFunc {
scope: item.1.clone(),
func_name: item.0.function_name.clone(),
module_name: item.0.module_name.clone(),
params: funt_comp.args.clone(),
recursive: funt_comp.recursive,
});
full_func_ir.extend(funt_comp.ir.clone());
for ir in full_func_ir.into_iter().rev() {
ir_stack.insert(index, ir);
}
}
}
}
}
}
fn define_recurse_ir(
&mut self,
ir_stack: &[IR],
func_components: &mut IndexMap<FunctionAccessKey, FuncComponents>,
func_index_map: &mut IndexMap<FunctionAccessKey, Vec<u64>>,
recursion_func_map: IndexMap<FunctionAccessKey, ()>,
) {
self.process_define_ir(ir_stack, func_components, func_index_map);
let mut recursion_func_map = recursion_func_map;
for func_index in func_index_map.clone().iter() {
let func = func_index.0;
let function_components = func_components.get(func).unwrap();
let function_ir = function_components.ir.clone();
for ir in function_ir.clone() {
if let IR::Var {
constructor:
ValueConstructor {
variant:
ValueConstructorVariant::ModuleFn {
name: func_name,
module,
..
},
..
},
..
} = ir
{
if recursion_func_map.contains_key(&FunctionAccessKey {
module_name: module.clone(),
function_name: func_name.clone(),
}) {
return;
} else {
recursion_func_map.insert(
FunctionAccessKey {
module_name: module.clone(),
function_name: func_name.clone(),
},
(),
);
}
}
}
let mut inner_func_components = IndexMap::new();
let mut inner_func_index_map = IndexMap::new();
self.define_recurse_ir(
&function_ir,
&mut inner_func_components,
&mut inner_func_index_map,
recursion_func_map.clone(),
);
//now unify
for item in inner_func_components {
if !func_components.contains_key(&item.0) {
func_components.insert(item.0, item.1);
}
}
for item in inner_func_index_map {
if let Some(entry) = func_index_map.get_mut(&item.0) {
*entry = get_common_ancestor(entry, &item.1);
} else {
func_index_map.insert(item.0, item.1);
}
}
}
}
fn process_define_ir(
&mut self,
ir_stack: &[IR],
func_components: &mut IndexMap<FunctionAccessKey, FuncComponents>,
func_index_map: &mut IndexMap<FunctionAccessKey, Vec<u64>>,
) {
let mut to_be_defined_map: IndexMap<FunctionAccessKey, Vec<u64>> = IndexMap::new();
for ir in ir_stack.iter().rev() {
match ir {
IR::Var {
scope, constructor, ..
} => {
if let ValueConstructorVariant::ModuleFn {
name,
module,
builtin,
..
} = &constructor.variant
{
if builtin.is_none() {
let function_key = FunctionAccessKey {
module_name: module.clone(),
function_name: name.clone(),
};
if let Some(scope_prev) = to_be_defined_map.get(&function_key) {
let new_scope = get_common_ancestor(scope, scope_prev);
to_be_defined_map.insert(function_key, new_scope);
} else if func_components.get(&function_key).is_some() {
to_be_defined_map.insert(function_key.clone(), scope.to_vec());
} else {
let function = self.functions.get(&function_key).unwrap();
let mut func_ir = vec![];
self.build_ir(&function.body, &mut func_ir, scope.to_vec());
to_be_defined_map.insert(function_key.clone(), scope.to_vec());
let mut func_calls = vec![];
for ir in func_ir.clone() {
if let IR::Var {
constructor:
ValueConstructor {
variant:
ValueConstructorVariant::ModuleFn {
name: func_name,
module,
..
},
..
},
..
} = ir
{
func_calls.push(FunctionAccessKey {
module_name: module.clone(),
function_name: func_name.clone(),
})
}
}
let mut args = vec![];
for arg in function.arguments.iter() {
match &arg.arg_name {
ArgName::Named { name, .. }
| ArgName::NamedLabeled { name, .. } => {
args.push(name.clone());
}
_ => {}
}
}
let recursive =
if let Ok(index) = func_calls.binary_search(&function_key) {
func_calls.remove(index);
true
} else {
false
};
func_components.insert(
function_key,
FuncComponents {
ir: func_ir,
dependencies: func_calls,
recursive,
args,
},
);
}
}
}
}
a => {
let scope = a.scope();
for func in to_be_defined_map.clone().iter() {
if get_common_ancestor(&scope, func.1) == scope.to_vec() {
if let Some(index_scope) = func_index_map.get(func.0) {
if get_common_ancestor(index_scope, func.1) == scope.to_vec() {
func_index_map.insert(func.0.clone(), scope.clone());
to_be_defined_map.shift_remove(func.0);
} else {
to_be_defined_map.insert(
func.0.clone(),
get_common_ancestor(index_scope, func.1),
);
}
} else {
func_index_map.insert(func.0.clone(), scope.clone());
to_be_defined_map.shift_remove(func.0);
}
}
}
}
}
}
//Still to be defined
for func in to_be_defined_map.clone().iter() {
let index_scope = func_index_map.get(func.0).unwrap();
func_index_map.insert(func.0.clone(), get_common_ancestor(func.1, index_scope));
}
}
}
fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> {
let longest_length = if scope.len() >= scope_prev.len() {
scope.len()
} else {
scope_prev.len()
};
if *scope == *scope_prev {
return scope.to_vec();
}
for index in 0..longest_length {
if scope.get(index).is_none() {
return scope.to_vec();
} else if scope_prev.get(index).is_none() {
return scope_prev.to_vec();
} else if scope[index] != scope_prev[index] {
return scope[0..index].to_vec();
}
}
vec![]
}
fn list_access_to_uplc(
names: &[String],
id_list: &[u64],
tail: bool,
current_index: usize,
term: Term<Name>,
) -> Term<Name> {
let (first, names) = names.split_first().unwrap();
if names.len() == 1 && tail {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: names[0].clone(),
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::TailList).into())
.into(),
argument: Term::Var(Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
})
.into(),
}
.into(),
}
.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()).into(),
argument: Term::Var(Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
})
.into(),
}
.into(),
}
.into(),
}
} else if names.is_empty() {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()).into(),
argument: Term::Var(Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
})
.into(),
}
.into(),
}
.into(),
}
} else {
Term::Lambda {
parameter_name: Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
},
body: Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: first.clone(),
unique: 0.into(),
},
body: Term::Apply {
function: list_access_to_uplc(
names,
id_list,
tail,
current_index + 1,
term,
)
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::TailList).into())
.into(),
argument: Term::Var(Name {
text: format!(
"tail_index_{}_{}",
current_index, id_list[current_index]
),
unique: 0.into(),
})
.into(),
}
.into(),
}
.into(),
}
.into(),
argument: Term::Apply {
function: Term::Force(Term::Builtin(DefaultFunction::HeadList).into()).into(),
argument: Term::Var(Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
unique: 0.into(),
})
.into(),
}
.into(),
}
.into(),
}
}
}