fuck it js backend

replace/7746dba3cc6b3860afe1faf69e86ed84ee46988d
Natapat Samutpong 2022-02-26 20:44:06 +07:00
parent b2dc49beac
commit d10f3e3f38
8 changed files with 109 additions and 204 deletions

View File

@ -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

View File

@ -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;
fun bar (baz: int) -> int = baz + 1;
fun qux (quux: int) -> int = do
let corge: int = quux + quux;
bar(corge);
end;
print(qux(5));

View File

@ -1,3 +0,0 @@
#define bool _Bool
#define true 1
#define false 0

View File

@ -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] = [
"<unistd.h>",
"<string.h>",
"<hycron/stdbool.h>",
];
impl Codegen {
pub fn new() -> Self {
Self {
emitted: String::new(),
}
}
fn emit<T: Display>(&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::<Vec<_>>().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)),
}
}
}

91
src/back/js.rs Normal file
View File

@ -0,0 +1,91 @@
use crate::middle::ir::{IR, Value};
pub fn gen(irs: Vec<IR>) -> 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::<Vec<_>>()
.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::<Vec<_>>()
.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),
}
}

View File

@ -1,2 +1,2 @@
/// C compiler backend
pub mod c;
/// Javascript compiler backend
pub mod js;

View File

@ -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()));
},

View File

@ -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<Self>, right: Box<Self> },
}
pub fn ast_to_ir(ast: &[Expr]) -> Vec<IR> {
pub fn ast_to_ir(ast: Vec<Expr>) -> Vec<IR> {
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)