Add ability to generate ir with complex constructor cases

This commit is contained in:
Kasey White 2022-12-03 03:52:25 -05:00 committed by Lucas
parent 64cbae938d
commit f48039fd4f
3 changed files with 137 additions and 40 deletions

View File

@ -138,10 +138,13 @@ pub enum IR {
count: usize, count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
complex_clause: bool,
}, },
ClauseGuard { ClauseGuard {
scope: Vec<u64>, scope: Vec<u64>,
subject_name: String,
tipo: Arc<Type>,
}, },
Discard { Discard {
@ -242,7 +245,7 @@ impl IR {
| IR::Lam { scope, .. } | IR::Lam { scope, .. }
| IR::When { scope, .. } | IR::When { scope, .. }
| IR::Clause { scope, .. } | IR::Clause { scope, .. }
| IR::ClauseGuard { scope } | IR::ClauseGuard { scope, .. }
| IR::Discard { scope } | IR::Discard { scope }
| IR::Finally { scope } | IR::Finally { scope }
| IR::If { scope, .. } | IR::If { scope, .. }

View File

@ -37,6 +37,12 @@ pub struct FuncComponents {
// } // }
pub struct ClauseComplexity {
subject_var_name: String,
needs_subject_var: bool,
is_complex_clause: bool,
}
pub struct CodeGenerator<'a> { pub struct CodeGenerator<'a> {
defined_functions: HashMap<FunctionAccessKey, ()>, defined_functions: HashMap<FunctionAccessKey, ()>,
functions: &'a HashMap<FunctionAccessKey, &'a Function<Arc<tipo::Type>, TypedExpr>>, functions: &'a HashMap<FunctionAccessKey, &'a Function<Arc<tipo::Type>, TypedExpr>>,
@ -259,7 +265,7 @@ impl<'a> CodeGenerator<'a> {
// assuming one subject at the moment // assuming one subject at the moment
let subject = subjects[0].clone(); let subject = subjects[0].clone();
let mut needs_constr_var = false; let mut needs_subject_var = false;
if let Some((last_clause, clauses)) = clauses.split_last() { if let Some((last_clause, clauses)) = clauses.split_last() {
let mut clauses_vec = vec![]; let mut clauses_vec = vec![];
@ -268,28 +274,48 @@ impl<'a> CodeGenerator<'a> {
for clause in clauses { for clause in clauses {
let mut scope = scope.clone(); let mut scope = scope.clone();
scope.push(self.id_gen.next()); scope.push(self.id_gen.next());
let mut clause_subject_vec = vec![];
let mut clause_complexity = ClauseComplexity {
subject_var_name: constr_var.clone(),
needs_subject_var: false,
is_complex_clause: false,
};
self.build_ir(&clause.then, &mut clauses_vec, scope.clone());
self.when_ir(
&clause.pattern[0],
&mut clause_subject_vec,
&mut clauses_vec,
&subject.tipo(),
&mut clause_complexity,
scope.clone(),
);
pattern_vec.push(IR::Clause { pattern_vec.push(IR::Clause {
scope: scope.clone(), scope: scope.clone(),
count: 2, count: 2,
tipo: subject.tipo().clone(), tipo: subject.tipo().clone(),
subject_name: subject_name.clone(), subject_name: subject_name.clone(),
complex_clause: clause_complexity.is_complex_clause,
}); });
self.build_ir(&clause.then, &mut clauses_vec, scope.clone()); pattern_vec.append(&mut clause_subject_vec);
self.when_ir(
&clause.pattern[0], if clause_complexity.needs_subject_var {
&mut pattern_vec, needs_subject_var = true;
&mut clauses_vec, }
&subject.tipo(),
constr_var.clone(),
&mut needs_constr_var,
scope,
);
} }
let last_pattern = &last_clause.pattern[0]; let last_pattern = &last_clause.pattern[0];
let mut final_clause_complexity = ClauseComplexity {
subject_var_name: constr_var.clone(),
needs_subject_var: false,
is_complex_clause: false,
};
let mut final_scope = scope.clone(); let mut final_scope = scope.clone();
final_scope.push(self.id_gen.next()); final_scope.push(self.id_gen.next());
pattern_vec.push(IR::Finally { pattern_vec.push(IR::Finally {
@ -302,12 +328,11 @@ impl<'a> CodeGenerator<'a> {
&mut pattern_vec, &mut pattern_vec,
&mut clauses_vec, &mut clauses_vec,
&subject.tipo(), &subject.tipo(),
constr_var.clone(), &mut final_clause_complexity,
&mut needs_constr_var,
final_scope, final_scope,
); );
if needs_constr_var { if needs_subject_var || final_clause_complexity.needs_subject_var {
ir_stack.push(IR::Lam { ir_stack.push(IR::Lam {
scope: scope.clone(), scope: scope.clone(),
name: constr_var.clone(), name: constr_var.clone(),
@ -460,8 +485,7 @@ impl<'a> CodeGenerator<'a> {
pattern_vec: &mut Vec<IR>, pattern_vec: &mut Vec<IR>,
values: &mut Vec<IR>, values: &mut Vec<IR>,
tipo: &Type, tipo: &Type,
constr_var: String, when_complexity: &mut ClauseComplexity,
needs_constr_var: &mut bool,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {
match pattern { match pattern {
@ -500,8 +524,8 @@ impl<'a> CodeGenerator<'a> {
.. ..
} => { } => {
let mut needs_access_to_constr_var = false; let mut needs_access_to_constr_var = false;
let mut needs_clause_guard = false; let mut needs_clause_guard = false;
for arg in arguments { for arg in arguments {
match arg.value { match arg.value {
Pattern::Var { .. } => { Pattern::Var { .. } => {
@ -550,18 +574,12 @@ impl<'a> CodeGenerator<'a> {
location: Span::empty(), location: Span::empty(),
}, },
), ),
name: constr_var, name: when_complexity.subject_var_name.clone(),
scope: scope.clone(), scope: scope.clone(),
}]; }];
// if only one constructor, no need to check // if only one constructor, no need to check
if data_type.constructors.len() > 1 { if data_type.constructors.len() > 1 {
if needs_clause_guard {
pattern_vec.push(IR::ClauseGuard {
scope: scope.clone(),
});
}
// push constructor Index // push constructor Index
pattern_vec.push(IR::Int { pattern_vec.push(IR::Int {
value: index.to_string(), value: index.to_string(),
@ -569,8 +587,12 @@ impl<'a> CodeGenerator<'a> {
}); });
} }
if needs_clause_guard {
when_complexity.is_complex_clause = true;
}
if needs_access_to_constr_var { if needs_access_to_constr_var {
*needs_constr_var = true; when_complexity.needs_subject_var = true;
self.when_recursive_ir(pattern, pattern_vec, &mut new_vec, tipo, scope); self.when_recursive_ir(pattern, pattern_vec, &mut new_vec, tipo, scope);
pattern_vec.append(values); pattern_vec.append(values);
@ -717,18 +739,48 @@ impl<'a> CodeGenerator<'a> {
.. ..
} => { } => {
let id = self.id_gen.next(); let id = self.id_gen.next();
let constr_name = format!("{constr_name}_{id}"); let constr_var_name = format!("{constr_name}_{id}");
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();
if data_type.constructors.len() > 1 {
nested_pattern.push(IR::ClauseGuard {
scope: scope.clone(),
tipo: tipo.clone(),
subject_name: constr_var_name.clone(),
});
}
let mut clause_complexity = ClauseComplexity {
subject_var_name: constr_var_name.clone(),
needs_subject_var: false,
is_complex_clause: false,
};
self.when_ir( self.when_ir(
a, a,
&mut nested_pattern, &mut nested_pattern,
&mut vec![], &mut vec![],
tipo, tipo,
constr_name.clone(), &mut clause_complexity,
&mut false,
scope.clone(), scope.clone(),
); );
(false, constr_name) (false, constr_var_name)
} }
_ => todo!(), _ => todo!(),
}; };
@ -775,18 +827,47 @@ impl<'a> CodeGenerator<'a> {
.. ..
} => { } => {
let id = self.id_gen.next(); let id = self.id_gen.next();
let constr_name = format!("{constr_name}_{id}"); let constr_var_name = format!("{constr_name}_{id}");
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();
if data_type.constructors.len() > 1 {
nested_pattern.push(IR::ClauseGuard {
scope: scope.clone(),
tipo: tipo.clone(),
subject_name: constr_var_name.clone(),
});
}
let mut clause_complexity = ClauseComplexity {
subject_var_name: constr_var_name.clone(),
needs_subject_var: false,
is_complex_clause: false,
};
self.when_ir( self.when_ir(
a, a,
&mut nested_pattern, &mut nested_pattern,
&mut vec![], &mut vec![],
tipo, tipo,
constr_name.clone(), &mut clause_complexity,
&mut false,
scope.clone(), scope.clone(),
); );
(false, constr_name) (false, constr_var_name)
} }
_ => todo!(), _ => todo!(),
}; };
@ -1426,7 +1507,14 @@ impl<'a> CodeGenerator<'a> {
.into(), .into(),
argument: right.into(), argument: right.into(),
}, },
BinOp::GtEqInt => todo!(), BinOp::GtEqInt => Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::LessThanEqualsInteger).into(),
argument: right.into(),
}
.into(),
argument: left.into(),
},
BinOp::GtInt => Term::Apply { BinOp::GtInt => Term::Apply {
function: Term::Apply { function: Term::Apply {
function: Term::Builtin(DefaultFunction::LessThanInteger).into(), function: Term::Builtin(DefaultFunction::LessThanInteger).into(),
@ -1736,7 +1824,13 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
IR::ClauseGuard { .. } => todo!(), IR::ClauseGuard { .. } => {
let _condition = arg_stack.pop().unwrap();
let _then = arg_stack.pop().unwrap();
todo!();
}
IR::Finally { .. } => { IR::Finally { .. } => {
let _clause = arg_stack.pop().unwrap(); let _clause = arg_stack.pop().unwrap();
} }

View File

@ -47,7 +47,7 @@ pub fn who(a: ByteArray) -> ByteArray {
} }
pub type Datum { pub type Datum {
Offer { prices: List(Int), asset_class: ByteArray, other_thing: Redeemer } Offer { prices: List(Int), asset_class: ByteArray, other_thing: Datum }
Sell Sell
Hold(Int) Hold(Int)
} }
@ -58,11 +58,11 @@ pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool {
Offer { Offer {
prices: p, prices: p,
asset_class: ac, asset_class: ac,
other_thing: Redeemer { other_thing: Offer {
other_thing: Redeemer { signer: nested_signer, amount, .. }, other_thing: Offer { asset_class: nested_signer, prices: amounts, .. },
.. ..
}, },
} -> True } -> 1 == 1
_ -> False _ -> False
} }
} }