checkpoint
This commit is contained in:
parent
389699f485
commit
c6f90a999b
|
@ -38,8 +38,8 @@ use self::{
|
|||
air::Air,
|
||||
builder::{
|
||||
cast_validator_args, convert_type_to_data, lookup_data_type_by_tipo, modify_self_calls,
|
||||
rearrange_clauses, AssignmentProperties, ClauseProperties, DataTypeKey, FunctionAccessKey,
|
||||
UserFunction,
|
||||
rearrange_list_clauses, AssignmentProperties, ClauseProperties, DataTypeKey,
|
||||
FunctionAccessKey, UserFunction,
|
||||
},
|
||||
tree::{AirExpression, AirTree, TreePath},
|
||||
};
|
||||
|
@ -218,9 +218,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => {
|
||||
let mut expressions = expressions.clone();
|
||||
|
||||
let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| {
|
||||
unreachable!("Sequence or Pipeline should have at least one expression")
|
||||
}));
|
||||
assert!(
|
||||
!expressions.is_empty(),
|
||||
"Sequence or Pipeline should have at least one expression"
|
||||
);
|
||||
|
||||
let mut last_exp = self.build(&expressions.pop().unwrap_or_else(|| unreachable!()));
|
||||
|
||||
while let Some(expression) = expressions.pop() {
|
||||
let exp_tree = self.build(&expression);
|
||||
|
@ -276,8 +279,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
},
|
||||
..
|
||||
} => {
|
||||
let Some(data_type) = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
else {unreachable!("Creating a record with no record definition.")};
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
.expect("Creating a record with no record definition.");
|
||||
|
||||
let (constr_index, _) = data_type
|
||||
.constructors
|
||||
|
@ -299,7 +302,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
},
|
||||
..
|
||||
} => {
|
||||
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")};
|
||||
let fun_arg_types = fun
|
||||
.tipo()
|
||||
.arg_types()
|
||||
.expect("Expected a function type with arguments");
|
||||
|
||||
assert!(args.len() == fun_arg_types.len());
|
||||
|
||||
let func_args = args
|
||||
.iter()
|
||||
|
@ -331,7 +339,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let ValueConstructorVariant::ModuleFn { builtin, .. } = &value.variant else {unreachable!("Missing module function definition")};
|
||||
|
||||
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")};
|
||||
let fun_arg_types = fun
|
||||
.tipo()
|
||||
.arg_types()
|
||||
.expect("Expected a function type with arguments");
|
||||
|
||||
assert!(args.len() == fun_arg_types.len());
|
||||
|
||||
let func_args = args
|
||||
.iter()
|
||||
|
@ -353,7 +366,12 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
}
|
||||
_ => {
|
||||
let Some(fun_arg_types) = fun.tipo().arg_types() else {unreachable!("Expected a function type with arguments")};
|
||||
let fun_arg_types = fun
|
||||
.tipo()
|
||||
.arg_types()
|
||||
.expect("Expected a function type with arguments");
|
||||
|
||||
assert!(args.len() == fun_arg_types.len());
|
||||
|
||||
let func_args = args
|
||||
.iter()
|
||||
|
@ -447,7 +465,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
assignment.hoist_over(clause_then)
|
||||
} else {
|
||||
clauses = if subject.tipo().is_list() {
|
||||
rearrange_clauses(clauses)
|
||||
rearrange_list_clauses(clauses)
|
||||
} else {
|
||||
clauses
|
||||
};
|
||||
|
@ -478,6 +496,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
|
||||
let constr_assign = AirTree::let_assignment(&constr_var, self.build(subject));
|
||||
|
||||
let when_assign = AirTree::when(
|
||||
subject_name,
|
||||
tipo.clone(),
|
||||
|
@ -535,9 +554,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
location: Span::empty(),
|
||||
module: module_name.clone(),
|
||||
constructors_count: data_type
|
||||
.unwrap_or_else(|| {
|
||||
unreachable!("Created a module type without a definition?")
|
||||
})
|
||||
.expect("Created a module type without a definition?")
|
||||
.constructors
|
||||
.len() as u16,
|
||||
},
|
||||
|
@ -552,6 +569,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
});
|
||||
|
||||
let type_info = self.module_types.get(module_name).unwrap();
|
||||
|
||||
let value = type_info.values.get(name).unwrap();
|
||||
|
||||
if let Some(_func) = func {
|
||||
|
@ -643,6 +661,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
"__expected_by_{}_span_{}_{}",
|
||||
expected_int, location.start, location.end
|
||||
);
|
||||
|
||||
let assignment = AirTree::let_assignment(&name, value);
|
||||
|
||||
let expect = AirTree::binop(
|
||||
|
@ -660,9 +679,11 @@ impl<'a> CodeGenerator<'a> {
|
|||
Pattern::Var { name, .. } => {
|
||||
if props.full_check {
|
||||
let mut index_map = IndexMap::new();
|
||||
|
||||
let non_opaque_tipo = convert_opaque_type(tipo, &self.data_types);
|
||||
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
|
||||
if tipo.is_primitive() {
|
||||
|
@ -676,6 +697,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
|
||||
let assign_expect = AirTree::let_assignment("_", expect);
|
||||
|
||||
AirTree::let_assignment(
|
||||
name,
|
||||
assignment.hoist_over(assign_expect.hoist_over(val)),
|
||||
|
@ -688,6 +710,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
Pattern::Assign { name, pattern, .. } => {
|
||||
let inner_pattern =
|
||||
self.assignment(pattern, AirTree::local_var(name, tipo.clone()), tipo, props);
|
||||
|
||||
let assign = AirTree::let_assignment(name, value);
|
||||
|
||||
AirTree::UnhoistedSequence(vec![assign, inner_pattern])
|
||||
|
@ -696,9 +719,13 @@ impl<'a> CodeGenerator<'a> {
|
|||
if props.full_check {
|
||||
let name = &format!("__discard_expect_{}", name);
|
||||
let mut index_map = IndexMap::new();
|
||||
|
||||
let tipo = convert_opaque_type(tipo, &self.data_types);
|
||||
|
||||
let assignment = AirTree::let_assignment(name, value);
|
||||
|
||||
let val = AirTree::local_var(name, tipo.clone());
|
||||
|
||||
if tipo.is_primitive() {
|
||||
AirTree::let_assignment(name, assignment.hoist_over(val))
|
||||
} else {
|
||||
|
@ -710,6 +737,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
|
||||
let assign_expect = AirTree::let_assignment("_", expect);
|
||||
|
||||
AirTree::let_assignment(
|
||||
name,
|
||||
assignment.hoist_over(assign_expect.hoist_over(val)),
|
||||
|
@ -724,6 +752,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
Pattern::List { elements, tail, .. } => {
|
||||
assert!(tipo.is_list());
|
||||
assert!(props.kind.is_expect());
|
||||
|
||||
let list_elem_types = tipo.get_inner_types();
|
||||
|
||||
let list_elem_type = list_elem_types
|
||||
|
@ -843,7 +872,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else {
|
||||
if props.kind.is_expect() {
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo)
|
||||
.unwrap_or_else(|| panic!("Failed to find definition for {}", name));
|
||||
.unwrap_or_else(|| {
|
||||
unreachable!("Failed to find definition for {}", name)
|
||||
});
|
||||
|
||||
if data_type.constructors.len() > 1 || props.full_check {
|
||||
let (index, _) = data_type
|
||||
|
@ -885,11 +916,19 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let mut type_map: IndexMap<usize, Arc<Type>> = IndexMap::new();
|
||||
|
||||
for (index, arg) in constr_tipo.arg_types().unwrap().iter().enumerate() {
|
||||
for (index, arg) in constr_tipo
|
||||
.arg_types()
|
||||
.expect("Mismatched type")
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
let field_type = arg.clone();
|
||||
|
||||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
assert!(type_map.len() == arguments.len());
|
||||
|
||||
let fields = arguments
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
@ -979,7 +1018,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
type_map.insert(index, field_type);
|
||||
}
|
||||
|
||||
println!("TIPO {:#?}", tipo);
|
||||
assert!(type_map.len() == elems.len());
|
||||
|
||||
let elems = elems
|
||||
.iter()
|
||||
|
@ -1055,13 +1094,16 @@ impl<'a> CodeGenerator<'a> {
|
|||
location: Span,
|
||||
) -> AirTree {
|
||||
assert!(tipo.get_generic().is_none());
|
||||
|
||||
if tipo.is_primitive() {
|
||||
// Since we would return void anyway and ignore then we can just return value here and ignore
|
||||
value
|
||||
} else if tipo.is_map() {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
let inner_pair_types = inner_list_type.get_inner_types();
|
||||
|
||||
assert!(inner_pair_types.len() == 2);
|
||||
|
||||
let map_name = format!("__map_span_{}_{}", location.start, location.end);
|
||||
|
@ -1142,6 +1184,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
assign.hoist_over(func_call)
|
||||
} else if tipo.is_list() {
|
||||
assert!(!tipo.get_inner_types().is_empty());
|
||||
|
||||
let inner_list_type = &tipo.get_inner_types()[0];
|
||||
|
||||
let list_name = format!("__list_span_{}_{}", location.start, location.end);
|
||||
|
@ -1206,6 +1249,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else if tipo.is_2_tuple() {
|
||||
let tuple_inner_types = tipo.get_inner_types();
|
||||
|
||||
assert!(tuple_inner_types.len() == 2);
|
||||
|
||||
let pair_name = format!("__pair_span_{}_{}", location.start, location.end);
|
||||
|
||||
let fst_name = format!("__pair_fst_span_{}_{}", location.start, location.end);
|
||||
|
@ -1243,6 +1288,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else if tipo.is_tuple() {
|
||||
let tuple_inner_types = tipo.get_inner_types();
|
||||
|
||||
assert!(!tuple_inner_types.is_empty());
|
||||
|
||||
let tuple_name = format!("__tuple_span_{}_{}", location.start, location.end);
|
||||
let tuple_assign = AirTree::let_assignment(&tuple_name, value);
|
||||
|
||||
|
@ -1293,7 +1340,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
AirTree::UnhoistedSequence(sequence).hoist_over(AirTree::void())
|
||||
} else {
|
||||
let data_type = lookup_data_type_by_tipo(&self.data_types, tipo).unwrap_or_else(|| {
|
||||
unreachable!("We need a data type definition fot type {:#?}", tipo)
|
||||
unreachable!("We need a data type definition for type {:#?}", tipo)
|
||||
});
|
||||
|
||||
let data_type_variant = tipo
|
||||
|
@ -1302,6 +1349,8 @@ impl<'a> CodeGenerator<'a> {
|
|||
.map(|arg| get_arg_type_name(arg))
|
||||
.join("_");
|
||||
|
||||
assert!(data_type.typed_parameters.len() == tipo.arg_types().unwrap().len());
|
||||
|
||||
let mono_types: IndexMap<u64, Arc<Type>> = if !data_type.typed_parameters.is_empty() {
|
||||
data_type
|
||||
.typed_parameters
|
||||
|
@ -1484,8 +1533,10 @@ impl<'a> CodeGenerator<'a> {
|
|||
if let Some((clause, rest_clauses)) = clauses.split_first() {
|
||||
let mut clause_then = self.build(&clause.then);
|
||||
|
||||
// handles clause guard if it exists
|
||||
if let Some(guard) = &clause.guard {
|
||||
props.complex_clause = true;
|
||||
|
||||
let clause_guard_name = format!(
|
||||
"__clause_guard_span_{}_{}",
|
||||
clause.location.start, clause.location.end
|
||||
|
@ -1546,6 +1597,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
)
|
||||
}
|
||||
} else {
|
||||
// Case of ByteArray or Int or Bool matches
|
||||
assert!(subject_tipo.is_primitive());
|
||||
|
||||
AirTree::clause(
|
||||
&props.original_subject_name,
|
||||
clause_cond,
|
||||
|
@ -1564,7 +1618,19 @@ impl<'a> CodeGenerator<'a> {
|
|||
SpecificClause::ListClause {
|
||||
current_index,
|
||||
defined_tails,
|
||||
checked_index,
|
||||
} => {
|
||||
let mut clause_pattern = &clause.pattern;
|
||||
|
||||
if let Pattern::Assign { pattern, .. } = clause_pattern {
|
||||
clause_pattern = pattern;
|
||||
}
|
||||
|
||||
assert!(matches!(
|
||||
clause_pattern,
|
||||
Pattern::List { .. } | Pattern::Var { .. } | Pattern::Discard { .. }
|
||||
));
|
||||
|
||||
let Pattern::List { elements, tail, .. } = &clause.pattern
|
||||
else {
|
||||
let mut next_clause_props = ClauseProperties {
|
||||
|
@ -1576,6 +1642,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
specific_clause: SpecificClause::ListClause {
|
||||
current_index: *current_index,
|
||||
defined_tails: defined_tails.clone(),
|
||||
checked_index: *checked_index,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1595,31 +1662,37 @@ impl<'a> CodeGenerator<'a> {
|
|||
);
|
||||
};
|
||||
|
||||
let mut tail_name = if *current_index == 0 {
|
||||
props.original_subject_name.clone()
|
||||
} else {
|
||||
format!(
|
||||
"tail_index_{}_span_{}_{}",
|
||||
*current_index,
|
||||
clause.pattern.location().start,
|
||||
clause.pattern.location().end
|
||||
)
|
||||
};
|
||||
let tail_name = defined_tails
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(props.original_subject_name.clone());
|
||||
|
||||
let next_tail_name = {
|
||||
if rest_clauses.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let next_clause = &rest_clauses[0];
|
||||
|
||||
let next_elements_len = match &next_clause.pattern {
|
||||
Pattern::List { elements, .. } => elements.len(),
|
||||
Pattern::List { elements, tail, .. } => {
|
||||
elements.len() - usize::from(tail.is_some())
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
if (*current_index as usize) < next_elements_len {
|
||||
*current_index += 1;
|
||||
|
||||
defined_tails.push(format!(
|
||||
"tail_index_{}_span_{}_{}",
|
||||
*current_index,
|
||||
clause.pattern.location().start,
|
||||
clause.pattern.location().end
|
||||
));
|
||||
|
||||
Some(format!(
|
||||
"tail_index_{}_span_{}_{}",
|
||||
*current_index + 1,
|
||||
*current_index,
|
||||
next_clause.pattern.location().start,
|
||||
next_clause.pattern.location().end
|
||||
))
|
||||
|
@ -1629,16 +1702,21 @@ impl<'a> CodeGenerator<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
if elements.len() - usize::from(tail.is_some() && !elements.is_empty())
|
||||
>= *current_index as usize
|
||||
let mut is_wild_card_elems_clause = clause.guard.is_none();
|
||||
for elements in elements.iter() {
|
||||
if let Pattern::Constructor { .. }
|
||||
| Pattern::Tuple { .. }
|
||||
| Pattern::List { .. } = elements
|
||||
{
|
||||
is_wild_card_elems_clause = false;
|
||||
}
|
||||
}
|
||||
let elements_len = elements.len() - usize::from(tail.is_some());
|
||||
|
||||
if *checked_index < elements_len.try_into().unwrap()
|
||||
&& is_wild_card_elems_clause
|
||||
{
|
||||
*current_index += 1;
|
||||
defined_tails.push(tail_name.clone());
|
||||
} else if next_tail_name.is_none() {
|
||||
tail_name = defined_tails
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(props.original_subject_name.clone());
|
||||
*checked_index += 1;
|
||||
}
|
||||
|
||||
let mut next_clause_props = ClauseProperties {
|
||||
|
@ -1650,6 +1728,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
specific_clause: SpecificClause::ListClause {
|
||||
current_index: *current_index,
|
||||
defined_tails: defined_tails.clone(),
|
||||
checked_index: *checked_index,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1660,6 +1739,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
|
||||
let complex_clause = props.complex_clause;
|
||||
|
||||
// TODO: stuff
|
||||
AirTree::list_clause(
|
||||
tail_name,
|
||||
subject_tipo.clone(),
|
||||
|
@ -1734,7 +1814,9 @@ impl<'a> CodeGenerator<'a> {
|
|||
} else {
|
||||
// handle final_clause
|
||||
props.final_clause = true;
|
||||
|
||||
assert!(final_clause.guard.is_none());
|
||||
|
||||
let clause_then = self.build(&final_clause.then);
|
||||
let (condition, assignments) =
|
||||
self.clause_pattern(&final_clause.pattern, subject_tipo, props);
|
||||
|
@ -2190,6 +2272,7 @@ impl<'a> CodeGenerator<'a> {
|
|||
SpecificClause::ListClause {
|
||||
current_index,
|
||||
defined_tails,
|
||||
..
|
||||
},
|
||||
..
|
||||
} = props
|
||||
|
|
|
@ -100,6 +100,7 @@ pub enum SpecificClause {
|
|||
ListClause {
|
||||
current_index: i64,
|
||||
defined_tails: Vec<String>,
|
||||
checked_index: i64,
|
||||
},
|
||||
TupleClause {
|
||||
defined_tuple_indices: IndexSet<(usize, String)>,
|
||||
|
@ -118,6 +119,7 @@ impl ClauseProperties {
|
|||
specific_clause: SpecificClause::ListClause {
|
||||
current_index: 0,
|
||||
defined_tails: vec![],
|
||||
checked_index: -1,
|
||||
},
|
||||
}
|
||||
} else if t.is_tuple() {
|
||||
|
@ -159,6 +161,7 @@ impl ClauseProperties {
|
|||
specific_clause: SpecificClause::ListClause {
|
||||
current_index: 0,
|
||||
defined_tails: vec![],
|
||||
checked_index: -1,
|
||||
},
|
||||
}
|
||||
} else if t.is_tuple() {
|
||||
|
@ -598,7 +601,8 @@ pub fn modify_self_calls(air_tree: &mut AirTree, func_key: &FunctionAccessKey, v
|
|||
}
|
||||
}
|
||||
|
||||
pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
||||
// TODO: write some tests
|
||||
pub fn rearrange_list_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
||||
let mut sorted_clauses = clauses;
|
||||
|
||||
// if we have a list sort clauses so we can plug holes for cases not covered by clauses
|
||||
|
@ -610,7 +614,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
.sorted_by(|(index1, clause1), (index2, clause2)| {
|
||||
let clause1_len = match &clause1.pattern {
|
||||
Pattern::List { elements, tail, .. } => {
|
||||
Some(elements.len() + usize::from(tail.is_some()))
|
||||
Some(elements.len() + usize::from(tail.is_some() && clause1.guard.is_none()))
|
||||
}
|
||||
_ if clause1.guard.is_none() => Some(100000),
|
||||
_ => None,
|
||||
|
@ -618,7 +622,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
|
||||
let clause2_len = match &clause2.pattern {
|
||||
Pattern::List { elements, tail, .. } => {
|
||||
Some(elements.len() + usize::from(tail.is_some()))
|
||||
Some(elements.len() + usize::from(tail.is_some() && clause2.guard.is_none()))
|
||||
}
|
||||
_ if clause2.guard.is_none() => Some(100001),
|
||||
_ => None,
|
||||
|
@ -635,15 +639,15 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
.map(|(_, item)| item)
|
||||
.collect_vec();
|
||||
|
||||
let mut elems_len = 0;
|
||||
let mut final_clauses = sorted_clauses.clone();
|
||||
let mut holes_to_fill = vec![];
|
||||
let mut last_clause_index = 0;
|
||||
let mut last_clause_set = false;
|
||||
let mut wild_card_clause_elems = 0;
|
||||
|
||||
// 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 = |index: usize, last_clause: &TypedClause| {
|
||||
let plug_in_then = &|index: usize, last_clause: &TypedClause| {
|
||||
if last_clause.guard.is_none() {
|
||||
match &last_clause.pattern {
|
||||
Pattern::Var { .. } | Pattern::Discard { .. } => last_clause.clone().then,
|
||||
|
@ -692,14 +696,29 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
};
|
||||
|
||||
for (index, clause) in sorted_clauses.iter().enumerate() {
|
||||
if let Pattern::List { elements, .. } = &clause.pattern {
|
||||
if last_clause_set {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut clause_pattern = &clause.pattern;
|
||||
|
||||
if let Pattern::Assign { pattern, .. } = clause_pattern {
|
||||
clause_pattern = pattern;
|
||||
}
|
||||
|
||||
assert!(matches!(
|
||||
clause_pattern,
|
||||
Pattern::List { .. } | Pattern::Var { .. } | Pattern::Discard { .. }
|
||||
));
|
||||
|
||||
if let Pattern::List { elements, tail, .. } = &clause.pattern {
|
||||
// found a hole and now we plug it
|
||||
while elems_len < elements.len() {
|
||||
while wild_card_clause_elems < elements.len() - usize::from(tail.is_some()) {
|
||||
let mut discard_elems = vec![];
|
||||
|
||||
for _ in 0..elems_len {
|
||||
for _ in 0..wild_card_clause_elems {
|
||||
discard_elems.push(Pattern::Discard {
|
||||
name: "_".to_string(),
|
||||
name: "__fill".to_string(),
|
||||
location: Span::empty(),
|
||||
});
|
||||
}
|
||||
|
@ -719,7 +738,7 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
.into(),
|
||||
},
|
||||
guard: None,
|
||||
then: plug_in_then(elems_len, last_clause),
|
||||
then: plug_in_then(wild_card_clause_elems, last_clause),
|
||||
}
|
||||
} else {
|
||||
TypedClause {
|
||||
|
@ -730,44 +749,38 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
tail: None,
|
||||
},
|
||||
guard: None,
|
||||
then: plug_in_then(elems_len, last_clause),
|
||||
then: plug_in_then(wild_card_clause_elems, last_clause),
|
||||
}
|
||||
};
|
||||
|
||||
holes_to_fill.push((index, clause_to_fill));
|
||||
elems_len += 1;
|
||||
wild_card_clause_elems += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a pattern with no clause guards and a tail then no lists will get past here to other clauses
|
||||
if clause.guard.is_none() {
|
||||
match &clause.pattern {
|
||||
Pattern::Var { .. } => {
|
||||
last_clause_index = index + 1;
|
||||
last_clause_set = true;
|
||||
let mut is_wild_card_elems_clause = clause.guard.is_none();
|
||||
|
||||
for elements in elements.iter() {
|
||||
if let Pattern::Constructor { .. } | Pattern::Tuple { .. } | Pattern::List { .. } =
|
||||
elements
|
||||
{
|
||||
is_wild_card_elems_clause = false;
|
||||
}
|
||||
Pattern::Discard { .. } => {
|
||||
last_clause_index = index + 1;
|
||||
last_clause_set = true;
|
||||
}
|
||||
Pattern::List {
|
||||
elements,
|
||||
tail: Some(tail),
|
||||
..
|
||||
} => {
|
||||
let mut elements = elements.clone();
|
||||
elements.push(*tail.clone());
|
||||
if elements.iter().all(|element| {
|
||||
matches!(element, Pattern::Var { .. } | Pattern::Discard { .. })
|
||||
}) && !last_clause_set
|
||||
&& !elements.is_empty()
|
||||
{
|
||||
last_clause_index = index + 1;
|
||||
last_clause_set = true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if is_wild_card_elems_clause {
|
||||
wild_card_clause_elems += 1;
|
||||
if clause.guard.is_none() && tail.is_some() {
|
||||
last_clause_index = index;
|
||||
last_clause_set = true;
|
||||
}
|
||||
}
|
||||
} else if let Pattern::Var { .. } | Pattern::Discard { .. } = &clause.pattern {
|
||||
if clause.guard.is_none() {
|
||||
last_clause_set = true;
|
||||
last_clause_index = index;
|
||||
}
|
||||
} else {
|
||||
unreachable!("Found a clause that is not a list or var or discard");
|
||||
}
|
||||
|
||||
// If the last condition doesn't have a catch all or tail then add a catch all with a todo
|
||||
|
@ -784,8 +797,6 @@ pub fn rearrange_clauses(clauses: Vec<TypedClause>) -> Vec<TypedClause> {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
elems_len += 1;
|
||||
}
|
||||
|
||||
// Encountered a tail so stop there with that as last clause
|
||||
|
|
Loading…
Reference in New Issue