From ae88843df0660874b02f0b616b0e982dc6c9bc1b Mon Sep 17 00:00:00 2001 From: Nicolas Abril Date: Wed, 30 Nov 2022 17:32:25 +0100 Subject: [PATCH] Feat: Add U120.new compilation to kdl --- crates/kind-target-kdl/src/compile.rs | 185 ++++++++++++------ .../kind-tests/suite/kdl/LinearizeVars.golden | 9 +- 2 files changed, 127 insertions(+), 67 deletions(-) diff --git a/crates/kind-target-kdl/src/compile.rs b/crates/kind-target-kdl/src/compile.rs index 524a9371..977768e9 100644 --- a/crates/kind-target-kdl/src/compile.rs +++ b/crates/kind-target-kdl/src/compile.rs @@ -126,7 +126,7 @@ pub fn compile_book( Ok(ctx.file) } -pub fn compile_rule(ctx: &mut CompileCtx, rule: &untyped::Rule) -> kindelia_lang::ast::Rule { +pub fn compile_rule(ctx: &mut CompileCtx, rule: &untyped::Rule) -> kdl::Rule { let name = *ctx.kdl_names.get(rule.name.to_str()).unwrap(); let mut args = Vec::new(); for pat in &rule.pats { @@ -139,13 +139,13 @@ pub fn compile_rule(ctx: &mut CompileCtx, rule: &untyped::Rule) -> kindelia_lang kdl::Rule { lhs, rhs } } -pub fn err_term() -> kindelia_lang::ast::Term { - kindelia_lang::ast::Term::Num { - numb: kindelia_lang::ast::U120::new(99999).unwrap(), +pub fn err_term() -> kdl::Term { + kdl::Term::Num { + numb: kdl::U120::new(99999).unwrap(), } } -pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kindelia_lang::ast::Term { +pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kdl::Term { use crate::untyped::ExprKind as From; use kdl::Term as To; match &expr.data { @@ -202,13 +202,24 @@ pub fn compile_expr(ctx: &mut CompileCtx, expr: &untyped::Expr) -> kindelia_lang } } From::Ctr { name, args } => { + // Convert U120 numbers into the native kindelia representation + // Only possible if both U60s are U60 terms + if name.to_str() == "U120.new" { + if let (From::U60 { numb: hi }, From::U60 { numb: lo }) = + (&args[0].data, &args[1].data) + { + let numb = kdl::U120(((*hi as u128) << 60) | (*lo as u128)); + return To::Num { numb }; + } + } let name = ctx.kdl_names.get(name.to_str()).unwrap().clone(); let args = args.iter().map(|x| compile_expr(ctx, &x)).collect(); To::Ctr { name, args } } From::Fun { name, args } => { match name.to_str() { - // Special compilation for some numeric functions + // Special inline compilation for + // some numeric function applications // Add with no boundary check is just a normal add "U60.add_unsafe" => To::Op2 { @@ -395,68 +406,114 @@ pub fn compile_entry(ctx: &mut CompileCtx, entry: &untyped::Entry) { ctx.file.runs.push(statement); } } else { - let name = ctx.kdl_names.get(entry.name.to_str()).cloned().unwrap(); - - let mut args = Vec::new(); - - for (name, range, _strictness) in &entry.args { - if let Ok(name) = kdl::Name::from_str(name) { - args.push(name) - } else { - ctx.send_err(Box::new(KdlError::InvalidVarName(*range))); - } - } - - if entry.rules.is_empty() { - // Functions with no rules become Ctr - let sttm = kdl::Statement::Ctr { - name, - args, - sign: None, - }; - ctx.file.ctrs.insert(entry.name.to_string(), sttm); - } else { - // Functions with rules become Fun - let rules = entry - .rules - .iter() - .map(|rule| compile_rule(ctx, rule)) - .collect::>(); - let func = kdl::Func { rules }; - - let init = if let Some(state_name) = &entry.attrs.kdl_state { - let init_entry = ctx.book.entrs.get(state_name.to_str()); - if let Some(entry) = init_entry { - if !entry.args.is_empty() { - ctx.send_err(Box::new(KdlError::ShouldNotHaveArguments(entry.range))); - None - } else if entry.rules.len() != 1 { - ctx.send_err(Box::new(KdlError::ShouldHaveOnlyOneRule(entry.range))); - None - } else { - ctx.kdl_states.push(state_name.to_string()); - Some(compile_expr(ctx, &entry.rules[0].body)) - } - } else { - ctx.send_err(Box::new(KdlError::NoInitEntry(state_name.range))); - None - } - } else { - None - }; - - let sttm = kdl::Statement::Fun { - name, - args, - func, - init, - sign: None, - }; - ctx.file.funs.insert(entry.name.to_string(), sttm); + match entry.name.to_str() { + "U120.new" => compile_u120_new(ctx, entry), + _ => compile_common_function(ctx, entry), } } } +fn compile_common_function(ctx: &mut CompileCtx, entry: &untyped::Entry) { + let name = ctx.kdl_names.get(entry.name.to_str()).cloned().unwrap(); + + let mut args = Vec::new(); + for (name, range, _strictness) in &entry.args { + if let Ok(name) = kdl::Name::from_str(name) { + args.push(name) + } else { + ctx.send_err(Box::new(KdlError::InvalidVarName(*range))); + } + } + + if entry.rules.is_empty() { + // Functions with no rules become Ctr + let sttm = kdl::Statement::Ctr { + name, + args, + sign: None, + }; + ctx.file.ctrs.insert(entry.name.to_string(), sttm); + } else { + // Functions with rules become Fun + let rules = entry + .rules + .iter() + .map(|rule| compile_rule(ctx, rule)) + .collect::>(); + let func = kdl::Func { rules }; + + let init = if let Some(state_name) = &entry.attrs.kdl_state { + let init_entry = ctx.book.entrs.get(state_name.to_str()); + if let Some(entry) = init_entry { + if !entry.args.is_empty() { + ctx.send_err(Box::new(KdlError::ShouldNotHaveArguments(entry.range))); + None + } else if entry.rules.len() != 1 { + ctx.send_err(Box::new(KdlError::ShouldHaveOnlyOneRule(entry.range))); + None + } else { + ctx.kdl_states.push(state_name.to_string()); + Some(compile_expr(ctx, &entry.rules[0].body)) + } + } else { + ctx.send_err(Box::new(KdlError::NoInitEntry(state_name.range))); + None + } + } else { + None + }; + + let sttm = kdl::Statement::Fun { + name, + args, + func, + init, + sign: None, + }; + ctx.file.funs.insert(entry.name.to_string(), sttm); + } +} + +fn compile_u120_new(ctx: &mut CompileCtx, entry: &untyped::Entry) { + // U120.new hi lo = (hi << 60) | lo + let hi_name = kdl::Name::from_str("hi").unwrap(); + let lo_name = kdl::Name::from_str("lo").unwrap(); + let hi_var = kdl::Term::Var { + name: hi_name.clone(), + }; + let lo_var = kdl::Term::Var { + name: lo_name.clone(), + }; + let name = ctx.kdl_names.get(entry.name.to_str()).cloned().unwrap(); + let args = vec![hi_name, lo_name]; + let rules = vec![kdl::Rule { + lhs: kdl::Term::Fun { + name: name.clone(), + args: vec![hi_var.clone(), lo_var.clone()], + }, + rhs: kdl::Term::Op2 { + oper: kdl::Oper::Or, + val0: Box::new(kdl::Term::Op2 { + oper: kdl::Oper::Shl, + val0: Box::new(hi_var), + val1: Box::new(kdl::Term::Num { + numb: kdl::U120(60), + }), + }), + val1: Box::new(lo_var), + }, + }]; + let func = kdl::Func { rules }; + let sttm = kdl::Statement::Fun { + name, + args, + func, + init: None, + sign: None, + }; + ctx.file.funs.insert(entry.name.to_string(), sttm); +} + impl Display for File { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { for ctr in &self.ctrs { diff --git a/crates/kind-tests/suite/kdl/LinearizeVars.golden b/crates/kind-tests/suite/kdl/LinearizeVars.golden index 572d4d5c..095f2796 100644 --- a/crates/kind-tests/suite/kdl/LinearizeVars.golden +++ b/crates/kind-tests/suite/kdl/LinearizeVars.golden @@ -1,7 +1,10 @@ -ctr {U120.new a b} ctr {List.cons h t} -fun (TestFunc xs) { - (TestFunc {List.cons ~ x1}) = (!@x1.0 (!@x2 dup c.0 x2.0 = x2; dup x2.1 x2.2 = c.0; (!@x3 (!@x3.0 (!@~ {List.cons (& (+ x2.0 x3.0) #1152921504606846975) x1.0} {U120.new #0 #4}) x3) (& (+ x2.1 x2.2) #1152921504606846975)) {U120.new #0 #2}) x1) +fun (U120.new hi lo) { + (U120.new x0 x1) = (!@x1.0 (!@x0.0 (| (<< x0.0 #60) x1.0) x0) x1) +} + +fun (TestFunc xs) { + (TestFunc {List.cons ~ x1}) = (!@x1.0 (!@x2 dup c.0 x2.0 = x2; dup x2.1 x2.2 = c.0; (!@x3 (!@x3.0 (!@~ {List.cons (& (+ x2.0 x3.0) #1152921504606846975) x1.0} #4) x3) (& (+ x2.1 x2.2) #1152921504606846975)) #2) x1) }