1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

Compare commits

..

No commits in common. "dccbe7c17cff2cf9bffb185e12d579a7920b0f76" and "1e20eb89c397915fbaa0e5ccac79eedfd849b709" have entirely different histories.

12 changed files with 24 additions and 131 deletions

8
Cargo.lock generated
View file

@ -88,13 +88,6 @@ dependencies = [
"syn",
]
[[package]]
name = "codegen"
version = "0.1.0"
dependencies = [
"hir",
]
[[package]]
name = "const-random"
version = "0.1.13"
@ -147,7 +140,6 @@ dependencies = [
"ariadne",
"chumsky",
"clap",
"codegen",
"hir",
"lexer",
"parser",

View file

@ -4,5 +4,4 @@ members = [
"crates/lexer",
"crates/parser",
"crates/hir",
"crates/codegen",
]

View file

@ -1,10 +1,10 @@
# Hades
Programming language that compiles to C++!
Programming language that compiles to JavaScript!
Note: Everything in this project can be changed at anytime! (I'm still finding out what work best for lots of thing) if you have an idea, feel free to create an issues about it, or even create a PR! (I'd be very happy)
# Prerequistie
- `clang++`(preferred) or any C++ compiler
- `node` or any JavaScript runner
- Rust (if you're going to build from source)
# TODO

View file

@ -1,8 +0,0 @@
[package]
name = "codegen"
license = "MIT OR Apache-2.0"
version = "0.1.0"
edition = "2021"
[dependencies]
hir = { path = "../hir" }

View file

@ -1,52 +0,0 @@
use std::fmt::Display;
use hir::{IR, IRKind, Value};
pub struct Codegen {
pub emitted: String,
}
impl Codegen {
pub fn new() -> Self {
Self { emitted: String::new() }
}
fn emit<T: Display>(&mut self, t: T) {
self.emitted.push_str(&t.to_string());
}
pub fn gen(&mut self, irs: Vec<IR>) {
self.emit("#include <stdbool.h>\n");
self.emit("#include <iostream>\n");
self.emit("#include <string>\n");
self.emit("int main() {\n");
for ir in irs {
self.emit(&self.gen_ir(&ir.kind));
}
self.emit("}");
}
fn gen_ir(&self, ir: &IRKind) -> String {
match ir {
IRKind::Define { name, type_hint, value } => {
format!("{} {} = {};\n", type_hint, name, self.gen_ir(value))
},
IRKind::Call { name, args } => {
match name.as_str() {
"write" => { format!("std::cout << {};\n", self.gen_ir(&args[0])) },
"read" => { format!("std::cin >> {};\n", self.gen_ir(&args[0])) },
_ => format!("{}({});\n", name, args.iter().map(|arg| self.gen_ir(arg)).collect::<Vec<_>>().join(", ")),
}
},
IRKind::Value { value } => {
match value {
Value::Int(value) => format!("{}", value),
Value::Boolean(value) => format!("{}", value),
Value::String(value) => format!("\"{}\"", value),
Value::Ident(value) => format!("{}", value),
}
},
_ => { dbg!(ir); todo!() },
}
}
}

View file

@ -1 +0,0 @@
pub mod cpp;

View file

@ -2,7 +2,7 @@ use std::ops::Range;
use parser::Expr;
#[derive(Debug)]
pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) }
pub enum Value { Int(i64), Float(f64), Bool(bool), String(String), Ident(String) }
#[derive(Debug)]
pub enum IRKind {
@ -41,30 +41,9 @@ pub fn expr_to_ir(expr: &Expr) -> IRKind {
match expr {
Expr::Let { name, type_hint, value } => {
let value = expr_to_ir(&value.0);
IRKind::Define { name: name.clone(), type_hint: gen_type_hint(type_hint), value: Box::new(value) }
IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) }
},
Expr::Call { name, args } => {
let name = match &name.0 {
Expr::Identifier(s) => s.clone(),
_ => panic!("Expected identifier") // TODO: Remove panic and use error handling
};
let args = args.0.iter().map(|arg| expr_to_ir(&arg.0)).collect::<Vec<_>>();
IRKind::Call { name, args }
},
Expr::Int(value) => IRKind::Value { value: Value::Int(*value) },
Expr::Boolean(value) => IRKind::Value { value: Value::Boolean(*value) },
Expr::String(value) => IRKind::Value { value: Value::String(value.clone()) },
Expr::Identifier(value) => IRKind::Value { value: Value::Ident(value.clone()) },
_ => { dbg!(expr); todo!() }
}
}
fn gen_type_hint(type_hint: &str) -> String {
match type_hint {
"int" => "int".to_string(),
"bool" => "bool".to_string(),
"string" => "std::string".to_string(),
_ => { dbg!(type_hint); todo!() }
}
}

