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",
]
[[package]]
name = "codegen"
version = "0.1.0"
dependencies = [
"hir",
]
[[package]]
name = "const-random"
version = "0.1.13"
@ -140,6 +147,7 @@ dependencies = [
"ariadne",
"chumsky",
"clap",
"codegen",
"hir",
"lexer",
"parser",

View file

@ -4,4 +4,5 @@ members = [
"crates/lexer",
"crates/parser",
"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;
#[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)]
pub enum IRKind {
@ -41,9 +41,21 @@ 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: 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!() }
}
}
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), Float(String), Boolean(bool),
Int(i64), Boolean(bool),
String(String), Identifier(String),
// Operators
@ -36,7 +36,6 @@ 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),
@ -66,11 +65,6 @@ 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())
@ -112,7 +106,6 @@ 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,5 +9,6 @@ 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,10 +1,12 @@
use std::fs;
use std::{fs, io::Write};
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};
@ -19,14 +21,17 @@ fn main() {
input: file_name,
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");
// 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())))
@ -57,7 +62,7 @@ fn main() {
))
.with_color(Color::Red)
),
chumsky::error::SimpleReason::Unexpected => report
.with_message(format!(
"{}, expected {}",
@ -94,15 +99,30 @@ 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.");
// Print the HIR.
println!("{:#?}", ir);
// 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."));
},
None => {
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 {
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 +1,3 @@
let foo: int = 1;
let foo: int = 1;
let baz: bool = true;
let qux: string = "Hello, World";