diff --git a/example/ex.hyc b/example/ex.hyc index 7bf81af..6d64d19 100644 --- a/example/ex.hyc +++ b/example/ex.hyc @@ -1,12 +1,9 @@ -let foo = if 1 == 1 then - 5 - else - 10 - end; +let foo = 1; +let bar = true; +let baz = "qux"; -do - print(1); -end; - -fun bar a b = a + b; -let baz = bar(34 35); \ No newline at end of file +if (bar == true) then + print(baz); +else + print("quux"); +end; \ No newline at end of file diff --git a/src/back/c.rs b/src/back/c.rs new file mode 100644 index 0000000..2c115ad --- /dev/null +++ b/src/back/c.rs @@ -0,0 +1,76 @@ +use crate::front::parse::Expr; + +pub struct Codegen { + pub emitted: String, +} + +impl Codegen { + pub fn new() -> Self { + Self { + emitted: String::new(), + } + } + + fn emit(&mut self, s: String) { + self.emitted.push_str(s.as_str()); + } + + pub fn gen(&mut self, exprs: &[Expr]) { + self.emit("#include \n#include \nint main() {\n".to_string()); + for expr in exprs { + self.gen_expr(expr); + } + self.emit("return 0;\n}\n".to_string()); + } + + fn gen_expr(&mut self, expr: &Expr) { + match expr { + Expr::Let { name, value } => { + match &**value { + Expr::Int(i) => self.emit(format!("int {} = {};\n", name, i)), + Expr::Float(f) => self.emit(format!("double {} = {};\n", name, f)), + Expr::Boolean(b) => self.emit(format!("bool {} = {};\n", name, b)), + Expr::String(s) => self.emit(format!("char *{} = \"{}\";\n", name, s)), + _ => todo!(), + } + }, + Expr::Call { name, args } => { + match &**name { + Expr::Ident(func) => { + match func.as_str() { + "print" => { + self.emit(format!("printf({});\n", match &args[0] { + Expr::String(s) => format!("\"{}\"", s), + Expr::Ident(s) => s.to_string(), + _ => todo!(), + })); + }, + _ => todo!(), + } + }, + _ => todo!(), + } + }, + Expr::If { cond, then, else_ } => { + self.emit("if ".to_string()); + self.gen_expr(&cond); + self.emit(" {\n".to_string()); + self.gen_expr(&then); + self.emit("} else {\n".to_string()); + self.gen_expr(&else_); + self.emit("}\n".to_string()); + }, + Expr::Binary { left, op, right } => { + self.emit("(".to_string()); + self.gen_expr(&left); + self.emit(format!(" {} ", op.to_string())); + self.gen_expr(&right); + self.emit(")".to_string()); + }, + Expr::Ident(s) => self.emit(s.to_string()), + Expr::Boolean(b) => self.emit(format!("{}", b)), + _ => { println!("{:?}", expr); todo!() }, + } + } + +} \ No newline at end of file diff --git a/src/back/mod.rs b/src/back/mod.rs new file mode 100644 index 0000000..fe2aa9b --- /dev/null +++ b/src/back/mod.rs @@ -0,0 +1,2 @@ +/// C compiler backend +pub mod c; \ No newline at end of file diff --git a/src/front/parse.rs b/src/front/parse.rs index 60d2f51..b9ab89b 100644 --- a/src/front/parse.rs +++ b/src/front/parse.rs @@ -26,6 +26,7 @@ pub fn lexer() -> impl Parser, Error = Simple> { let int = text::int(10) .map(|s: String| Token::Int(s.parse().unwrap())); + // TODO: this is not working somehow let float = text::int(10) .then_ignore(just('.')) .chain::(text::digits(10)) @@ -315,7 +316,7 @@ impl Expr { Self::String(x) => out.push_str(&format!("\"{}\"", x)), Self::Ident(x) => out.push_str(&x), - Self::Unary{ op, expr } => out.push_str(&format!("({} {})", op, expr.to_sexpr())), + Self::Unary{ op, expr } => out.push_str(&format!("({} {})", op, expr.to_sexpr())), Self::Binary{ op, left, right } => out.push_str( &format!("({} {} {})", op, left.to_sexpr(), right.to_sexpr()) ), @@ -328,7 +329,7 @@ impl Expr { &format!("(fun {} ({})\n {})", name, args.join(" "), body.to_sexpr())), Self::If { cond, then, else_ } => out.push_str( - &format!("(if {}\n {}\n {})", cond.to_sexpr(), then.to_sexpr(), else_.to_sexpr())), + &format!("(if {} {} {})", cond.to_sexpr(), then.to_sexpr(), else_.to_sexpr())), Self::Do { body } => out.push_str( &format!("(do {})", body.iter().map(|x| x.to_sexpr()).collect::>().join(" "))), diff --git a/src/main.rs b/src/main.rs index 289cc84..7b65804 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,10 @@ use args::{Args, Options}; pub mod front; use front::parse::{lexer, parser}; +/// Back-end of the language. +/// Contains code generator. +pub mod back; + fn main() { let args = Args::parse(); match args.options { @@ -24,7 +28,10 @@ fn main() { if parse_error.is_empty() { match ast { Some(ast) => { - println!("{}", ast.iter().map(|e| e.to_sexpr()).collect::>().join("\n\n")); + // println!("{}", ast.iter().map(|e| e.to_sexpr()).collect::>().join("\n\n")); + let mut codegen = back::c::Codegen::new(); + codegen.gen(&ast); + print!("{}", codegen.emitted); }, None => println!("no ast :("), };