View file

@ -9,7 +9,7 @@ pub enum Token {
KwReturn,
// Literals
Int(i64), Boolean(bool),
Int(i64), Float(String), Boolean(bool),
String(String), Identifier(String),
// Operators
@ -36,6 +36,7 @@ impl std::fmt::Display for Token {
Token::KwReturn => write!(f, "return"),
Token::Int(i) => write!(f, "{}", i),
Token::Float(s) => write!(f, "{}", s),
Token::Boolean(b) => write!(f, "{}", b),
Token::String(s) => write!(f, "{}", s),
Token::Identifier(s) => write!(f, "{}", s),
@ -65,6 +66,11 @@ pub type Span = std::ops::Range<usize>;
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
let int = text::int(10)
.map(|s: String| Token::Int(s.parse().unwrap()));
let float = text::int(10)
.chain(just('.'))
.chain::<char, _, _>(text::digits(10))
.collect::<String>()
.map(Token::Float);
let string = just('"')
.ignore_then(filter(|c| *c != '"').repeated())
@ -106,6 +112,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
});
let token = int
.or(float)
.or(string)
.or(symbol)
.or(keyword)

View file

@ -9,6 +9,5 @@ clap = { version = "3.0.14", features = ["derive"] }
lexer = { path = "../lexer" }
parser = { path = "../parser" }
hir = { path = "../hir" }
codegen = { path = "../codegen" }
chumsky = "0.8.0"
ariadne = "0.1.5"

View file

@ -1,12 +1,10 @@
use std::{fs, io::Write};
use std::fs;
use clap::Parser as ArgParser;
use ariadne::{Report, ReportKind, Label, Source, Color, Fmt};
use lexer::lex;
use parser::parse;
use hir::ast_to_ir;
use codegen::cpp;
pub mod args;
use args::{Args, Options};
@ -21,17 +19,14 @@ fn main() {
input: file_name,
ast: _print_ast,
} => {
// Start timer
let start = std::time::Instant::now();
// Get file contents
// Get file contents.
let src = fs::read_to_string(&file_name).expect("Failed to read file");
// Lex the file
// Lex the file.
let (tokens, lex_error) = lex(src.clone());
let (ast, parse_error) = parse(tokens.unwrap(), src.chars().count());
// Report errors
// Report errors.
lex_error.into_iter()
.map(|e| e.map(|e| e.to_string()))
.chain(parse_error.into_iter().map(|e| e.map(|tok| tok.to_string())))
@ -99,30 +94,15 @@ fn main() {
};
report.finish().print(Source::from(&src)).unwrap();
}
); // End errors reporting
log(0, format!("Parsing took {}ms", start.elapsed().as_millis()));
});
match ast {
Some(ast) => {
// Convert the AST to HIR
// Convert the AST to HIR.
let ir = ast_to_ir(ast);
log(0, "Generated HIR.");
// Generate code
let mut codegen = cpp::Codegen::new();
codegen.gen(ir);
log(0, "Successfully generated code.");
// Write code to file
let mut file = fs::File::create("out.cpp").expect("Failed to create file");
file.write_all(codegen.emitted.as_bytes()).expect("Failed to write to file");
// End timer
let duration = start.elapsed().as_millis();
log(0, format!("Compilation took {}ms", duration));
log(0, format!("Wrote output to `out.cpp`. All done."));
// Print the HIR.
println!("{:#?}", ir);
},
None => {
log(2, "Failed to parse.");

View file

@ -43,6 +43,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
let literal = filter_map(|span, token| match token {
Token::Int(i) => Ok((Expr::Int(i), span)),
Token::Float(f) => Ok((Expr::Float(f.parse().unwrap()), span)),
Token::Boolean(b) => Ok((Expr::Boolean(b), span)),
Token::String(s) => Ok((Expr::String(s), span)),
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),

View file

@ -1,4 +1 @@
let foo: int = 1;
let baz: bool = true;
let qux: string = "Hello, World";
write(qux);