2024-09-16 14:07:53 -07:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
import sys
|
|
|
|
|
import time
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
GENERATE = [
|
|
|
|
|
(
|
|
|
|
|
"Expr",
|
|
|
|
|
[
|
|
|
|
|
"Binary -> lhs: ExprP, op: Token, rhs: ExprP",
|
|
|
|
|
"Unary -> op: Token, expr: ExprP",
|
|
|
|
|
"Call -> expr: ExprP, args: Vec<ExprP>, rparen: Token",
|
|
|
|
|
"Get -> expr: ExprP, name: Token",
|
|
|
|
|
"Primary -> token: Token",
|
|
|
|
|
"Function -> lparen: Token, params: Vec<(Token <COMMA> Option<ExprP>)>, return_type: Option<ExprP>, body: Vec<StmtP>, rbrace: Token",
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"Stmt",
|
|
|
|
|
[
|
|
|
|
|
"Expr -> expr: ExprP",
|
|
|
|
|
"Assign -> lhs: Token, rhs: ExprP",
|
|
|
|
|
"Set -> expr: ExprP, name: Token, rhs: ExprP",
|
|
|
|
|
"Block -> lbrace: Token, stmts: Vec<StmtP>, rbrace: Token",
|
|
|
|
|
"Return -> return_kw: Token, expr: Option<ExprP>",
|
|
|
|
|
"If -> if_kw: Token, condition: ExprP, then_branch: BlockStmt, else_branch: Vec<StmtP>",
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FileWriter:
|
|
|
|
|
def __init__(self, path: Path) -> None:
|
|
|
|
|
self.path = path
|
|
|
|
|
self.fp = open(path, "w")
|
|
|
|
|
|
|
|
|
|
def write(self, text: str = "") -> None:
|
|
|
|
|
self.fp.write(text)
|
|
|
|
|
|
|
|
|
|
def line(self, line: str = "") -> None:
|
|
|
|
|
self.fp.write(line)
|
|
|
|
|
self.fp.write("\n")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def define_visitor(wr: FileWriter, base: str, type_lines: list[str]):
|
|
|
|
|
types = []
|
|
|
|
|
for line in type_lines:
|
|
|
|
|
parts = line.split("->")
|
|
|
|
|
members = [p.strip().replace("<COMMA>", ",") for p in parts[1].split(",")]
|
|
|
|
|
types += [(parts[0].strip(), members)]
|
|
|
|
|
|
|
|
|
|
wr.line(f"pub trait {base}Visitor " + "{")
|
|
|
|
|
|
|
|
|
|
for type, members in types:
|
|
|
|
|
wr.line(
|
2024-09-20 16:03:37 -07:00
|
|
|
f" fn visit_{type.lower()}_{base.lower()}(&mut self, {base.lower()}: &{type}{base}) -> Result<(), Box<dyn std::error::Error>>;"
|
2024-09-16 14:07:53 -07:00
|
|
|
)
|
|
|
|
|
wr.line("}")
|
|
|
|
|
wr.line()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def define_ast(wr: FileWriter, base: str, type_lines: list[str]):
|
|
|
|
|
types = []
|
|
|
|
|
for line in type_lines:
|
|
|
|
|
parts = line.split("->")
|
|
|
|
|
members = [p.strip().replace("<COMMA>", ",") for p in parts[1].split(",")]
|
|
|
|
|
types += [(parts[0].strip(), members)]
|
|
|
|
|
|
|
|
|
|
visitor = f"{base}Visitor"
|
|
|
|
|
|
|
|
|
|
wr.line(f"pub trait {base}: Debug + Any " + "{")
|
2024-09-20 16:03:37 -07:00
|
|
|
wr.line(
|
|
|
|
|
f" fn accept(&self, visitor: &mut dyn {visitor}) -> Result<(), Box<dyn std::error::Error>>;"
|
|
|
|
|
)
|
2024-09-16 14:07:53 -07:00
|
|
|
wr.line(" fn as_any(self: Box<Self>) -> Box<dyn Any>;")
|
|
|
|
|
wr.line(" fn as_any_ref(&self) -> &dyn Any;")
|
|
|
|
|
wr.line("}")
|
|
|
|
|
wr.line()
|
|
|
|
|
wr.line(f"pub type {base}P = Box<dyn {base} + 'static>;")
|
|
|
|
|
wr.line()
|
|
|
|
|
|
|
|
|
|
for type, members in types:
|
|
|
|
|
wr.line("#[derive(Debug)]")
|
|
|
|
|
wr.line(f"pub struct {type}{base} " + "{")
|
|
|
|
|
for member in members:
|
|
|
|
|
wr.line(f" pub {member},")
|
|
|
|
|
wr.line("}")
|
|
|
|
|
wr.line()
|
|
|
|
|
wr.line(f"impl {base} for {type}{base} " + "{")
|
2024-09-20 16:03:37 -07:00
|
|
|
wr.line(
|
2024-09-26 11:09:07 -07:00
|
|
|
f" fn accept(&self, visitor: &mut dyn {visitor}) -> Result<(), Box<dyn std::error::Error>> "
|
2024-09-20 16:03:37 -07:00
|
|
|
+ "{"
|
|
|
|
|
)
|
|
|
|
|
wr.line(f" visitor.visit_{type.lower()}_{base.lower()}(self)")
|
2024-09-16 14:07:53 -07:00
|
|
|
wr.line(" }")
|
|
|
|
|
wr.line()
|
|
|
|
|
wr.line(" fn as_any(self: Box<Self>) -> Box<dyn Any> {")
|
|
|
|
|
wr.line(" self")
|
|
|
|
|
wr.line(" }")
|
|
|
|
|
wr.line()
|
|
|
|
|
wr.line(" fn as_any_ref(&self) -> &dyn Any {")
|
|
|
|
|
wr.line(" self")
|
|
|
|
|
wr.line(" }")
|
|
|
|
|
wr.line("}")
|
|
|
|
|
wr.line()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
if len(sys.argv) == 1:
|
|
|
|
|
path = Path(__file__).parent / "../src/ast.rs"
|
|
|
|
|
else:
|
|
|
|
|
path = Path(sys.argv[1])
|
|
|
|
|
|
|
|
|
|
path = path.resolve()
|
|
|
|
|
print(f"Using {path}")
|
|
|
|
|
|
|
|
|
|
wr = FileWriter(path)
|
|
|
|
|
|
2024-09-20 16:03:37 -07:00
|
|
|
# File headers
|
2024-09-16 14:07:53 -07:00
|
|
|
wr.line(
|
|
|
|
|
"// This is an auto-generated file. Any changes made to this file may be overwritten."
|
|
|
|
|
)
|
|
|
|
|
wr.line("// This file was created at: " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
2024-09-20 16:03:37 -07:00
|
|
|
wr.line("#![allow(dead_code)]")
|
2024-09-16 14:07:53 -07:00
|
|
|
|
|
|
|
|
# Imports
|
|
|
|
|
wr.line("use std::fmt::Debug;")
|
|
|
|
|
wr.line("use std::any::Any;")
|
|
|
|
|
wr.line()
|
|
|
|
|
wr.line("use crate::token::Token;")
|
|
|
|
|
wr.line()
|
|
|
|
|
|
|
|
|
|
# Visitors
|
|
|
|
|
for base, types in GENERATE:
|
|
|
|
|
define_visitor(wr, base, types)
|
|
|
|
|
|
|
|
|
|
# AST
|
|
|
|
|
for base, types in GENERATE:
|
|
|
|
|
define_ast(wr, base, types)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|