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:
parent
1e20eb89c3
commit
dd8d73c51a
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -4,4 +4,5 @@ members = [
|
|||
"crates/lexer",
|
||||
"crates/parser",
|
||||
"crates/hir",
|
||||
"crates/codegen",
|
||||
]
|
8
crates/codegen/Cargo.toml
Normal file
8
crates/codegen/Cargo.toml
Normal 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
44
crates/codegen/src/cpp.rs
Normal 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!() },
|
||||
}
|
||||
}
|
||||
}
|
1
crates/codegen/src/lib.rs
Normal file
1
crates/codegen/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod cpp;
|
|
@ -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!() }
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
|
@ -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.");
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
let foo: int = 1;
|
||||
let foo: int = 1;
|
||||
let baz: bool = true;
|
||||
let qux: string = "Hello, World";
|
Loading…
Reference in a new issue