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 foo: int = 1;
|
||||||
let bar: string = "str";
|
|
||||||
let baz: bool = true;
|
|
||||||
|
|
||||||
fun qux (lhs: int rhs: int) -> int = lhs + rhs;
|
fun bar (baz: int) -> int = baz + 1;
|
||||||
fun quux () -> string = "Hi, World!\n";
|
fun qux (quux: int) -> int = do
|
||||||
fun main () -> int = do
|
let corge: int = quux + quux;
|
||||||
let msg: string = "Hello, World!\n";
|
bar(corge);
|
||||||
write(msg);
|
end;
|
||||||
let qux_result: int = qux(34 35);
|
|
||||||
0;
|
print(qux(5));
|
||||||
end;
|
|
|
@ -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
|
/// Javascript compiler backend
|
||||||
pub mod c;
|
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 chumsky::{Parser, Stream};
|
||||||
use clap::Parser as ArgParser;
|
use clap::Parser as ArgParser;
|
||||||
|
@ -47,49 +47,11 @@ fn main() {
|
||||||
Some(ast) => {
|
Some(ast) => {
|
||||||
let start = time::Instant::now();
|
let start = time::Instant::now();
|
||||||
|
|
||||||
let ir = ir::ast_to_ir(&ast);
|
let ir = ir::ast_to_ir(ast);
|
||||||
let mut codegen = back::c::Codegen::new();
|
|
||||||
codegen.gen(&ir);
|
let out = back::js::gen(ir);
|
||||||
|
println!("{}", out);
|
||||||
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();
|
|
||||||
|
|
||||||
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();
|
let all_elapsed = start.elapsed();
|
||||||
log(0, format!("Done in {}s", all_elapsed.as_secs_f64()));
|
log(0, format!("Done in {}s", all_elapsed.as_secs_f64()));
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,8 +25,7 @@ impl fmt::Display for TypeHint {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
Float(f32),
|
Float(f64),
|
||||||
Double(f64),
|
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
String(String),
|
String(String),
|
||||||
Ident(String),
|
Ident(String),
|
||||||
|
@ -43,10 +42,10 @@ pub enum IR {
|
||||||
Binary { op: String, left: Box<Self>, right: Box<Self> },
|
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();
|
let mut ir = Vec::new();
|
||||||
for expr in ast {
|
for expr in ast {
|
||||||
ir.push(expr_to_ir(expr));
|
ir.push(expr_to_ir(&expr));
|
||||||
}
|
}
|
||||||
ir
|
ir
|
||||||
}
|
}
|
||||||
|
@ -86,8 +85,7 @@ pub fn expr_to_ir(expr: &Expr) -> IR {
|
||||||
right: Box::new(expr_to_ir(right)),
|
right: Box::new(expr_to_ir(right)),
|
||||||
},
|
},
|
||||||
Expr::Int(value) => IR::Value { value: Value::Int(*value) },
|
Expr::Int(value) => IR::Value { value: Value::Int(*value) },
|
||||||
Expr::Float(value) => IR::Value { value: Value::Double(*value) }, // TODO: Actually use float
|
Expr::Float(value) => IR::Value { value: Value::Float(*value) },
|
||||||
// Expr::Double(value) => IR::Value { value: Value::Double(*value) },
|
|
||||||
Expr::Bool(value) => IR::Value { value: Value::Bool(*value) },
|
Expr::Bool(value) => IR::Value { value: Value::Bool(*value) },
|
||||||
Expr::String(value) => IR::Value { value: Value::String(value.clone()) },
|
Expr::String(value) => IR::Value { value: Value::String(value.clone()) },
|
||||||
Expr::Ident(name) => IR::Value { value: Value::Ident(name.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() {
|
match from.as_str() {
|
||||||
"int" => TypeHint::Int,
|
"int" => TypeHint::Int,
|
||||||
"float" => TypeHint::Float,
|
"float" => TypeHint::Float,
|
||||||
"double" => TypeHint::Double,
|
|
||||||
"bool" => TypeHint::Bool,
|
"bool" => TypeHint::Bool,
|
||||||
"string" => TypeHint::String,
|
"string" => TypeHint::String,
|
||||||
_ => panic!("Unsupported type hint: {}", from)
|
_ => panic!("Unsupported type hint: {}", from)
|
||||||
|
|
Loading…
Reference in a new issue