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:
parent
728c7a3857
commit
1c5efe7e62
3 changed files with 332 additions and 204 deletions
src
202
src/ast.rs
202
src/ast.rs
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue