AST - Replaced dumper

* Rewrote as a kind of "pretty" printer
  * It isn't actually pretty but it does restore Lox code from the AST.
This commit is contained in:
Emmanuel BENOîT 2023-01-08 15:25:27 +01:00
parent 728c7a3857
commit 1c5efe7e62
3 changed files with 332 additions and 204 deletions

View file

@ -147,205 +147,3 @@ pub enum ExprNode {
/// A get expression.
Get(GetExpr),
}
/* -------------------------------- *
* Dumper trait and implementations *
* -------------------------------- */
/// This trait should be implemented by nodes to allow AST dumps.
pub trait AstDumper {
/// Dump the node as a string.
fn dump(&self) -> String;
}
impl AstDumper for ProgramNode {
fn dump(&self) -> String {
self.0
.iter()
.map(|node| node.dump())
.collect::<Vec<String>>()
.join(" ")
}
}
/// Function formatting macro.
macro_rules! fmt_fun_decl {
($fs:literal, $fd:expr) => {
format!(
$fs,
$fd.name.lexeme,
$fd.params
.iter()
.map(|token| &token.lexeme as &str)
.collect::<Vec<&str>>()
.join(" "),
$fd.body
.iter()
.map(|stmt| stmt.dump())
.collect::<Vec<String>>()
.join(" ")
)
};
}
impl AstDumper for StmtNode {
fn dump(&self) -> String {
match self {
Self::VarDecl(name, Some(expr)) => format!("( var {} {} )", name.lexeme, expr.dump()),
Self::VarDecl(name, None) => format!("( var {} nil )", name.lexeme),
Self::FunDecl(fun_decl) => fmt_fun_decl!("( fun {} ({}) {} )", fun_decl),
Self::ClassDecl(decl) => format!(
"( class {} {} )",
decl.name.lexeme,
decl.methods
.iter()
.map(|fun_decl| fmt_fun_decl!("( {} ({}) {} )", fun_decl))
.collect::<Vec<String>>()
.join(" "),
),
Self::Expression(expr) => expr.dump(),
Self::Print(expr) => format!("(print {})", expr.dump()),
Self::Block(stmts) => format!(
"( {} )",
stmts
.iter()
.map(|s| s.dump())
.collect::<Vec<String>>()
.join(" ")
),
Self::If {
condition,
then_branch,
else_branch,
} => match else_branch {
None => format!("( if {} {} () )", condition.dump(), then_branch.dump()),
Some(stmt) => format!(
"( if {} {} {} )",
condition.dump(),
then_branch.dump(),
stmt.dump()
),
},
Self::Loop {
label,
condition,
body,
after_body,
} => {
let ltxt = if let Some(label) = label {
format!("@{} ", label.lexeme)
} else {
"".to_string()
};
let abtxt = if let Some(after_body) = after_body {
format!("{} ", after_body.dump())
} else {
"".to_string()
};
format!(
"( {}loop {} {} {})",
ltxt,
condition.dump(),
body.dump(),
abtxt
)
}
Self::LoopControl {
is_break,
loop_name,
} => {
let stmt = if *is_break { "break" } else { "continue" };
match loop_name {
Some(name) => format!("( {} {} )", stmt, name.lexeme),
None => format!("( {} )", stmt),
}
}
Self::Return { token: _, value } => match value {
Some(expr) => format!("( return {} )", expr.dump()),
None => "( return )".to_owned(),
},
}
}
}
impl AstDumper for ExprNode {
fn dump(&self) -> String {
match self {
Self::Assignment { name, value, id } => {
format!("{{#{}}}( = {} {} )", id, name.lexeme, value.dump())
}
Self::Logical {
left,
operator,
right,
} => format!("( {} {} {} )", operator.lexeme, left.dump(), right.dump()),
Self::Binary {
left,
operator,
right,
} => format!("( {} {} {} )", operator.lexeme, left.dump(), right.dump()),
Self::Unary { operator, right } => format!("( {} {} )", operator.lexeme, right.dump()),
Self::Grouping { expression } => format!("( {} )", expression.dump()),
Self::Variable { name, id } => format!("{{#{}}}{}", id, name.lexeme),
Self::Litteral { value } => {
if value.is_litteral() {
value.lexeme.clone()
} else {
panic!("Unexpected token type for token {:#?}", value)
}
}
ExprNode::Lambda { params, body } => {
format!(
"( fun ({}) {} )",
params
.iter()
.map(|token| &token.lexeme as &str)
.collect::<Vec<&str>>()
.join(" "),
body.iter()
.map(|stmt| stmt.dump())
.collect::<Vec<String>>()
.join(" ")
)
}
ExprNode::Call {
callee,
right_paren: _,
arguments,
} => {
let callee = callee.dump();
if arguments.is_empty() {
format!("( call {} )", callee)
} else {
format!(
"( call {} {} )",
callee,
arguments
.iter()
.map(|arg| arg.dump())
.collect::<Vec<String>>()
.join(" ")
)
}
}
ExprNode::Get(get_expr) => {
format!(
"( get {} {} )",
get_expr.instance.dump(),
get_expr.name.lexeme
)
}
}
}
}