///|
fn[T] without_index(values : Array[T], removed : Int32) -> Array[T] {
values[:removed].to_owned() + values[removed + 1:].to_owned()
}
///|
fn Expr::rewrite_tree(self : Expr, rewrite : (Expr) -> Expr) -> Expr {
rewrite(self.map_children(child => child.rewrite_tree(rewrite)))
}
///|
fn Template::rewrite_all(self : Template, rewrite : (Expr) -> Expr) -> Template {
{
..self,
functions: self.functions.map(f => {
..f,
body: f.body.rewrite_tree(rewrite),
}),
result: self.result.rewrite_tree(rewrite),
}
}
///|
fn Expr::uses_variant(
self : Expr,
enum_id : Int32,
variant_tag : Int32,
) -> Bool {
let mut used = false
ignore(
self.rewrite_tree(expr => {
if expr is Variant(id, tag, _) && id == enum_id && tag == variant_tag {
used = true
}
expr
}),
)
used
}
///|
fn Template::coordinated_templates(self : Template) -> Array[Template] {
let candidates : Array[Template] = []
for id, function in self.functions {
for removed in 0.. {
match expr {
Call(callee, arguments) if callee == id =>
Call(callee, without_index(arguments, removed))
_ => expr
}
}),
)
}
}
for id, definition in self.enums {
for tag, fields in definition.variants {
let used = self.result.uses_variant(id, tag) ||
self.functions.any(f => f.body.uses_variant(id, tag))
if definition.variants.length() > 1 && !used {
let enums = self.enums.copy()
enums[id] = { variants: without_index(definition.variants, tag), }
candidates.push(
{ ..self, enums, }.rewrite_all(expr => {
match expr {
Variant(enum_id, variant_tag, arguments) if enum_id == id &&
variant_tag > tag =>
Variant(enum_id, variant_tag - 1, arguments)
Match(enum_id, value, arms) if enum_id == id =>
Match(enum_id, value, without_index(arms, tag))
_ => expr
}
}),
)
}
for removed in 0.. {
match expr {
Variant(enum_id, variant_tag, arguments) if enum_id == id &&
variant_tag == tag =>
Variant(enum_id, variant_tag, without_index(arguments, removed))
Match(enum_id, value, arms) if enum_id == id => {
let smaller = arms.copy()
smaller[tag] = {
..arms[tag],
parameters: without_index(arms[tag].parameters, removed),
}
Match(enum_id, value, smaller)
}
_ => expr
}
}),
)
}
}
}
candidates
}