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.
dccbe7c17c
...
1e20eb89c3
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -4,5 +4,4 @@ members = [
|
|||
"crates/lexer",
|
||||
"crates/parser",
|
||||
"crates/hir",
|
||||
"crates/codegen",
|
||||
]
|
|
@ -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
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "codegen"
|
||||
license = "MIT OR Apache-2.0"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
hir = { path = "../hir" }
|
|
@ -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!() },
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
pub mod cpp;
|
|
@ -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!() }
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
|
@ -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.");
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -1,4 +1 @@
|
|||
let foo: int = 1;
|
||||
let baz: bool = true;
|
||||
let qux: string = "Hello, World";
|
||||
write(qux);
|
Loading…
Reference in a new issue