Move code generation into a build script

master
Nick Krichevsky 2024-05-17 15:01:41 -04:00
parent 96ca870db0
commit 8cdfbd61a9
4 changed files with 23 additions and 90 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
/target
# Autogenerated
/src/ast.rs

View File

@ -4,10 +4,6 @@ version = "0.1.0"
edition = "2021"
default-run = "jlox-rust"
[[bin]]
name = "astgen"
path = "bin/astgen.rs"
[dependencies]
anyhow = "1.0.83"
itertools = "0.12.1"

View File

@ -2,26 +2,31 @@
use std::{
collections::BTreeMap,
fs::File,
io::{self, Write},
iter,
};
fn main() {
let mut stdout = io::stdout();
pub fn main() {
let mut ast_file = File::create("./src/ast.rs").expect("could not open src/ast.rs for writing");
do_ast_codegen(&mut ast_file);
}
fn do_ast_codegen<W: Write>(mut output: W) {
// Autogenerated file, clippy can leave us alone
writeln!(stdout, "#![allow(clippy::all)]").unwrap();
writeln!(output, "#![allow(clippy::all)]").unwrap();
writeln!(
stdout,
"// This file is auto-generated. Do not modify it directly, but rather use bin/astgen.rs.\n"
output,
"// This file is auto-generated. Do not modify it directly, but rather modify build.rs.\n"
)
.unwrap();
define_imports(&mut stdout, &["crate::lex::Token"]).expect("failed to define imports");
writeln!(stdout).unwrap();
define_imports(&mut output, &["crate::lex::Token"]).expect("failed to define imports");
writeln!(output).unwrap();
define_literals(
&mut stdout,
&mut output,
"LiteralValue",
&BTreeMap::from([
("Number", Some("f64")),
@ -32,7 +37,7 @@ fn main() {
]),
)
.expect("failed to generate literals");
writeln!(stdout).unwrap();
writeln!(output).unwrap();
let expr_types = BTreeMap::from([
(
@ -44,21 +49,21 @@ fn main() {
("Literal", "value: LiteralValue"),
]);
define_ast(&mut stdout, "Expr", &expr_types).expect("failed to generate ast values");
writeln!(stdout).unwrap();
define_visitor_trait(&mut stdout, "ExprVisitor", "Expr", &expr_types)
define_ast(&mut output, "Expr", &expr_types).expect("failed to generate ast values");
writeln!(output).unwrap();
define_visitor_trait(&mut output, "ExprVisitor", "Expr", &expr_types)
.expect("failed to generate visitor trait");
writeln!(stdout).unwrap();
writeln!(output).unwrap();
let statement_types = BTreeMap::from([
("Expression", "expression: Expr"),
("Print", "expression: Expr"),
]);
define_ast(&mut stdout, "Stmt", &statement_types).expect("failed to generate ast values");
writeln!(stdout).unwrap();
define_visitor_trait(&mut stdout, "StmtVisitor", "Stmt", &statement_types)
define_ast(&mut output, "Stmt", &statement_types).expect("failed to generate ast values");
writeln!(output).unwrap();
define_visitor_trait(&mut output, "StmtVisitor", "Stmt", &statement_types)
.expect("failed to generate visitor trait");
}

View File

@ -1,70 +0,0 @@
#![allow(clippy::all)]
// This file is auto-generated. Do not modify it directly, but rather use bin/astgen.rs.
use crate::lex::Token;
#[derive(Debug, Clone)]
pub enum LiteralValue {
False,
Nil,
Number(f64),
String(String),
True,
}
#[derive(Debug, Clone)]
pub enum Expr {
Binary {
left: Box<Expr>,
operator: Token,
right: Box<Expr>,
},
Grouping {
expr: Box<Expr>,
},
Literal {
value: LiteralValue,
},
Unary {
expr: Box<Expr>,
operator: Token,
},
}
pub trait ExprVisitor<T> {
fn visit_expr(&mut self, expr: &Expr) -> T {
match expr {
Expr::Binary { left, operator, right } => self.visit_binary(left.as_ref(), &operator, right.as_ref()),
Expr::Grouping { expr } => self.visit_grouping(expr.as_ref()),
Expr::Literal { value } => self.visit_literal(&value),
Expr::Unary { expr, operator } => self.visit_unary(expr.as_ref(), &operator),
}
}
fn visit_binary(&mut self, left: &Expr, operator: &Token, right: &Expr) -> T;
fn visit_grouping(&mut self, expr: &Expr) -> T;
fn visit_literal(&mut self, value: &LiteralValue) -> T;
fn visit_unary(&mut self, expr: &Expr, operator: &Token) -> T;
}
#[derive(Debug, Clone)]
pub enum Stmt {
Expression {
expression: Expr,
},
Print {
expression: Expr,
},
}
pub trait StmtVisitor<T> {
fn visit_stmt(&mut self, stmt: &Stmt) -> T {
match stmt {
Stmt::Expression { expression } => self.visit_expression(&expression),
Stmt::Print { expression } => self.visit_print(&expression),
}
}
fn visit_expression(&mut self, expression: &Expr) -> T;
fn visit_print(&mut self, expression: &Expr) -> T;
}