feat: finish list destructure in when matches

This commit is contained in:
Kasey White 2022-12-05 01:07:27 -05:00 committed by Lucas
parent 8cbdf97d22
commit de9302a877
3 changed files with 551 additions and 116 deletions

View File

@ -49,7 +49,8 @@ pub enum IR {
Tail { Tail {
scope: Vec<u64>, scope: Vec<u64>,
count: usize, name: String,
prev_tail_name: String,
}, },
ListAccessor { ListAccessor {
@ -58,10 +59,12 @@ pub enum IR {
tail: bool, tail: bool,
}, },
// func(x, other(y)) ListExpose {
//[ Define(3) x definition *lam_body* -> [ (x [ (func [ func x [ (y [ other y ]) *definition* ] ]) *definition* ]) *definition* ], Define func -> [ (func [ func x [ (y [ other y ]) *definition* ] ]) *definition* ] , Call func -> [ func x [ (y [ other y ]) *definition* ] ], Var x -> x, Define y -> [ (y [ other y ]) *definition* ], Call other -> [ other y ], Var y -> y] scope: Vec<u64>,
tail_head_names: Vec<(String, String)>,
tail: Option<(String, String)>,
},
// [y_varCall other_var Call Call x_defCall func_var ]
Call { Call {
scope: Vec<u64>, scope: Vec<u64>,
count: usize, count: usize,
@ -128,19 +131,25 @@ pub enum IR {
// }, // },
When { When {
scope: Vec<u64>, scope: Vec<u64>,
count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
}, },
Clause { Clause {
scope: Vec<u64>, scope: Vec<u64>,
count: usize,
tipo: Arc<Type>, tipo: Arc<Type>,
subject_name: String, subject_name: String,
complex_clause: bool, complex_clause: bool,
}, },
ListClause {
scope: Vec<u64>,
tipo: Arc<Type>,
tail_name: String,
complex_clause: bool,
next_tail_name: Option<String>,
},
ClauseGuard { ClauseGuard {
scope: Vec<u64>, scope: Vec<u64>,
subject_name: String, subject_name: String,
@ -157,7 +166,6 @@ pub enum IR {
If { If {
scope: Vec<u64>, scope: Vec<u64>,
count: usize,
}, },
Constr { Constr {
@ -234,6 +242,7 @@ impl IR {
| IR::List { scope, .. } | IR::List { scope, .. }
| IR::Tail { scope, .. } | IR::Tail { scope, .. }
| IR::ListAccessor { scope, .. } | IR::ListAccessor { scope, .. }
| IR::ListExpose { scope, .. }
| IR::Call { scope, .. } | IR::Call { scope, .. }
| IR::Builtin { scope, .. } | IR::Builtin { scope, .. }
| IR::BinOp { scope, .. } | IR::BinOp { scope, .. }
@ -245,6 +254,7 @@ impl IR {
| IR::Lam { scope, .. } | IR::Lam { scope, .. }
| IR::When { scope, .. } | IR::When { scope, .. }
| IR::Clause { scope, .. } | IR::Clause { scope, .. }
| IR::ListClause { scope, .. }
| IR::ClauseGuard { scope, .. } | IR::ClauseGuard { scope, .. }
| IR::Discard { scope } | IR::Discard { scope }
| IR::Finally { scope } | IR::Finally { scope }

View File

@ -13,10 +13,10 @@ use uplc::{
}; };
use crate::{ use crate::{
ast::{ArgName, AssignmentKind, BinOp, DataType, Function, Pattern, Span, TypedArg}, ast::{ArgName, AssignmentKind, BinOp, Clause, DataType, Function, Pattern, Span, TypedArg},
expr::TypedExpr, expr::TypedExpr,
ir::IR, ir::IR,
tipo::{self, Type, TypeInfo, ValueConstructor, ValueConstructorVariant}, tipo::{self, PatternConstructor, Type, TypeInfo, ValueConstructor, ValueConstructorVariant},
uplc::{DataTypeKey, FunctionAccessKey}, uplc::{DataTypeKey, FunctionAccessKey},
IdGenerator, IdGenerator,
}; };
@ -37,10 +37,13 @@ pub struct FuncComponents {
// } // }
pub struct ClauseComplexity { #[derive(Clone, Debug)]
subject_var_name: String, pub struct ClauseProperties {
needs_subject_var: bool, clause_var_name: String,
needs_constr_var: bool,
is_complex_clause: bool, is_complex_clause: bool,
current_index: usize,
original_subject_name: String,
} }
pub struct CodeGenerator<'a> { pub struct CodeGenerator<'a> {
@ -83,11 +86,11 @@ impl<'a> CodeGenerator<'a> {
self.build_ir(&body, &mut ir_stack, scope); self.build_ir(&body, &mut ir_stack, scope);
println!("{ir_stack:#?}"); println!("INITIAL: {ir_stack:#?}");
self.define_ir(&mut ir_stack); self.define_ir(&mut ir_stack);
println!("{ir_stack:#?}"); println!("AFTER FUNCTION DEFINITIONS: {ir_stack:#?}");
let mut term = self.uplc_code_gen(&mut ir_stack); let mut term = self.uplc_code_gen(&mut ir_stack);
@ -188,10 +191,7 @@ impl<'a> CodeGenerator<'a> {
if let Some(tail) = tail { if let Some(tail) = tail {
let mut scope = scope; let mut scope = scope;
scope.push(self.id_gen.next()); scope.push(self.id_gen.next());
ir_stack.push(IR::Tail {
scope: scope.clone(),
count: 1,
});
self.build_ir(tail, ir_stack, scope); self.build_ir(tail, ir_stack, scope);
} }
} }
@ -267,20 +267,34 @@ impl<'a> CodeGenerator<'a> {
let subject = subjects[0].clone(); let subject = subjects[0].clone();
let mut needs_subject_var = false; let mut needs_subject_var = false;
let clauses = if matches!(clauses[0].pattern[0], Pattern::List { .. }) {
rearrange_clauses(clauses.clone())
} else {
clauses.clone()
};
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![];
let mut pattern_vec = vec![]; let mut pattern_vec = vec![];
for clause in clauses { let mut clause_properties = ClauseProperties {
clause_var_name: constr_var.clone(),
needs_constr_var: false,
is_complex_clause: false,
current_index: 0,
original_subject_name: subject_name.clone(),
};
for (index, clause) in clauses.iter().enumerate() {
// scope per clause is different
let mut scope = scope.clone(); let mut scope = scope.clone();
scope.push(self.id_gen.next()); scope.push(self.id_gen.next());
// holds when clause pattern IR
let mut clause_subject_vec = vec![]; let mut clause_subject_vec = vec![];
let mut clause_complexity = ClauseComplexity { // reset complex clause setting per clause back to default
subject_var_name: constr_var.clone(), clause_properties.is_complex_clause = false;
needs_subject_var: false,
is_complex_clause: false,
};
self.build_ir(&clause.then, &mut clauses_vec, scope.clone()); self.build_ir(&clause.then, &mut clauses_vec, scope.clone());
@ -289,33 +303,51 @@ impl<'a> CodeGenerator<'a> {
&mut clause_subject_vec, &mut clause_subject_vec,
&mut clauses_vec, &mut clauses_vec,
&subject.tipo(), &subject.tipo(),
&mut clause_complexity, &mut clause_properties,
scope.clone(), scope.clone(),
); );
pattern_vec.push(IR::Clause { if clause_properties.needs_constr_var {
scope: scope.clone(),
count: 2,
tipo: subject.tipo().clone(),
subject_name: subject_name.clone(),
complex_clause: clause_complexity.is_complex_clause,
});
pattern_vec.append(&mut clause_subject_vec);
if clause_complexity.needs_subject_var {
needs_subject_var = true; needs_subject_var = true;
} }
let subject_name = if clause_properties.current_index == 0 {
subject_name.clone()
} else {
format!("__tail_{}", clause_properties.current_index - 1)
};
// Clause is first in IR pattern vec
if subject.tipo().is_list() {
let next_tail = if index == clauses.len() - 1 {
None
} else {
Some(format!("__tail_{}", clause_properties.current_index))
};
pattern_vec.push(IR::ListClause {
scope,
tipo: subject.tipo().clone(),
tail_name: subject_name,
complex_clause: clause_properties.is_complex_clause,
next_tail_name: next_tail,
});
clause_properties.current_index += 1;
} else {
pattern_vec.push(IR::Clause {
scope,
tipo: subject.tipo().clone(),
subject_name,
complex_clause: clause_properties.is_complex_clause,
});
}
pattern_vec.append(&mut clause_subject_vec);
} }
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 {
@ -323,16 +355,17 @@ impl<'a> CodeGenerator<'a> {
}); });
self.build_ir(&last_clause.then, &mut clauses_vec, final_scope.clone()); self.build_ir(&last_clause.then, &mut clauses_vec, final_scope.clone());
self.when_ir( self.when_ir(
last_pattern, last_pattern,
&mut pattern_vec, &mut pattern_vec,
&mut clauses_vec, &mut clauses_vec,
&subject.tipo(), &subject.tipo(),
&mut final_clause_complexity, &mut clause_properties,
final_scope, final_scope,
); );
if needs_subject_var || final_clause_complexity.needs_subject_var { if needs_subject_var || clause_properties.needs_constr_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(),
@ -342,7 +375,6 @@ impl<'a> CodeGenerator<'a> {
ir_stack.push(IR::When { ir_stack.push(IR::When {
scope: scope.clone(), scope: scope.clone(),
count: clauses.len() + 1,
subject_name, subject_name,
tipo: subject.tipo(), tipo: subject.tipo(),
}); });
@ -363,7 +395,6 @@ impl<'a> CodeGenerator<'a> {
} else { } else {
ir_stack.push(IR::When { ir_stack.push(IR::When {
scope: scope.clone(), scope: scope.clone(),
count: clauses.len() + 1,
subject_name, subject_name,
tipo: subject.tipo(), tipo: subject.tipo(),
}); });
@ -391,12 +422,10 @@ impl<'a> CodeGenerator<'a> {
if index == 0 { if index == 0 {
if_ir.push(IR::If { if_ir.push(IR::If {
scope: scope.clone(), scope: scope.clone(),
count: 3,
}); });
} else { } else {
if_ir.push(IR::If { if_ir.push(IR::If {
scope: branch_scope.clone(), scope: branch_scope.clone(),
count: 3,
}); });
} }
self.build_ir(&branch.condition, &mut if_ir, branch_scope.clone()); self.build_ir(&branch.condition, &mut if_ir, branch_scope.clone());
@ -485,7 +514,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,
when_complexity: &mut ClauseComplexity, clause_properties: &mut ClauseProperties,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {
match pattern { match pattern {
@ -499,25 +528,90 @@ impl<'a> CodeGenerator<'a> {
} }
Pattern::String { .. } => todo!(), Pattern::String { .. } => todo!(),
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
pattern_vec.push(IR::Discard {
scope: scope.clone(),
});
pattern_vec.push(IR::Lam {
scope: scope.clone(),
name: name.clone(),
});
pattern_vec.push(IR::Var { pattern_vec.push(IR::Var {
scope, scope,
name: name.clone(),
constructor: ValueConstructor::public( constructor: ValueConstructor::public(
tipo.clone().into(), tipo.clone().into(),
ValueConstructorVariant::LocalVariable { ValueConstructorVariant::LocalVariable {
location: Span::empty(), location: Span::empty(),
}, },
), ),
name: clause_properties.original_subject_name.clone(),
}); });
pattern_vec.append(values); pattern_vec.append(values);
} }
Pattern::VarUsage { .. } => todo!(), Pattern::VarUsage { .. } => todo!(),
Pattern::Assign { .. } => todo!(), Pattern::Assign { name, pattern, .. } => {
let mut new_vec = vec![];
new_vec.push(IR::Lam {
scope: scope.clone(),
name: name.clone(),
});
new_vec.push(IR::Var {
scope: scope.clone(),
constructor: ValueConstructor::public(
tipo.clone().into(),
ValueConstructorVariant::LocalVariable {
location: Span::empty(),
},
),
name: clause_properties.original_subject_name.clone(),
});
new_vec.append(values);
// pattern_vec.push(value)
self.when_ir(
pattern,
pattern_vec,
&mut new_vec,
tipo,
clause_properties,
scope,
);
}
Pattern::Discard { .. } => { Pattern::Discard { .. } => {
pattern_vec.push(IR::Discard { scope }); pattern_vec.push(IR::Discard { scope });
pattern_vec.append(values); pattern_vec.append(values);
} }
Pattern::List { .. } => todo!(), Pattern::List { elements, tail, .. } => {
let mut needs_clause_guard = false;
for element in elements {
check_when_pattern_needs(element, &mut false, &mut needs_clause_guard);
}
if let Some(tail) = tail {
check_when_pattern_needs(tail, &mut false, &mut needs_clause_guard);
}
if needs_clause_guard {
clause_properties.is_complex_clause = true;
}
pattern_vec.push(IR::Discard {
scope: scope.clone(),
});
self.when_recursive_ir(
pattern,
pattern_vec,
&mut vec![],
clause_properties.clone(),
tipo,
scope,
);
pattern_vec.append(values);
}
Pattern::Constructor { Pattern::Constructor {
arguments, arguments,
name: constr_name, name: constr_name,
@ -527,20 +621,11 @@ impl<'a> CodeGenerator<'a> {
let mut needs_clause_guard = false; let mut needs_clause_guard = false;
for arg in arguments { for arg in arguments {
match arg.value { check_when_pattern_needs(
Pattern::Var { .. } => { &arg.value,
needs_access_to_constr_var = true; &mut needs_access_to_constr_var,
} &mut needs_clause_guard,
Pattern::List { .. } );
| Pattern::Constructor { .. }
| Pattern::Tuple { .. } => {
needs_access_to_constr_var = true;
needs_clause_guard = true;
}
Pattern::Discard { .. } => {}
_ => todo!("{arg:#?}"),
}
} }
let data_type_key = match tipo { let data_type_key = match tipo {
@ -574,7 +659,7 @@ impl<'a> CodeGenerator<'a> {
location: Span::empty(), location: Span::empty(),
}, },
), ),
name: when_complexity.subject_var_name.clone(), name: clause_properties.clause_var_name.clone(),
scope: scope.clone(), scope: scope.clone(),
}]; }];
@ -588,16 +673,30 @@ impl<'a> CodeGenerator<'a> {
} }
if needs_clause_guard { if needs_clause_guard {
when_complexity.is_complex_clause = true; clause_properties.is_complex_clause = true;
} }
if needs_access_to_constr_var { if needs_access_to_constr_var {
when_complexity.needs_subject_var = true; clause_properties.needs_constr_var = true;
self.when_recursive_ir(pattern, pattern_vec, &mut new_vec, tipo, scope); self.when_recursive_ir(
pattern,
pattern_vec,
&mut new_vec,
clause_properties.clone(),
tipo,
scope,
);
pattern_vec.append(values); pattern_vec.append(values);
} else { } else {
self.when_recursive_ir(pattern, pattern_vec, &mut vec![], tipo, scope); self.when_recursive_ir(
pattern,
pattern_vec,
&mut vec![],
clause_properties.clone(),
tipo,
scope,
);
pattern_vec.append(values); pattern_vec.append(values);
} }
} }
@ -610,6 +709,7 @@ impl<'a> CodeGenerator<'a> {
pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>, pattern: &Pattern<tipo::PatternConstructor, Arc<tipo::Type>>,
pattern_vec: &mut Vec<IR>, pattern_vec: &mut Vec<IR>,
values: &mut Vec<IR>, values: &mut Vec<IR>,
clause_properties: ClauseProperties,
_tipo: &Type, _tipo: &Type,
scope: Vec<u64>, scope: Vec<u64>,
) { ) {
@ -625,7 +725,7 @@ impl<'a> CodeGenerator<'a> {
pattern_vec.append(values); pattern_vec.append(values);
} }
Pattern::List { elements, tail, .. } => { Pattern::List { elements, tail, .. } => {
let mut elements_vec = vec![]; // let mut elements_vec = vec![];
let mut names = vec![]; let mut names = vec![];
for element in elements { for element in elements {
@ -633,49 +733,85 @@ impl<'a> CodeGenerator<'a> {
Pattern::Var { name, .. } => { Pattern::Var { name, .. } => {
names.push(name.clone()); names.push(name.clone());
} }
a @ Pattern::List { .. } => { Pattern::Discard { .. } => {
let mut var_vec = vec![]; names.push("_".to_string());
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(), Pattern::List { .. } => {
ValueConstructorVariant::LocalVariable { todo!("Nested List Patterns Not Yet Done");
location: Span::empty(), // let mut var_vec = vec![];
}, // let item_name = format!("list_item_id_{}", self.id_gen.next());
), // names.push(item_name.clone());
name: item_name, // var_vec.push(IR::Var {
scope: scope.clone(), // constructor: ValueConstructor::public(
}); // Type::App {
self.pattern_ir(a, &mut elements_vec, &mut var_vec, scope.clone()); // 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!(), _ => todo!(),
} }
} }
let mut tail_name = String::new();
if let Some(tail) = tail { if let Some(tail) = tail {
match &**tail { match &**tail {
Pattern::Var { name, .. } => names.push(name.clone()), Pattern::Var { name, .. } => {
tail_name = name.clone();
}
Pattern::Discard { .. } => {} Pattern::Discard { .. } => {}
_ => unreachable!(), _ => todo!(),
} }
} }
pattern_vec.push(IR::ListAccessor { let tail_head_names = names
names, .iter()
tail: tail.is_some(), .enumerate()
.filter(|(_, name)| *name != &"_".to_string())
.map(|(index, name)| {
if index == 0 {
(
clause_properties.original_subject_name.clone(),
name.clone(),
)
} else {
(format!("__tail_{}", index - 1), name.clone())
}
})
.collect_vec();
if tail.is_some() && !elements.is_empty() {
let tail_var = if elements.len() == 1 {
clause_properties.original_subject_name
} else {
format!("__tail_{}", elements.len() - 2)
};
pattern_vec.push(IR::ListExpose {
scope, scope,
tail_head_names,
tail: Some((tail_var, tail_name)),
}); });
} else {
pattern_vec.push(IR::ListExpose {
scope,
tail_head_names,
tail: None,
});
}
pattern_vec.append(values); pattern_vec.append(values);
pattern_vec.append(&mut elements_vec);
todo!();
} }
Pattern::Constructor { Pattern::Constructor {
is_record, is_record,
@ -765,10 +901,12 @@ impl<'a> CodeGenerator<'a> {
}); });
} }
let mut clause_complexity = ClauseComplexity { let mut clause_complexity = ClauseProperties {
subject_var_name: constr_var_name.clone(), clause_var_name: constr_var_name.clone(),
needs_subject_var: false, needs_constr_var: false,
is_complex_clause: false, is_complex_clause: false,
current_index: 0,
original_subject_name: constr_var_name.clone(),
}; };
self.when_ir( self.when_ir(
@ -852,10 +990,12 @@ impl<'a> CodeGenerator<'a> {
subject_name: constr_var_name.clone(), subject_name: constr_var_name.clone(),
}); });
} }
let mut clause_complexity = ClauseComplexity { let mut clause_complexity = ClauseProperties {
subject_var_name: constr_var_name.clone(), clause_var_name: constr_var_name.clone(),
needs_subject_var: false, needs_constr_var: false,
is_complex_clause: false, is_complex_clause: false,
current_index: 0,
original_subject_name: constr_var_name.clone(),
}; };
self.when_ir( self.when_ir(
@ -1386,6 +1526,58 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
IR::ListExpose {
tail_head_names,
tail,
..
} => {
let mut term = arg_stack.pop().unwrap();
if let Some((tail_var, tail_name)) = tail {
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: tail_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList).force_wrap().into(),
argument: Term::Var(Name {
text: tail_var,
unique: 0.into(),
})
.into(),
}
.into(),
};
}
for (tail_var, head_name) in tail_head_names.into_iter().rev() {
term = Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: head_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::HeadList).force_wrap().into(),
argument: Term::Var(Name {
text: tail_var,
unique: 0.into(),
})
.into(),
}
.into(),
};
}
arg_stack.push(term);
}
IR::Call { count, .. } => { IR::Call { count, .. } => {
if count >= 2 { if count >= 2 {
let mut term = arg_stack.pop().unwrap(); let mut term = arg_stack.pop().unwrap();
@ -1762,7 +1954,7 @@ impl<'a> CodeGenerator<'a> {
// the body to be run if the clause matches // the body to be run if the clause matches
let body = arg_stack.pop().unwrap(); let body = arg_stack.pop().unwrap();
// the final branch in the when expression // the next branch in the when expression
let mut term = arg_stack.pop().unwrap(); let mut term = arg_stack.pop().unwrap();
let checker = if tipo.is_int() { let checker = if tipo.is_int() {
@ -1795,7 +1987,7 @@ impl<'a> CodeGenerator<'a> {
.into(), .into(),
} }
} else if tipo.is_list() { } else if tipo.is_list() {
todo!() unreachable!()
} else { } else {
Term::Apply { Term::Apply {
function: DefaultFunction::EqualsInteger.into(), function: DefaultFunction::EqualsInteger.into(),
@ -1864,6 +2056,68 @@ impl<'a> CodeGenerator<'a> {
arg_stack.push(term); arg_stack.push(term);
} }
IR::ListClause {
tail_name,
next_tail_name,
..
} => {
// discard to pop off
let _ = arg_stack.pop().unwrap();
// the body to be run if the clause matches
let body = arg_stack.pop().unwrap();
// the next branch in the when expression
let mut term = arg_stack.pop().unwrap();
let arg = if let Some(next_tail_name) = next_tail_name {
Term::Apply {
function: Term::Lambda {
parameter_name: Name {
text: next_tail_name,
unique: 0.into(),
},
body: term.into(),
}
.into(),
argument: Term::Apply {
function: Term::Builtin(DefaultFunction::TailList).force_wrap().into(),
argument: Term::Var(Name {
text: tail_name.clone(),
unique: 0.into(),
})
.into(),
}
.into(),
}
} else {
term
};
term = Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::ChooseList)
.force_wrap()
.force_wrap()
.into(),
argument: Term::Var(Name {
text: tail_name,
unique: 0.into(),
})
.into(),
}
.into(),
argument: Term::Delay(body.into()).into(),
}
.into(),
argument: Term::Delay(arg.into()).into(),
}
.force_wrap();
arg_stack.push(term);
}
IR::ClauseGuard { IR::ClauseGuard {
subject_name, tipo, .. subject_name, tipo, ..
} => { } => {
@ -2562,6 +2816,28 @@ impl<'a> CodeGenerator<'a> {
} }
} }
fn check_when_pattern_needs(
pattern: &Pattern<tipo::PatternConstructor, Arc<Type>>,
needs_access_to_constr_var: &mut bool,
needs_clause_guard: &mut bool,
) {
match pattern {
Pattern::Var { .. } => {
*needs_access_to_constr_var = true;
}
Pattern::List { .. }
| Pattern::Constructor { .. }
| Pattern::Tuple { .. }
| Pattern::Int { .. } => {
*needs_access_to_constr_var = true;
*needs_clause_guard = true;
}
Pattern::Discard { .. } => {}
_ => todo!("{pattern:#?}"),
}
}
fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> { fn get_common_ancestor(scope: &[u64], scope_prev: &[u64]) -> Vec<u64> {
let longest_length = if scope.len() >= scope_prev.len() { let longest_length = if scope.len() >= scope_prev.len() {
scope.len() scope.len()
@ -2723,3 +2999,149 @@ fn list_access_to_uplc(
} }
} }
} }
fn rearrange_clauses(
clauses: Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>>,
) -> Vec<Clause<TypedExpr, PatternConstructor, Arc<Type>, String>> {
let mut sorted_clauses = clauses;
// if we have a list sort clauses so we can plug holes for cases not covered by clauses
sorted_clauses.sort_by(|clause1, clause2| {
let clause1_len = match &clause1.pattern[0] {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 1000000,
};
let clause2_len = match &clause2.pattern[0] {
Pattern::List { elements, tail, .. } => elements.len() + usize::from(tail.is_some()),
_ => 1000001,
};
clause1_len.cmp(&clause2_len)
});
let mut elems_len = 0;
let mut final_clauses = sorted_clauses.clone();
let mut holes_to_fill = vec![];
let mut assign_plug_in_name = None;
let mut last_clause_index = 0;
let mut last_clause_set = false;
// If we have a catch all, use that. Otherwise use todo which will result in error
// TODO: fill in todo label with description
let plug_in_then = match &sorted_clauses[sorted_clauses.len() - 1].pattern[0] {
Pattern::Var { name, .. } => {
assign_plug_in_name = Some(name);
sorted_clauses[sorted_clauses.len() - 1].clone().then
}
Pattern::Discard { .. } => sorted_clauses[sorted_clauses.len() - 1].clone().then,
_ => TypedExpr::Todo {
location: Span::empty(),
label: None,
tipo: sorted_clauses[sorted_clauses.len() - 1].then.tipo(),
},
};
for (index, clause) in sorted_clauses.iter().enumerate() {
if let Pattern::List { elements, .. } = &clause.pattern[0] {
while elems_len < elements.len() {
let mut discard_elems = vec![];
for _ in 0..elems_len {
discard_elems.push(Pattern::Discard {
name: "_".to_string(),
location: Span::empty(),
});
}
let clause_to_fill = if let Some(name) = assign_plug_in_name {
Clause {
location: Span::empty(),
pattern: vec![Pattern::Assign {
name: name.clone(),
location: Span::empty(),
pattern: Pattern::List {
location: Span::empty(),
elements: discard_elems,
tail: None,
}
.into(),
}],
alternative_patterns: vec![],
guard: None,
then: plug_in_then.clone(),
}
} else {
Clause {
location: Span::empty(),
pattern: vec![Pattern::List {
location: Span::empty(),
elements: discard_elems,
tail: None,
}],
alternative_patterns: vec![],
guard: None,
then: plug_in_then.clone(),
}
};
holes_to_fill.push((index, clause_to_fill));
elems_len += 1;
}
}
if let Pattern::List {
elements,
tail: Some(tail),
..
} = &clause.pattern[0]
{
let mut elements = elements.clone();
elements.push(*tail.clone());
if elements
.iter()
.all(|element| matches!(element, Pattern::Var { .. } | Pattern::Discard { .. }))
&& !last_clause_set
{
last_clause_index = index;
last_clause_set = true;
}
}
if index == sorted_clauses.len() - 1 {
if let Pattern::List {
elements,
tail: Some(tail),
..
} = &clause.pattern[0]
{
let mut elements = elements.clone();
elements.push(*tail.clone());
if !elements
.iter()
.all(|element| matches!(element, Pattern::Var { .. } | Pattern::Discard { .. }))
{
final_clauses.push(Clause {
location: Span::empty(),
pattern: vec![Pattern::Discard {
name: "_".to_string(),
location: Span::empty(),
}],
alternative_patterns: vec![],
guard: None,
then: plug_in_then.clone(),
});
}
}
}
elems_len += 1;
}
final_clauses = final_clauses[0..(last_clause_index + 1)].to_vec();
for (index, clause) in holes_to_fill.into_iter().rev() {
final_clauses.insert(index, clause);
}
final_clauses
}

View File

@ -42,10 +42,6 @@ pub fn incrementor(counter: Int, target: Int) -> Int {
} }
} }
pub fn who(a: ByteArray) -> ByteArray {
builtin.append_bytearray(a, #[12, 255])
}
pub type Datum { pub type Datum {
Offer { prices: List(Int), asset_class: ByteArray, other_thing: Datum } Offer { prices: List(Int), asset_class: ByteArray, other_thing: Datum }
Sell Sell
@ -63,10 +59,17 @@ pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool {
.. ..
}, },
} -> 1 == 1 } -> 1 == 1
Offer { prices, other_thing: thing, .. } ->
when prices is {
[] -> True
[a] -> True
[a, b, c] -> True
[a, b, c, d, ..e] -> 1 == 1
rest -> False
}
_ -> False _ -> False
} }
} }
// let Redeemer{ signer, amount: amount2, other_thing: Redeemer{ signer: nested_signer, ..}} = datum // let Redeemer{ signer, amount: amount2, other_thing: Redeemer{ signer: nested_signer, ..}} = datum
// True // True
// when datum is { // when datum is {
@ -78,6 +81,6 @@ pub fn spend(datum: Datum, _rdmr: Nil, _ctx: Nil) -> Bool {
// [] -> True // [] -> True
// [1] -> False // [1] -> False
// [a, b] -> True // [a, b] -> True
// [a, b, ..c] -> False // [a, b, ..[a]] -> False
// } // }
// } // }