mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
fuck it js backend
This commit is contained in:
parent
b2dc49beac
commit
d10f3e3f38
4
Makefile
4
Makefile
|
@ -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
|
|
@ -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));
|
|
@ -1,3 +0,0 @@
|
|||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
135
src/back/c.rs
135
src/back/c.rs
|
@ -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
91
src/back/js.rs
Normal 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),
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
/// C compiler backend
|
||||
pub mod c;
|
||||
/// Javascript compiler backend
|
||||
pub mod js;
|
48
src/main.rs
48
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()));
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue