mirror of
https://github.com/HigherOrderCO/Kind.git
synced 2024-10-27 00:32:44 +03:00
Refactor code generation to use Show
This commit is contained in:
parent
af819567fd
commit
67abc5cdf8
@ -82,6 +82,8 @@ impl Book {
|
|||||||
let maybe_ctr = Term::constructor_code((&def_name, &def_term), &ref_name);
|
let maybe_ctr = Term::constructor_code((&def_name, &def_term), &ref_name);
|
||||||
|
|
||||||
if let Some(ctr_code) = maybe_ctr {
|
if let Some(ctr_code) = maybe_ctr {
|
||||||
|
let ctr_code = ctr_code.flatten(Some(80));
|
||||||
|
|
||||||
let file_name = format!("{}.kind2", ref_name.trim_end_matches('/'));
|
let file_name = format!("{}.kind2", ref_name.trim_end_matches('/'));
|
||||||
let file_path = std::path::Path::new(&file_name);
|
let file_path = std::path::Path::new(&file_name);
|
||||||
let err = || format!("ERROR: could not create file for generated constructor {ref_name}");
|
let err = || format!("ERROR: could not create file for generated constructor {ref_name}");
|
||||||
@ -227,8 +229,22 @@ mod tests {
|
|||||||
fn constructor_generation() {
|
fn constructor_generation() {
|
||||||
let book_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("book");
|
let book_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("book");
|
||||||
let modules_to_test = [
|
let modules_to_test = [
|
||||||
"BBT", "BMap", "Bool", "Char", "Cmp", "Empty", "Equal", "List", "Maybe", "Monad", "Nat", "Pair",
|
"BBT",
|
||||||
"String", "Vector", "Tests/CtrGen/ParamsTest", "Tests/CtrGen/VectorTest"
|
"BMap",
|
||||||
|
"Bool",
|
||||||
|
"Char",
|
||||||
|
"Cmp",
|
||||||
|
"Empty",
|
||||||
|
"Equal",
|
||||||
|
"List",
|
||||||
|
"Maybe",
|
||||||
|
"Monad",
|
||||||
|
"Nat",
|
||||||
|
"Pair",
|
||||||
|
"String",
|
||||||
|
"Vector",
|
||||||
|
"Tests/CtrGen/ParamsTest",
|
||||||
|
"Tests/CtrGen/VectorTest",
|
||||||
];
|
];
|
||||||
|
|
||||||
for module in modules_to_test {
|
for module in modules_to_test {
|
||||||
@ -256,7 +272,8 @@ mod tests {
|
|||||||
|
|
||||||
let ctr_ref = full_name(&adt.name, ctr_name);
|
let ctr_ref = full_name(&adt.name, ctr_name);
|
||||||
let gen_code = Term::constructor_code((&adt.name, term), &ctr_ref).unwrap();
|
let gen_code = Term::constructor_code((&adt.name, term), &ctr_ref).unwrap();
|
||||||
let gen_term = KindParser::new(&gen_code).parse_def(0, &im::HashMap::new()).unwrap().1;
|
let gen_term =
|
||||||
|
KindParser::new(&gen_code.flatten(None)).parse_def(0, &im::HashMap::new()).unwrap().1;
|
||||||
|
|
||||||
let t1 = rename_variables(ctr_term, 0, &im::HashMap::new());
|
let t1 = rename_variables(ctr_term, 0, &im::HashMap::new());
|
||||||
let t2 = rename_variables(&gen_term, 0, &im::HashMap::new());
|
let t2 = rename_variables(&gen_term, 0, &im::HashMap::new());
|
||||||
|
@ -128,7 +128,7 @@ impl Show {
|
|||||||
},
|
},
|
||||||
Style::Glue => {
|
Style::Glue => {
|
||||||
for (i, c) in child.iter().enumerate() {
|
for (i, c) in child.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 && !c.is_empty() {
|
||||||
out.push_str(&join);
|
out.push_str(&join);
|
||||||
}
|
}
|
||||||
c.flatten_into(out, fmt, tab, lim);
|
c.flatten_into(out, fmt, tab, lim);
|
||||||
@ -162,6 +162,18 @@ impl Show {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks if the element contains no text.
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Show::Many { child, .. } => child.is_empty(),
|
||||||
|
Show::Text { value } => value.is_empty(),
|
||||||
|
Show::Line => false,
|
||||||
|
Show::Semi => false,
|
||||||
|
Show::Inc => false,
|
||||||
|
Show::Dec => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sums the width of all children ropes, up to a limit.
|
// Sums the width of all children ropes, up to a limit.
|
||||||
fn width(&self, lim: usize) -> usize {
|
fn width(&self, lim: usize) -> usize {
|
||||||
let mut total_width = 0;
|
let mut total_width = 0;
|
||||||
|
@ -394,7 +394,6 @@ impl<'i> KindParser<'i> {
|
|||||||
// ---
|
// ---
|
||||||
|
|
||||||
impl Term {
|
impl Term {
|
||||||
|
|
||||||
// Interprets a λ-encoded Algebraic Data Type definition as an ADT struct.
|
// Interprets a λ-encoded Algebraic Data Type definition as an ADT struct.
|
||||||
pub fn as_adt(&self) -> Option<ADT> {
|
pub fn as_adt(&self) -> Option<ADT> {
|
||||||
let name: String;
|
let name: String;
|
||||||
@ -662,7 +661,7 @@ impl Term {
|
|||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constructor_code((adt_name, adt_term): (&str, &Term), ctr_ref: &str) -> Option<String> {
|
pub fn constructor_code((adt_name, adt_term): (&str, &Term), ctr_ref: &str) -> Option<Box<Show>> {
|
||||||
// Check if `adt_name` really is an ADT
|
// Check if `adt_name` really is an ADT
|
||||||
let adt = match &adt_term {
|
let adt = match &adt_term {
|
||||||
// Type variables wrap ADTs in Lams
|
// Type variables wrap ADTs in Lams
|
||||||
@ -680,38 +679,68 @@ impl Term {
|
|||||||
// Search for constructor in ADT
|
// Search for constructor in ADT
|
||||||
let ctr_ref = ctr_ref.trim_end_matches('/'); // last "/" is not part of name
|
let ctr_ref = ctr_ref.trim_end_matches('/'); // last "/" is not part of name
|
||||||
let ctr = ctrs.iter().find(|ctr| format!("{adt_name}/{}", ctr.name) == ctr_ref)?.clone();
|
let ctr = ctrs.iter().find(|ctr| format!("{adt_name}/{}", ctr.name) == ctr_ref)?.clone();
|
||||||
let ctr_name = &ctr.name;
|
|
||||||
let names = ctrs.into_iter().map(|ctr| ctr.name);
|
|
||||||
|
|
||||||
// Generate constructor code:
|
// Generate constructor code:
|
||||||
|
|
||||||
// Type parameters
|
// Constructor name.
|
||||||
let format_param = |param| format!("<{}>", param);
|
let ctr_name = &ctr.name;
|
||||||
let params = adt.pars.iter().map(format_param).rev().collect::<Vec<_>>().join(" ");
|
|
||||||
|
|
||||||
// Constructor fields
|
// Type parameters.
|
||||||
let format_field = |(name, typ): &(String, Term)| format!("({name}: {})", typ.show());
|
// Format: <Par_1> .. <Par_n>
|
||||||
let fields = ctr.flds.iter().map(format_field).collect::<Vec<_>>().join(" ");
|
let format_param = |param| Show::text(&format!("<{}>", param));
|
||||||
|
let params = Show::glue(" ", adt.pars.iter().map(format_param).rev().collect());
|
||||||
|
|
||||||
// Constructor return type with type parameters and type indices
|
// Constructor fields.
|
||||||
let mut ctr_typ = vec![adt.name.clone()];
|
// Format: (f_1: T_1) .. (f_n: T_n)
|
||||||
adt.pars.into_iter().rev().for_each(|par| ctr_typ.push(par));
|
let format_field = |(name, typ): &(String, Term)| {
|
||||||
ctr.idxs.into_iter().rev().for_each(|idx| ctr_typ.push(idx.show()));
|
Show::glue("", vec![
|
||||||
let ctr_typ = format!("({})", ctr_typ.join(" "));
|
Show::text("("),
|
||||||
|
Show::glue("", vec![Show::text(name), Show::text(": "), typ.format()]),
|
||||||
|
Show::text(")"),
|
||||||
|
])
|
||||||
|
};
|
||||||
|
let fields = Show::glue(" ", ctr.flds.iter().map(format_field).collect());
|
||||||
|
|
||||||
// Constructor names into Scott-encoding
|
// Constructor return type with type parameters and type indices.
|
||||||
let format_ctr_lam_name = |ctr_name| format!("λ{ctr_name}");
|
// Format: (adt_name Par_1 .. Par_n Idx_1 .. Idx_n)
|
||||||
let ctr_lam_names = names.map(format_ctr_lam_name).collect::<Vec<_>>().join(" ");
|
let mut ctr_typ = vec![Show::text(&adt.name)];
|
||||||
|
adt.pars.iter().rev().for_each(|par| ctr_typ.push(Show::text(par)));
|
||||||
|
ctr.idxs.iter().rev().for_each(|idx| ctr_typ.push(idx.format()));
|
||||||
|
let ctr_typ = Show::glue("", vec![Show::text("("), Show::glue(" ", ctr_typ), Show::text(")")]);
|
||||||
|
|
||||||
// Fields without their types
|
// Constructor names into Scott-encoding.
|
||||||
let field_names = ctr.flds.iter().map(|(name, _)| name.clone()).collect::<Vec<_>>().join(" ");
|
// Format: λctr_name_1 .. λctr_name_n
|
||||||
|
let format_ctr_lam_name = |ctr_name| Show::text(&format!("λ{ctr_name}"));
|
||||||
|
let names = ctrs.into_iter().map(|ctr| ctr.name);
|
||||||
|
let ctr_lam_names = Show::glue(" ", names.map(format_ctr_lam_name).collect());
|
||||||
|
|
||||||
|
// Fields without their types.
|
||||||
|
// Format: f_1 .. f_n
|
||||||
|
let field_names = Show::glue(" ", ctr.flds.iter().map(|(name, _)| Show::text(name)).collect());
|
||||||
|
|
||||||
|
// Applies constructor and fields.
|
||||||
|
// Format: (ctr_name f_1 .. f_n)
|
||||||
|
let final_app = Show::glue("", vec![
|
||||||
|
Show::text("("),
|
||||||
|
Show::glue(" ", vec![Show::text(ctr_name), field_names]),
|
||||||
|
Show::text(")"),
|
||||||
|
]);
|
||||||
|
|
||||||
// The result should be in the following format:
|
// The result should be in the following format:
|
||||||
// ctr_name <Par_1> .. <Par_n> (f_1: T_1) .. (f_n: T_n): (adt_name Par_1 .. Par_n Idx_1 .. Idx_n) =
|
// ctr_name <Par_1> .. <Par_n> (f_1: T_1) .. (f_n: T_n): (adt_name Par_1 .. Par_n Idx_1 .. Idx_n) =
|
||||||
// ~λP λctr_name_1 .. λctr_name_n (ctr_name f_1 .. f_n)
|
// ~λP λctr_name_1 .. λctr_name_n (ctr_name f_1 .. f_n)
|
||||||
let ctr_text = format!(
|
let ctr_text = Show::glue(" ", vec![
|
||||||
"{ctr_name} {params} {fields}: {ctr_typ} =\n ~λP {ctr_lam_names} ({ctr_name} {field_names})"
|
Show::text(ctr_name),
|
||||||
);
|
params,
|
||||||
|
fields,
|
||||||
|
Show::text(":"),
|
||||||
|
ctr_typ,
|
||||||
|
Show::text("="),
|
||||||
|
Show::line(),
|
||||||
|
Show::text("~λP"),
|
||||||
|
ctr_lam_names,
|
||||||
|
final_app,
|
||||||
|
]);
|
||||||
|
|
||||||
Some(ctr_text)
|
Some(ctr_text)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user