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

codegen (c++), removed float for now

This commit is contained in:
Natapat Samutpong 2022-03-07 15:15:43 +07:00
parent 1e20eb89c3
commit dd8d73c51a
11 changed files with 111 additions and 22 deletions

8
Cargo.lock generated
View file

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

View file

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

View file

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

44
crates/codegen/src/cpp.rs Normal file
View file

@ -0,0 +1,44 @@
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 <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::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

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

View file

@ -2,7 +2,7 @@ use std::ops::Range;
use parser::Expr; use parser::Expr;
#[derive(Debug)] #[derive(Debug)]
pub enum Value { Int(i64), Float(f64), Bool(bool), String(String), Ident(String) } pub enum Value { Int(i64), Boolean(bool), String(String), Ident(String) }
#[derive(Debug)] #[derive(Debug)]
pub enum IRKind { pub enum IRKind {
@ -41,9 +41,21 @@ pub fn expr_to_ir(expr: &Expr) -> IRKind {
match expr { match expr {
Expr::Let { name, type_hint, value } => { Expr::Let { name, type_hint, value } => {
let value = expr_to_ir(&value.0); let value = expr_to_ir(&value.0);
IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) } IRKind::Define { name: name.clone(), type_hint: gen_type_hint(type_hint), value: Box::new(value) }
}, },
Expr::Int(value) => IRKind::Value { value: Value::Int(*value) },
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()) },
_ => { dbg!(expr); todo!() } _ => { 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, KwReturn,
// Literals // Literals
Int(i64), Float(String), Boolean(bool), Int(i64), Boolean(bool),
String(String), Identifier(String), String(String), Identifier(String),
// Operators // Operators
@ -36,7 +36,6 @@ impl std::fmt::Display for Token {
Token::KwReturn => write!(f, "return"), Token::KwReturn => write!(f, "return"),
Token::Int(i) => write!(f, "{}", i), Token::Int(i) => write!(f, "{}", i),
Token::Float(s) => write!(f, "{}", s),
Token::Boolean(b) => write!(f, "{}", b), Token::Boolean(b) => write!(f, "{}", b),
Token::String(s) => write!(f, "{}", s), Token::String(s) => write!(f, "{}", s),
Token::Identifier(s) => write!(f, "{}", s), Token::Identifier(s) => write!(f, "{}", s),
@ -66,11 +65,6 @@ pub type Span = std::ops::Range<usize>;
pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> { pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
let int = text::int(10) let int = text::int(10)
.map(|s: String| Token::Int(s.parse().unwrap())); .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('"') let string = just('"')
.ignore_then(filter(|c| *c != '"').repeated()) .ignore_then(filter(|c| *c != '"').repeated())
@ -112,7 +106,6 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
}); });
let token = int let token = int
.or(float)
.or(string) .or(string)
.or(symbol) .or(symbol)
.or(keyword) .or(keyword)

View file

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

View file

@ -1,10 +1,12 @@
use std::fs; use std::{fs, io::Write};
use clap::Parser as ArgParser; use clap::Parser as ArgParser;
use ariadne::{Report, ReportKind, Label, Source, Color, Fmt}; use ariadne::{Report, ReportKind, Label, Source, Color, Fmt};
use lexer::lex; use lexer::lex;
use parser::parse; use parser::parse;
use hir::ast_to_ir; use hir::ast_to_ir;
use codegen::cpp;
pub mod args; pub mod args;
use args::{Args, Options}; use args::{Args, Options};
@ -19,14 +21,17 @@ fn main() {
input: file_name, input: file_name,
ast: _print_ast, ast: _print_ast,
} => { } => {
// Get file contents. // Start timer
let start = std::time::Instant::now();
// Get file contents
let src = fs::read_to_string(&file_name).expect("Failed to read file"); 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 (tokens, lex_error) = lex(src.clone());
let (ast, parse_error) = parse(tokens.unwrap(), src.chars().count()); let (ast, parse_error) = parse(tokens.unwrap(), src.chars().count());
// Report errors. // Report errors
lex_error.into_iter() lex_error.into_iter()
.map(|e| e.map(|e| e.to_string())) .map(|e| e.map(|e| e.to_string()))
.chain(parse_error.into_iter().map(|e| e.map(|tok| tok.to_string()))) .chain(parse_error.into_iter().map(|e| e.map(|tok| tok.to_string())))
@ -57,7 +62,7 @@ fn main() {
)) ))
.with_color(Color::Red) .with_color(Color::Red)
), ),
chumsky::error::SimpleReason::Unexpected => report chumsky::error::SimpleReason::Unexpected => report
.with_message(format!( .with_message(format!(
"{}, expected {}", "{}, expected {}",
@ -94,15 +99,30 @@ fn main() {
}; };
report.finish().print(Source::from(&src)).unwrap(); report.finish().print(Source::from(&src)).unwrap();
}); }
); // End errors reporting
log(0, format!("Parsing took {}ms", start.elapsed().as_millis()));
match ast { match ast {
Some(ast) => { Some(ast) => {
// Convert the AST to HIR. // Convert the AST to HIR
let ir = ast_to_ir(ast); 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.");
// Print the HIR. // Write code to file
println!("{:#?}", ir); 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."));
}, },
None => { None => {
log(2, "Failed to parse."); log(2, "Failed to parse.");

View file

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

View file

@ -1 +1,3 @@
let foo: int = 1; let foo: int = 1;
let baz: bool = true;
let qux: string = "Hello, World";