diff --git a/Cargo.lock b/Cargo.lock index bbf2270..1b35d7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -419,6 +419,9 @@ name = "ir" version = "0.1.0" dependencies = [ "chumsky", + "serde", + "serde-lexpr", + "serde_derive", "syntax", "typing", ] @@ -435,6 +438,33 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "lexpr" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a84de6a9df442363b08f5dbf0cd5b92edc70097b89c4ce4bfea4679fe48bc67" +dependencies = [ + "itoa", + "lexpr-macros", + "ryu", +] + +[[package]] +name = "lexpr-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b5cb8bb985c81a8ac1a0f8b5c4865214f574ddd64397ef7a99c236e21f35bb" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "libc" version = "0.2.142" @@ -540,6 +570,39 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" + +[[package]] +name = "serde-lexpr" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4cda13396159f59e7946118cdac0beadeecfb7cf76b197f4147e546f4ead6f" +dependencies = [ + "lexpr", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "slice-group-by" version = "0.3.1" diff --git a/bin/src/main.rs b/bin/src/main.rs index 1c55519..5277c39 100644 --- a/bin/src/main.rs +++ b/bin/src/main.rs @@ -1,9 +1,9 @@ use ariadne::{sources, Color, Label, Report, ReportKind}; use chumsky::{Parser, prelude::Input}; +use ir::lower_expr; use syntax::parser::{lexer, exprs_parser}; use typing::infer::{infer_exprs, InferErrorKind}; -use ir::Lowerer; pub mod args; @@ -59,9 +59,8 @@ fn main() { return; } // ast.iter().for_each(|node| println!("{:?}", node.0)); - let mut l = Lowerer::new(); - let irs = l.lower_texprs(ast); - irs.iter().for_each(|ir| println!("{:?}", ir)); + let irs = ast.into_iter().map(|node| lower_expr(node.0)).collect::>(); + irs.iter().for_each(|ir| println!("{}", ir)); } }; diff --git a/ir/Cargo.toml b/ir/Cargo.toml index 6a69a64..5b0be5f 100644 --- a/ir/Cargo.toml +++ b/ir/Cargo.toml @@ -5,5 +5,8 @@ edition = "2021" [dependencies] chumsky = "1.0.0-alpha.3" +serde = "1.0.164" +serde-lexpr = "0.1.3" +serde_derive = "1.0.164" syntax = { path = "../syntax" } -typing = { path = "../typing" } \ No newline at end of file +typing = { path = "../typing" } diff --git a/ir/src/lib.rs b/ir/src/lib.rs index 40861b2..92fde2b 100644 --- a/ir/src/lib.rs +++ b/ir/src/lib.rs @@ -1,115 +1,149 @@ -use chumsky::span::SimpleSpan; -use syntax::expr::{Lit, UnaryOp, BinaryOp}; use typing::typed::TExpr; +use syntax::expr::{Lit as ExprLit, UnaryOp, BinaryOp}; + +use std::fmt::{self, Display, Formatter, Result as FmtResult}; #[derive(Clone, Debug)] -pub enum IExpr<'src> { - BoolAnd, - IntPush(i64), - IntAdd, - IntSub, - IntRem, - IntEq, - StrPush(&'src str), - Branch(Vec, Vec), - VarLoad(&'src str), - VarStore(&'src str), - FnPush(Vec), - Call, - Ret, +pub enum Lit<'src> { + Unit, + Bool(bool), + Int(i64), + Str(&'src str), } -#[derive(Clone, Debug)] -pub struct Lowerer { -} - -impl Lowerer { - pub fn new() -> Self { - Self {} - } - - fn lower_texpr<'a>(self: &mut Self, e: TExpr<'a>) -> Vec> { - use IExpr::*; - match e { - TExpr::Lit(l) => match l { - Lit::Unit => vec![], - Lit::Bool(_) => todo!(), - Lit::Int(n) => vec![IntPush(n)], - Lit::Str(s) => vec![StrPush(s)], - } - TExpr::Ident(s) => vec![VarLoad(s)], - TExpr::Unary { op, expr, .. } => { - let mut expr = self.lower_texpr(*expr.0); - expr.push(match op { - UnaryOp::Neg => IntSub, - UnaryOp::Not => todo!(), - }); - expr - } - TExpr::Binary { op, lhs, rhs, .. } if op == BinaryOp::Pipe => { - println!("{lhs:?}"); - println!("{rhs:?}"); - todo!() - } - TExpr::Binary { op, lhs, rhs, .. } => { - let mut lhs = self.lower_texpr(*lhs.0); - let mut rhs = self.lower_texpr(*rhs.0); - lhs.append(&mut rhs); - lhs.push(match op { - BinaryOp::Add => IExpr::IntAdd, - BinaryOp::Sub => IExpr::IntSub, - BinaryOp::Mul => todo!(), - BinaryOp::Div => todo!(), - BinaryOp::Rem => IExpr::IntRem, - BinaryOp::Eq => IExpr::IntEq, - BinaryOp::Ne => todo!(), - BinaryOp::Lt => todo!(), - BinaryOp::Gt => todo!(), - BinaryOp::Le => todo!(), - BinaryOp::Ge => todo!(), - BinaryOp::And => IExpr::BoolAnd, - BinaryOp::Or => todo!(), - BinaryOp::Pipe => unreachable!(), - }); - lhs - } - - TExpr::Lambda { body, .. } => { - let mut es = self.lower_texpr(*body.0); - es.push(IExpr::Ret); - vec![IExpr::FnPush(es)] - }, - TExpr::Call { func, args } => { - let mut es: Vec = args.into_iter() - .flat_map(|(e, _)| self.lower_texpr(e)) - .collect(); - es.append(&mut self.lower_texpr(*func.0)); - es.push(IExpr::Call); - es - }, - - TExpr::If { cond, t, f, .. } => { - let mut es = self.lower_texpr(*cond.0); - es.push(IExpr::Branch( - self.lower_texpr(*t.0), - self.lower_texpr(*f.0), - )); - es - }, - TExpr::Define { name, value, .. } => { - let mut es = self.lower_texpr(*value.0); - es.push(IExpr::VarStore(name)); - es - }, - - - e => unimplemented!("{:?}", e) +impl Display for Lit<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Lit::Unit => write!(f, "()"), + Lit::Bool(b) => write!(f, "{}", b), + Lit::Int(i) => write!(f, "{}", i), + Lit::Str(s) => write!(f, "\"{}\"", s), } } +} - pub fn lower_texprs<'a>(self: &mut Self, e: Vec<(TExpr<'a>, SimpleSpan)>) -> Vec> { - e.into_iter() - .flat_map(|(e, _)| self.lower_texpr(e)) - .collect() +#[derive(Clone, Debug)] +pub enum Expr<'src> { + Lit(Lit<'src>), + // v0 + Var(&'src str), + // f(v0, v1, ...) + Call(Vec), +} + +impl Display for Expr<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Expr::Lit(l) => write!(f, "{}", l), + Expr::Var(s) => write!(f, "{}", s), + Expr::Call(v) => { + write!(f, "(")?; + for (i, e) in v.iter().enumerate() { + if i != 0 { + write!(f, " ")?; + } + write!(f, "{}", e)?; + } + write!(f, ")") + } + } + } +} + +macro_rules! unbox { + ($e:expr) => { + *(($e).0) + }; +} + +macro_rules! str { + ($e:expr) => { + Expr::Lit(Lit::Str($e)) + }; +} + +macro_rules! var { + ($e:expr) => { + Expr::Var($e) + }; +} + +macro_rules! call { + ($e:expr) => { + Expr::Call($e) + }; +} + +pub fn lower_lit(lit: ExprLit) -> Lit { + match lit { + ExprLit::Unit => Lit::Unit, + ExprLit::Bool(b) => Lit::Bool(b), + ExprLit::Int(i) => Lit::Int(i), + ExprLit::Str(s) => Lit::Str(s), + } +} + +pub fn lower_expr(e: TExpr) -> Expr { + match e { + TExpr::Lit(l) => Expr::Lit(lower_lit(l)), + TExpr::Ident(s) => var!(s), + TExpr::Unary { op, expr, .. } => { + let expr = lower_expr(unbox!(expr)); + match op { + UnaryOp::Neg => call!(vec![var!("neg"), expr]), + UnaryOp::Not => call!(vec![var!("not"), expr]), + } + } + TExpr::Binary { op: BinaryOp::Pipe, lhs, rhs, .. } => { + let lhs = lower_expr(unbox!(lhs)); // arguments + let rhs = lower_expr(unbox!(rhs)); // function + call!(vec![rhs, lhs]) + } + TExpr::Binary { op, lhs, rhs, .. } => { + let lhs = lower_expr(unbox!(lhs)); + let rhs = lower_expr(unbox!(rhs)); + match op { + BinaryOp::Add => call!(vec![var!("+"), lhs, rhs]), + BinaryOp::Sub => call!(vec![var!("-"), lhs, rhs]), + BinaryOp::Mul => call!(vec![var!("*"), lhs, rhs]), + BinaryOp::Div => call!(vec![var!("/"), lhs, rhs]), + BinaryOp::Rem => call!(vec![var!("%"), lhs, rhs]), + BinaryOp::Eq => call!(vec![var!("=="), lhs, rhs]), + BinaryOp::Ne => call!(vec![var!("!="), lhs, rhs]), + BinaryOp::Lt => call!(vec![var!("<"), lhs, rhs]), + BinaryOp::Le => call!(vec![var!("<="), lhs, rhs]), + BinaryOp::Gt => call!(vec![var!(">"), lhs, rhs]), + BinaryOp::Ge => call!(vec![var!(">="), lhs, rhs]), + BinaryOp::And => call!(vec![var!("&&"), lhs, rhs]), + BinaryOp::Or => call!(vec![var!("||"), lhs, rhs]), + BinaryOp::Pipe => unreachable!("pipe operator is handled separately"), + } + } + TExpr::Lambda { params, body, .. } => { + let body = lower_expr(unbox!(body)); + call!(vec![ + var!("lambda"), + call!(params.into_iter().map(|(p, _)| var!(p)).collect()), + body, + ]) + } + TExpr::Call { func, args } => { + let func = lower_expr(unbox!(func)); + let args = args.into_iter() + .map(|(a, _)| lower_expr(a)) + .collect::>(); + call!(vec![func].into_iter().chain(args).collect()) + } + TExpr::If { cond, t, f, br_ty } => todo!(), + TExpr::Let { name, value, body, .. } => { + let value = lower_expr(unbox!(value)); + let body = lower_expr(unbox!(body)); + call!(vec![var!("let"), str!(name), value, body]) + } + TExpr::Define { name, value, .. } => { + let value = lower_expr(unbox!(value)); + call!(vec![var!("define"), str!(name), value]) + } + TExpr::Block { exprs, void, ret_ty } => todo!(), } } \ No newline at end of file diff --git a/simple.hlm b/simple.hlm index ebfb7d8..6df56a2 100644 --- a/simple.hlm +++ b/simple.hlm @@ -1,2 +1,5 @@ -let f = fun (x Int, y) Int -> x + y; -f(34, 35); \ No newline at end of file +let add = fun (x Int, y Int) Int -> x + y; +let succ = fun (x) -> x + 1; + +add(33, 34) +|> fun (x) -> succ(x) \ No newline at end of file