Continue work on integrating the decision tree into code gen

This commit is contained in:
microproofs 2024-10-23 14:24:49 -04:00
parent 61184fbb86
commit 342676f530
No known key found for this signature in database
GPG Key ID: 14F93C84DE6AFD17
3 changed files with 176 additions and 121 deletions

View File

@ -45,13 +45,14 @@ use builder::{
introduce_name, introduce_pattern, pop_pattern, softcast_data_to_type_otherwise,
unknown_data_to_type, DISCARDED,
};
use decision_tree::{get_tipo_by_path, TreeGen};
use decision_tree::{get_tipo_by_path, Assigned, DecisionTree, TreeGen};
use indexmap::{IndexMap, IndexSet};
use interner::AirInterner;
use itertools::Itertools;
use petgraph::{algo, Graph};
use std::{collections::HashMap, rc::Rc};
use stick_break_set::{Builtin, Builtins, TreeSet};
use stick_break_set::{Builtins, TreeSet};
use tree::Fields;
use uplc::{
ast::{Constant as UplcConstant, Name, NamedDeBruijn, Program, Term, Type as UplcType},
@ -556,9 +557,9 @@ impl<'a> CodeGenerator<'a> {
),
TypedExpr::When {
tipo,
subject,
clauses,
tipo,
..
} => {
if clauses.is_empty() {
@ -597,22 +598,14 @@ impl<'a> CodeGenerator<'a> {
tree
} else {
let constr_var = format!(
"__when_var_span_{}_{}",
subject.location().start,
subject.location().end
);
let subject_name = format!(
"__subject_var_span_{}_{}",
subject.location().start,
subject.location().end
);
self.interner.intern(constr_var.clone());
self.interner.intern(subject_name.clone());
let constr_var_interned = self.interner.lookup_interned(&constr_var);
let subject_name_interned = self.interner.lookup_interned(&subject_name);
let wild_card = TypedPattern::Discard {
@ -628,72 +621,25 @@ impl<'a> CodeGenerator<'a> {
let stick_set = TreeSet::new();
let clauses = self.handle_decision_tree(tree, stick_set);
self.interner.pop_text(constr_var);
self.interner.pop_text(subject_name);
// clauses = if subject.tipo().is_list() {
// rearrange_list_clauses(clauses, &self.data_types)
// } else {
// clauses
// };
// let last_clause = clauses.pop().unwrap();
// let constr_var = format!(
// "__when_var_span_{}_{}",
// subject.location().start,
// subject.location().end
// );
// let subject_name = format!(
// "__subject_var_span_{}_{}",
// subject.location().start,
// subject.location().end
// );
// self.interner.intern(constr_var.clone());
// self.interner.intern(subject_name.clone());
// let constr_var_interned = self.interner.lookup_interned(&constr_var);
// let subject_name_interned = self.interner.lookup_interned(&subject_name);
// let clauses = self.handle_each_clause(
// &clauses,
// last_clause,
// &subject.tipo(),
// &mut ClauseProperties::init(
// &subject.tipo(),
// constr_var_interned.clone(),
// subject_name_interned.clone(),
// ),
// module_build_name,
// );
// self.interner.pop_text(constr_var);
// self.interner.pop_text(subject_name);
let when_assign = AirTree::when(
subject_name_interned,
tipo.clone(),
let clauses = self.handle_decision_tree(
&subject_name,
subject.tipo(),
AirTree::local_var(&constr_var_interned, subject.tipo()),
clauses,
tipo.clone(),
module_build_name,
tree,
stick_set,
);
self.interner.pop_text(subject_name);
AirTree::let_assignment(
constr_var_interned,
subject_name_interned,
self.build(subject, module_build_name, &[]),
when_assign,
clauses,
)
}
}
// let pattern = branch.condition
// branch.body
//
// if <expr:condition> is <pattern>: <annotation> { <expr:body> }
// [(builtin ifThenElse) (condition is pattern) (body) (else) ]
TypedExpr::If {
branches,
final_else,
@ -2461,59 +2407,68 @@ impl<'a> CodeGenerator<'a> {
fn handle_decision_tree(
&mut self,
subject_name: &String,
subject_tipo: Rc<Type>,
return_tipo: Rc<Type>,
module_build_name: &str,
tree: decision_tree::DecisionTree<'_>,
mut stick_set: TreeSet,
) -> AirTree {
match tree {
decision_tree::DecisionTree::Switch {
subject_name,
subject_tipo,
DecisionTree::Switch {
path,
mut cases,
default,
} => {
//Current path to test
let current_tipo = get_tipo_by_path(subject_tipo.clone(), &path);
let builtins_path = Builtins::new_from_path(subject_tipo.clone(), path);
let current_subject_name = if builtins_path.is_empty() {
subject_name.clone()
} else {
format!("{}_{}", subject_name, builtins_path.to_string())
};
let mut prev_builtins = builtins_path.clone();
// Transition process from previous to current
let builtins_to_add = stick_set.diff_union_builtins(builtins_path.clone());
builtins_to_add.vec.iter().for_each(|_| {
prev_builtins.vec.pop();
});
// Previous path to apply the transition process too
let prev_builtins = Builtins {
vec: builtins_path.vec[0..(builtins_path.len() - builtins_to_add.len())]
.to_vec(),
};
let prev_subject_name = if prev_builtins.is_empty() {
subject_name.clone()
} else {
format!("{}_{}", subject_name, prev_builtins.to_string())
};
let prev_tipo = prev_builtins.vec.last().unwrap().tipo();
let current_subject_name = if builtins_path.is_empty() {
subject_name
} else {
format!("{}_{}", subject_name, builtins_path.to_string())
};
let prev_tipo = prev_builtins
.vec
.last()
.map_or(subject_tipo.clone(), |last| last.tipo());
let data_type = lookup_data_type_by_tipo(&self.data_types, &current_tipo);
let needs_default = if let Some(data_type) = &data_type {
data_type.constructors.len() != cases.len()
} else {
true
};
let last_then = if needs_default {
let last_clause = if data_type
.as_ref()
.map_or(true, |d| d.constructors.len() != cases.len())
{
*default.unwrap()
} else {
cases.pop().unwrap().1
};
let last_then = AirTree::anon_func(
let last_clause = AirTree::anon_func(
vec![],
self.handle_decision_tree(last_then, stick_set.clone()),
self.handle_decision_tree(
subject_name,
subject_tipo.clone(),
return_tipo.clone(),
module_build_name,
last_clause,
stick_set.clone(),
),
true,
);
@ -2523,11 +2478,14 @@ impl<'a> CodeGenerator<'a> {
current_subject_name.clone()
};
let clauses = cases.into_iter().rfold(last_then, |acc, (case, then)| {
let case_air = AirTree::anon_func(
vec![],
self.handle_decision_tree(then, stick_set.clone()),
true,
let clauses = cases.into_iter().rfold(last_clause, |acc, (case, then)| {
let case_air = self.handle_decision_tree(
subject_name,
subject_tipo.clone(),
return_tipo.clone(),
module_build_name,
then,
stick_set.clone(),
);
AirTree::clause(
@ -2552,21 +2510,122 @@ impl<'a> CodeGenerator<'a> {
x
}
decision_tree::DecisionTree::ListSwitch {
subject_name,
subject_tipo,
path,
cases,
tail_cases,
default,
} => todo!(),
decision_tree::DecisionTree::HoistedLeaf(_, vec) => todo!(),
decision_tree::DecisionTree::HoistThen {
DecisionTree::ListSwitch { .. } => todo!(),
DecisionTree::HoistedLeaf(name, args) => {
let air_args = args
.iter()
.map(|item| {
let current_tipo = get_tipo_by_path(subject_tipo.clone(), &item.path);
(
current_tipo.clone(),
AirTree::local_var(item.assigned.clone(), current_tipo),
)
})
.collect_vec();
let then = if args.is_empty() {
AirTree::local_var(
name,
Type::function(
air_args.iter().map(|i| i.0.clone()).collect_vec(),
return_tipo.clone(),
),
)
} else {
AirTree::anon_func(
vec![],
AirTree::call(
AirTree::local_var(
name,
Type::function(
air_args.iter().map(|i| i.0.clone()).collect_vec(),
return_tipo.clone(),
),
),
Type::void(),
air_args.into_iter().map(|i| i.1).collect_vec(),
),
true,
)
};
args.into_iter().rfold(then, |acc, assign| {
let Assigned { path, assigned } = assign;
let current_tipo = get_tipo_by_path(subject_tipo.clone(), &path);
let builtins_path = Builtins::new_from_path(subject_tipo.clone(), path);
let current_subject_name = if builtins_path.is_empty() {
subject_name.clone()
} else {
format!("{}_{}", subject_name, builtins_path.to_string())
};
// Transition process from previous to current
let builtins_to_add = stick_set.diff_union_builtins(builtins_path.clone());
// Previous path to apply the transition process too
let prev_builtins = Builtins {
vec: builtins_path.vec[0..(builtins_path.len() - builtins_to_add.len())]
.to_vec(),
};
let prev_subject_name = if prev_builtins.is_empty() {
subject_name.clone()
} else {
format!("{}_{}", subject_name, prev_builtins.to_string())
};
let prev_tipo = prev_builtins
.vec
.last()
.map_or(subject_tipo.clone(), |last| last.tipo());
let assignment = AirTree::let_assignment(
assigned,
AirTree::local_var(current_subject_name, current_tipo),
acc,
);
let thing = builtins_to_add.to_air(prev_subject_name, prev_tipo, assignment);
thing
})
}
DecisionTree::HoistThen {
name,
assigns,
pattern,
then,
} => todo!(),
} => {
let assign = AirTree::let_assignment(
name,
AirTree::anon_func(
assigns
.iter()
.map(|i| {
let assign = introduce_name(&mut self.interner, &i.assigned);
assign
})
.collect_vec(),
self.build(then, module_build_name, &[]),
true,
),
self.handle_decision_tree(
subject_name,
subject_tipo,
return_tipo,
module_build_name,
*pattern,
stick_set,
),
);
assigns.into_iter().for_each(|x| {
self.interner.pop_text(x.assigned);
});
assign
}
}
}

View File

@ -82,8 +82,8 @@ impl Eq for Path {}
#[derive(Clone, Debug)]
pub struct Assigned {
path: Vec<Path>,
assigned: String,
pub path: Vec<Path>,
pub assigned: String,
}
#[derive(Clone, Debug)]
@ -143,15 +143,11 @@ impl Display for CaseTest {
#[derive(Debug, Clone)]
pub enum DecisionTree<'a> {
Switch {
subject_name: String,
subject_tipo: Rc<Type>,
path: Vec<Path>,
cases: Vec<(CaseTest, DecisionTree<'a>)>,
default: Option<Box<DecisionTree<'a>>>,
},
ListSwitch {
subject_name: String,
subject_tipo: Rc<Type>,
path: Vec<Path>,
cases: Vec<(CaseTest, DecisionTree<'a>)>,
tail_cases: Vec<(CaseTest, DecisionTree<'a>)>,
@ -963,8 +959,6 @@ impl<'a, 'b> TreeGen<'a, 'b> {
.partition(|(case, _)| matches!(case, CaseTest::ListWithTail(_)));
DecisionTree::ListSwitch {
subject_name: subject_name.clone(),
subject_tipo: specialized_tipo.clone(),
path,
cases: cases
.into_iter()
@ -1015,8 +1009,6 @@ impl<'a, 'b> TreeGen<'a, 'b> {
};
DecisionTree::Switch {
subject_name: subject_name.clone(),
subject_tipo: specialized_tipo.clone(),
path,
cases: specialized_matrices
.into_iter()

View File

@ -154,6 +154,10 @@ impl Builtins {
}
}
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn is_empty(&self) -> bool {
self.vec.is_empty()
}
@ -227,7 +231,7 @@ impl TreeSet {
}
pub fn diff_union_builtins(&mut self, builtins: Builtins) -> Builtins {
if let Some((first, rest)) = builtins.vec.split_first() {
if let Some((first, _rest)) = builtins.vec.split_first() {
if self.children.iter().any(|item| first == &item.node) {
todo!()
} else {