diff --git a/Makefile b/Makefile deleted file mode 100644 index e96d554..0000000 --- a/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# Build the libraries that are used by generated C code. -build_lib: - sudo mkdir -p /usr/include/hycron - sudo cp -r ./lib/* /usr/include/hycron \ No newline at end of file diff --git a/example/ex.hyc b/example/ex.hyc index 2c66f20..dd42636 100644 --- a/example/ex.hyc +++ b/example/ex.hyc @@ -1,12 +1,9 @@ let foo: int = 1; -let bar: string = "str"; -let baz: bool = true; -fun qux (lhs: int rhs: int) -> int = lhs + rhs; -fun quux () -> string = "Hi, World!\n"; -fun main () -> int = do - let msg: string = "Hello, World!\n"; - write(msg); - let qux_result: int = qux(34 35); - 0; -end; \ No newline at end of file +fun bar (baz: int) -> int = baz + 1; +fun qux (quux: int) -> int = do + let corge: int = quux + quux; + bar(corge); +end; + +print(qux(5)); \ No newline at end of file diff --git a/lib/stdbool.h b/lib/stdbool.h deleted file mode 100644 index 1b3abdb..0000000 --- a/lib/stdbool.h +++ /dev/null @@ -1,3 +0,0 @@ -#define bool _Bool -#define true 1 -#define false 0 \ No newline at end of file diff --git a/src/back/c.rs b/src/back/c.rs deleted file mode 100644 index 7297bb9..0000000 --- a/src/back/c.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::fmt::Display; - -use crate::middle::ir::{IR, Value}; - -#[derive(Debug, Clone)] -pub struct Codegen { - pub emitted: String, -} - -const HEADER_INCLUDES: [&str; 3] = [ - "", - "", - "", -]; - -impl Codegen { - pub fn new() -> Self { - Self { - emitted: String::new(), - } - } - - fn emit(&mut self, s: T) { - self.emitted.push_str(&s.to_string()); - } - - pub fn gen(&mut self, irs: &[IR]) { - for header in HEADER_INCLUDES.iter() { - self.emit("#include "); - self.emit(header); - self.emit("\n"); - } - for ir in irs { - self.gen_ir(ir); - } - } - - fn gen_ir(&mut self, ir: &IR) { - match ir { - IR::Define { name, type_hint, value } => { - self.emit(format!("{} {} = ", type_hint, name)); - self.gen_ir(value); - self.emit(";\n"); - }, - IR::Fun { name, return_type_hint, args, body } => { - let args_str = args.iter().map(|(name, type_hint)| { - format!("{} {}", type_hint, name) - }).collect::>().join(", "); - self.emit(format!( - "{} {}({}) {{", - return_type_hint, - match name.as_str() { - "main" => "main".to_string(), - _ => format!("USER_DEFINED_{}", name), - }, - match name.as_str() { - "main" => format!("{}{}{}", "int ARGC, char **ARGV", if args.len() == 0 { "" } else { "," }, args_str.as_str()), - _ => args_str, - } - )); - - match &**body { - IR::Value { value } => { - self.emit("return "); - self.gen_value(&value); - self.emit(";"); - }, - IR::Do { body } => { - for (i, node) in body.iter().enumerate() { - if i == body.len() - 1 { - self.emit("return "); - self.gen_ir(node); - self.emit(";"); - } else { - self.gen_ir(node); - } - } - }, - IR::Binary { op, left, right } => { - self.emit("return "); - self.gen_ir(left); - self.emit(op); - self.gen_ir(right); - self.emit(";"); - }, - _ => todo!(), - } - self.emit("}\n"); - }, - IR::Call { name, args } => { - match name.as_str() { - "write" => { - self.emit("write(1, "); - self.gen_ir(&args[0]); - self.emit(", strlen("); - self.gen_ir(&args[0]); - self.emit("));"); - }, - _ => { - self.emit(format!("USER_DEFINED_{}(", name)); - for (i, arg) in args.iter().enumerate() { - if i != 0 { - self.emit(", "); - } - self.gen_ir(arg); - } - self.emit(")"); - } - } - }, - IR::Value { value } => { - self.gen_value(value); - }, - IR::Binary { op, left, right } => { - self.gen_ir(left); - self.emit(op); - self.gen_ir(right); - self.emit(";"); - }, - _ => todo!() - } - } - - fn gen_value(&mut self, value: &Value) { - match value { - Value::Int(i) => self.emit(format!("{}", i)), - Value::Float(f) => self.emit(format!("{}", f)), - Value::Double(d) => self.emit(format!("{}", d)), - Value::Bool(b) => self.emit(format!("{}", b)), - Value::String(s) => self.emit(format!("\"{}\"", s)), - Value::Ident(s) => self.emit(format!("{}", s)), - } - } - -} \ No newline at end of file diff --git a/src/back/js.rs b/src/back/js.rs new file mode 100644 index 0000000..faee345 --- /dev/null +++ b/src/back/js.rs @@ -0,0 +1,91 @@ +use crate::middle::ir::{IR, Value}; + +pub fn gen(irs: Vec) -> String { + let mut output = String::new(); + for ir in irs { + output.push_str(&gen_ir(&ir)); + } + output +} + +fn gen_ir(ir: &IR) -> String { + match ir { + IR::Define { name, type_hint: _, value } => { // type_hint is only used in type_checking i think + let value = gen_ir(value); + format!("const {} = {};", name, value) + }, + IR::Fun { name, return_type_hint: _, args, body } => { + let args = args + .iter() + .map(|(name, _)| format!("{}", name)) + .collect::>() + .join(", "); + + let body = match &**body { + IR::Value { value } => gen_value(value), + IR::Do { body } => { + let mut out = String::new(); + for (i, node) in body.iter().enumerate() { + if i == body.len() - 1 { + out.push_str(format!("return {};", gen_ir(node)).as_str()); + } else { + out.push_str(&gen_ir(node)); + } + } + out + }, + IR::Binary { op, left, right } => { + format!( + "return {} {} {};", + gen_ir(left), + op, + gen_ir(right) + ) + }, + _ => { println!("{:?}", body); todo!() } + }; + + format!( + "function {}({}) {{ {} }}", + name, + args, + body + ) + }, + IR::Call { name, args } => { + match name.as_str() { + "print" => { + let args = gen_ir(&args[0]); + format!("process.stdout.write({});", args.trim_end_matches(";")) + }, + _ => { + let args = args + .iter() + .map(|arg| gen_ir(arg)) + .collect::>() + .join(", "); + format!("{}({})", name, args) + }, + } + }, + IR::Value { value } => { + gen_value(value) + }, + IR::Binary { op, left, right } => { + let left = gen_ir(left); + let right = gen_ir(right); + format!("({} {} {});", left, op, right) + }, + _ => { println!("{:?}", ir); todo!() } + } +} + +fn gen_value(value: &Value) -> String { + match value { + Value::Int(i) => format!("{}", i), + Value::Float(f) => format!("{}", f), + Value::Bool(b) => format!("{}", b), + Value::String(s) => format!("\"{}\"", s), + Value::Ident(s) => format!("{}", s), + } +} \ No newline at end of file diff --git a/src/back/mod.rs b/src/back/mod.rs index fe2aa9b..cf65c45 100644 --- a/src/back/mod.rs +++ b/src/back/mod.rs @@ -1,2 +1,2 @@ -/// C compiler backend -pub mod c; \ No newline at end of file +/// Javascript compiler backend +pub mod js; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a7d854f..cddb76c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{fs, io::Write, time, process::Command}; +use std::{fs, io::Write, time}; use chumsky::{Parser, Stream}; use clap::Parser as ArgParser; @@ -47,49 +47,11 @@ fn main() { Some(ast) => { let start = time::Instant::now(); - let ir = ir::ast_to_ir(&ast); - let mut codegen = back::c::Codegen::new(); - codegen.gen(&ir); - - let out_file_name = file_name.file_stem().unwrap().to_str().unwrap().to_string() + ".c"; - let mut out_file = fs::File::create(&out_file_name).expect("Failed to create file"); - write!(out_file, "{}", codegen.emitted).expect("Failed to write to file"); - - let compile_elapsed = start.elapsed(); + let ir = ir::ast_to_ir(ast); + + let out = back::js::gen(ir); + println!("{}", out); - log(0, format!("Compiled successfully to {} in {}s", &out_file_name, compile_elapsed.as_secs_f64())); - log(0, "Running clang-format..."); - let mut clang_format_status = Command::new("clang-format") - .arg("-i") - .arg("-style=Microsoft") - .arg(&out_file_name) - .spawn() - .expect("Failed to run clang-format, make sure you have it installed"); - match clang_format_status.wait() { - Ok(status) => { - match status.success() { - true => log(0, "Successfully run clang-format"), - false => log(2, "Failed to run clang-format"), - } - }, - Err(e) => log(2, format!("Failed to wait on clang-format: {}", e)), - } - - log(0, "Running clang..."); - let mut clang_status = Command::new("clang") - .arg(&out_file_name) - .spawn() - .expect("Failed to run clang, make sure you have it installed"); - match clang_status.wait() { - Ok(status) => { - match status.success() { - true => log(0, "Successfully run clang"), - false => log(2, "Failed to run clang"), - } - }, - Err(e) => log(2, format!("Failed to wait on clang: {}", e)), - } - let all_elapsed = start.elapsed(); log(0, format!("Done in {}s", all_elapsed.as_secs_f64())); }, diff --git a/src/middle/ir.rs b/src/middle/ir.rs index fe50f9d..7fc6631 100644 --- a/src/middle/ir.rs +++ b/src/middle/ir.rs @@ -25,8 +25,7 @@ impl fmt::Display for TypeHint { #[derive(Debug, Clone)] pub enum Value { Int(i64), - Float(f32), - Double(f64), + Float(f64), Bool(bool), String(String), Ident(String), @@ -43,10 +42,10 @@ pub enum IR { Binary { op: String, left: Box, right: Box }, } -pub fn ast_to_ir(ast: &[Expr]) -> Vec { +pub fn ast_to_ir(ast: Vec) -> Vec { let mut ir = Vec::new(); for expr in ast { - ir.push(expr_to_ir(expr)); + ir.push(expr_to_ir(&expr)); } ir } @@ -86,8 +85,7 @@ pub fn expr_to_ir(expr: &Expr) -> IR { right: Box::new(expr_to_ir(right)), }, Expr::Int(value) => IR::Value { value: Value::Int(*value) }, - Expr::Float(value) => IR::Value { value: Value::Double(*value) }, // TODO: Actually use float - // Expr::Double(value) => IR::Value { value: Value::Double(*value) }, + Expr::Float(value) => IR::Value { value: Value::Float(*value) }, Expr::Bool(value) => IR::Value { value: Value::Bool(*value) }, Expr::String(value) => IR::Value { value: Value::String(value.clone()) }, Expr::Ident(name) => IR::Value { value: Value::Ident(name.clone()) }, @@ -99,7 +97,6 @@ fn get_typehint(from: &String) -> TypeHint { match from.as_str() { "int" => TypeHint::Int, "float" => TypeHint::Float, - "double" => TypeHint::Double, "bool" => TypeHint::Bool, "string" => TypeHint::String, _ => panic!("Unsupported type hint: {}", from)