From f9dcd41fccb6da429c8c619b2c011e7dcf3ac10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20S=C3=BCberkr=C3=BCb?= Date: Sat, 4 Jan 2025 23:28:11 +0100 Subject: [PATCH] Generate IR from AST --- lang/backend/src/ast2ir/decls.rs | 96 ++++++++++++++++++ lang/backend/src/ast2ir/exprs.rs | 160 ++++++++++++++++++++++++++++++ lang/backend/src/ast2ir/mod.rs | 3 + lang/backend/src/ast2ir/traits.rs | 26 +++++ lang/backend/src/ir/decls.rs | 8 +- lang/backend/src/ir/exprs.rs | 8 ++ lang/backend/src/lib.rs | 1 + 7 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 lang/backend/src/ast2ir/decls.rs create mode 100644 lang/backend/src/ast2ir/exprs.rs create mode 100644 lang/backend/src/ast2ir/mod.rs create mode 100644 lang/backend/src/ast2ir/traits.rs diff --git a/lang/backend/src/ast2ir/decls.rs b/lang/backend/src/ast2ir/decls.rs new file mode 100644 index 000000000..2df7e8a19 --- /dev/null +++ b/lang/backend/src/ast2ir/decls.rs @@ -0,0 +1,96 @@ +use crate::ir; +use crate::result::BackendError; + +use super::traits::ToIR; + +impl ToIR for ast::Module { + type Target = ir::Module; + + fn to_ir(&self) -> Result { + let ast::Module { uri, use_decls, decls, meta_vars: _ } = self; + + let mut def_decls = Vec::new(); + let mut codef_decls = Vec::new(); + let mut let_decls = Vec::new(); + + for decl in decls { + match decl { + ast::Decl::Def(def) => def_decls.push(def.to_ir()?), + ast::Decl::Codef(codef) => codef_decls.push(codef.to_ir()?), + ast::Decl::Let(tl_let) => let_decls.push(tl_let.to_ir()?), + ast::Decl::Data(_) => {} + ast::Decl::Codata(_) => {} + } + } + + Ok(ir::Module { + uri: uri.clone(), + use_decls: use_decls.clone(), + def_decls, + codef_decls, + let_decls, + }) + } +} + +impl ToIR for ast::Def { + type Target = ir::Def; + + fn to_ir(&self) -> Result { + let ast::Def { name, params, self_param, cases, .. } = self; + + let params = params + .params + .iter() + .filter(|param| !param.erased) + .map(|param| param.name.to_string()) + .collect(); + + let cases = cases.to_ir()?; + + Ok(ir::Def { + name: name.to_string(), + self_param: self_param.name.as_ref().map(|nm| nm.to_string()).unwrap_or_default(), + params, + cases, + }) + } +} + +impl ToIR for ast::Codef { + type Target = ir::Codef; + + fn to_ir(&self) -> Result { + let ast::Codef { name, params, cases, .. } = self; + + let params = params + .params + .iter() + .filter(|param| !param.erased) + .map(|param| param.name.to_string()) + .collect(); + + let cases = cases.to_ir()?; + + Ok(ir::Codef { name: name.to_string(), params, cases }) + } +} + +impl ToIR for ast::Let { + type Target = ir::Let; + + fn to_ir(&self) -> Result { + let ast::Let { name, params, body, .. } = self; + + let params = params + .params + .iter() + .filter(|param| !param.erased) + .map(|param| param.name.to_string()) + .collect(); + + let body = Box::new(body.to_ir()?); + + Ok(ir::Let { name: name.to_string(), params, body }) + } +} diff --git a/lang/backend/src/ast2ir/exprs.rs b/lang/backend/src/ast2ir/exprs.rs new file mode 100644 index 000000000..3826e9194 --- /dev/null +++ b/lang/backend/src/ast2ir/exprs.rs @@ -0,0 +1,160 @@ +use ast::LocalComatch; + +use crate::ir; +use crate::result::BackendError; + +use super::traits::ToIR; + +impl ToIR for ast::Exp { + type Target = ir::Exp; + + fn to_ir(&self) -> Result { + let out = match self { + ast::Exp::Variable(variable) => ir::Exp::Variable(variable.to_ir()?), + ast::Exp::TypCtor(_) => ir::Exp::ZST, + ast::Exp::Call(call) => match call.kind { + ast::CallKind::Constructor => ir::Exp::CtorCall(call.to_ir()?), + ast::CallKind::Codefinition => ir::Exp::CodefCall(call.to_ir()?), + ast::CallKind::LetBound => ir::Exp::LetCall(call.to_ir()?), + }, + ast::Exp::DotCall(dot_call) => match dot_call.kind { + ast::DotCallKind::Destructor => ir::Exp::DtorCall(dot_call.to_ir()?), + ast::DotCallKind::Definition => ir::Exp::DefCall(dot_call.to_ir()?), + }, + ast::Exp::Anno(anno) => anno.exp.to_ir()?, + ast::Exp::TypeUniv(_) => ir::Exp::ZST, + ast::Exp::LocalMatch(local_match) => ir::Exp::LocalMatch(local_match.to_ir()?), + ast::Exp::LocalComatch(local_comatch) => ir::Exp::LocalComatch(local_comatch.to_ir()?), + ast::Exp::Hole(hole) => hole.to_ir()?, + }; + + Ok(out) + } +} + +impl ToIR for ast::Variable { + type Target = ir::Variable; + + fn to_ir(&self) -> Result { + let ast::Variable { name, .. } = self; + + Ok(ir::Variable { name: name.to_string() }) + } +} + +impl ToIR for ast::Call { + type Target = ir::Call; + + fn to_ir(&self) -> Result { + let ast::Call { name, args, .. } = self; + + let args = args + .args + .iter() + .filter(|arg| !arg.erased()) + .map(|arg| arg.exp()) + .map(|arg| arg.to_ir()) + .collect::>()?; + + Ok(ir::Call { name: name.to_string(), module_uri: name.uri.clone(), args }) + } +} + +impl ToIR for ast::DotCall { + type Target = ir::DotCall; + + fn to_ir(&self) -> Result { + let ast::DotCall { exp, name, args, .. } = self; + + let args = args + .args + .iter() + .filter(|arg| !arg.erased()) + .map(|arg| arg.exp()) + .map(|arg| arg.to_ir()) + .collect::>()?; + + let exp = Box::new(exp.to_ir()?); + + Ok(ir::DotCall { exp, module_uri: name.uri.clone(), name: name.to_string(), args }) + } +} + +impl ToIR for ast::LocalMatch { + type Target = ir::LocalMatch; + + fn to_ir(&self) -> Result { + let ast::LocalMatch { on_exp, cases, .. } = self; + + let on_exp = Box::new(on_exp.to_ir()?); + let cases = cases.to_ir()?; + + Ok(ir::LocalMatch { on_exp, cases }) + } +} + +impl ToIR for ast::LocalComatch { + type Target = ir::LocalComatch; + + fn to_ir(&self) -> Result { + let LocalComatch { cases, .. } = self; + + let cases = cases.to_ir()?; + + Ok(ir::LocalComatch { cases }) + } +} + +impl ToIR for ast::Hole { + type Target = ir::Exp; + + fn to_ir(&self) -> Result { + let ast::Hole { kind, solution, .. } = self; + + let res = + match kind { + ast::MetaVarKind::MustSolve | ast::MetaVarKind::Inserted => match solution { + Some(solution) => solution.to_ir()?, + None => return Err(BackendError::Impossible( + "Encountered hole without solution that must be solved during typechecking" + .to_owned(), + )), + }, + ast::MetaVarKind::CanSolve => { + ir::Exp::Panic(ir::Panic { message: "not yet implemented".to_owned() }) + } + }; + + Ok(res) + } +} + +impl ToIR for ast::Case { + type Target = ir::Case; + + fn to_ir(&self) -> Result { + let ast::Case { pattern, body, .. } = self; + let ast::Pattern { is_copattern, params, name } = pattern; + + let params = params + .params + .iter() + .filter(|param| !param.erased) + .map(|param| param.name.to_string()) + .collect::>(); + + let pattern = ir::Pattern { + is_copattern: *is_copattern, + name: name.to_string(), + module_uri: name.uri.clone(), + params, + }; + + let body = match body { + Some(body) => Some(Box::new(body.to_ir()?)), + None => None, + }; + + Ok(ir::Case { pattern, body }) + } +} diff --git a/lang/backend/src/ast2ir/mod.rs b/lang/backend/src/ast2ir/mod.rs new file mode 100644 index 000000000..c97c9a4ac --- /dev/null +++ b/lang/backend/src/ast2ir/mod.rs @@ -0,0 +1,3 @@ +pub mod decls; +pub mod exprs; +pub mod traits; diff --git a/lang/backend/src/ast2ir/traits.rs b/lang/backend/src/ast2ir/traits.rs new file mode 100644 index 000000000..ae466ce22 --- /dev/null +++ b/lang/backend/src/ast2ir/traits.rs @@ -0,0 +1,26 @@ +use crate::result::BackendError; + +pub trait ToIR { + type Target; + + fn to_ir(&self) -> Result; +} + +impl ToIR for Vec { + type Target = Vec; + + fn to_ir(&self) -> Result { + self.iter().map(|x| x.to_ir()).collect() + } +} + +impl ToIR for Option { + type Target = Option; + + fn to_ir(&self) -> Result { + match self { + Some(x) => Ok(Some(x.to_ir()?)), + None => Ok(None), + } + } +} diff --git a/lang/backend/src/ir/decls.rs b/lang/backend/src/ir/decls.rs index c6c67f7cd..f6773526c 100644 --- a/lang/backend/src/ir/decls.rs +++ b/lang/backend/src/ir/decls.rs @@ -47,10 +47,16 @@ impl Print for Module { // // - if use_decls.is_nil() { + let doc = if use_decls.is_nil() { decls } else { use_decls.append(alloc.line()).append(alloc.line()).append(decls) + }; + + if doc.is_nil() { + doc + } else { + doc.append(alloc.hardline()) } } } diff --git a/lang/backend/src/ir/exprs.rs b/lang/backend/src/ir/exprs.rs index 70b77eaff..6c66fa0d6 100644 --- a/lang/backend/src/ir/exprs.rs +++ b/lang/backend/src/ir/exprs.rs @@ -222,6 +222,10 @@ impl Print for Pattern { } pub fn print_params<'a>(params: &'a [String], alloc: &'a Alloc<'a>) -> Builder<'a> { + if params.is_empty() { + return alloc.nil(); + } + let mut doc = alloc.nil(); let mut first = true; @@ -260,6 +264,10 @@ pub fn print_cases<'a>(cases: &'a [Case], cfg: &PrintCfg, alloc: &'a Alloc<'a>) } fn print_args<'a>(args: &'a [Exp], cfg: &PrintCfg, alloc: &'a Alloc<'a>) -> Builder<'a> { + if args.is_empty() { + return alloc.nil(); + } + let mut doc = alloc.nil(); let mut first = true; diff --git a/lang/backend/src/lib.rs b/lang/backend/src/lib.rs index a22196e51..e1731d947 100644 --- a/lang/backend/src/lib.rs +++ b/lang/backend/src/lib.rs @@ -1,2 +1,3 @@ +pub mod ast2ir; pub mod ir; pub mod result;