Move code generation into a build script
parent
96ca870db0
commit
8cdfbd61a9
|
@ -1 +1,3 @@
|
|||
/target
|
||||
# Autogenerated
|
||||
/src/ast.rs
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
70
src/ast.rs
70
src/ast.rs
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue