add ast printer

This commit is contained in:
Sebastian Hugentobler 2025-05-27 09:22:29 +02:00
parent 8c500ab6a9
commit 6e02a1a644
Signed by: shu
SSH key fingerprint: SHA256:ppcx6MlixdNZd5EUM1nkHOKoyQYoJwzuQKXM6J/t66M
6 changed files with 314 additions and 1 deletions

173
src/ast_printer.rs Normal file
View file

@ -0,0 +1,173 @@
use crate::{expression::Expression, statement::Statement, token::Literal};
pub fn print(statements: &[Statement]) -> String {
let mut result = String::new();
for statement in statements {
result.push_str(&format!("{}\n", print_statement(statement, 0)));
}
result
}
fn print_statement(statement: &Statement, indent: usize) -> String {
let indent_str = " ".repeat(indent);
match statement {
Statement::Block(statements) => {
let mut result = format!("{}Block:\n", indent_str);
for stmt in statements {
result.push_str(&format!("{}\n", print_statement(stmt, indent + 1)));
}
result.trim_end().to_string()
}
Statement::Print(expr) => {
format!("{}Print: {}", indent_str, print_expression(expr))
}
Statement::Expression(expr) => {
format!("{}Expr: {}", indent_str, print_expression(expr))
}
Statement::Var { name, initializer } => {
let init_str = match **initializer {
Some(ref expr) => print_expression(expr),
None => "nil".to_string(),
};
format!("{}Var {}: {}", indent_str, name.lexeme, init_str)
}
Statement::If {
condition,
then_branch,
else_branch,
} => {
let mut result = format!(
"{}If ({})\n{}",
indent_str,
print_expression(condition),
print_statement(then_branch, indent + 1)
);
if let Some(else_branch) = else_branch {
result.push_str(&format!(
"\n{}Else:\n{}",
indent_str,
print_statement(else_branch, indent + 1)
));
}
result
}
Statement::While { condition, body } => {
format!(
"{}While ({})\n{}",
indent_str,
print_expression(condition),
print_statement(body, indent + 1)
)
}
Statement::Function { name, params, body } => {
let params_str = params
.iter()
.map(|p| p.lexeme.clone())
.collect::<Vec<_>>()
.join(", ");
let mut result = format!("{}Function {}({}):\n", indent_str, name.lexeme, params_str);
for stmt in body {
result.push_str(&format!("{}\n", print_statement(stmt, indent + 1)));
}
result.trim_end().to_string()
}
Statement::Return { keyword: _, value } => {
let value_str = match value {
Some(expr) => print_expression(expr),
None => "nil".to_string(),
};
format!("{}Return: {}", indent_str, value_str)
}
Statement::Class {
name,
superclass,
methods,
} => {
let superclass_str = match superclass {
Some(expr) => format!(" < {}", print_expression(expr)),
None => "".to_string(),
};
let mut result = format!("{}Class {}{}:\n", indent_str, name.lexeme, superclass_str);
for method in methods {
result.push_str(&format!("{}\n", print_statement(method, indent + 1)));
}
result.trim_end().to_string()
}
}
}
fn print_expression(expr: &Expression) -> String {
match expr {
Expression::Assign { name, value } => {
format!("(= {} {})", name.lexeme, print_expression(value))
}
Expression::Binary {
left,
operator,
right,
} => {
format!(
"({} {} {})",
operator.lexeme,
print_expression(left),
print_expression(right)
)
}
Expression::Call {
callee,
paren: _,
args,
} => {
let args_str = args
.iter()
.map(print_expression)
.collect::<Vec<_>>()
.join(", ");
format!("(call {} [{}])", print_expression(callee), args_str)
}
Expression::Get { object, name } => {
format!("(get {} {})", print_expression(object), name.lexeme)
}
Expression::Grouping { expression } => {
format!("(group {})", print_expression(expression))
}
Expression::Literal { value } => match value {
Literal::String(s) => format!("\"{}\"", s),
Literal::Number(n) => format!("{}", n),
Literal::Boolean(b) => format!("{}", b),
Literal::Nil => "nil".to_string(),
},
Expression::Logical {
left,
operator,
right,
} => {
format!(
"({} {} {})",
operator.lexeme,
print_expression(left),
print_expression(right)
)
}
Expression::Set {
object,
name,
value,
} => {
format!(
"(set {} {} {})",
print_expression(object),
name.lexeme,
print_expression(value)
)
}
Expression::Super { keyword: _, method } => {
format!("(super {})", method.lexeme)
}
Expression::This { keyword: _ } => "this".to_string(),
Expression::Unary { operator, right } => {
format!("({} {})", operator.lexeme, print_expression(right))
}
Expression::Variable { name } => name.lexeme.clone(),
}
}

View file

@ -11,8 +11,9 @@ use interpreter::{Interpreter, InterpreterError};
use parser::ParserError;
use resolver::{Resolver, ResolverError};
use thiserror::Error;
use tracing::error;
use tracing::{debug, error};
pub mod ast_printer;
pub mod callable;
pub mod class;
pub mod cli;
@ -90,6 +91,8 @@ fn run_rox(input: &str, interpreter: &mut Interpreter) -> Result<(), RoxError> {
let mut resolver = Resolver::new(interpreter);
let ast = parser::ast(tokens)?;
debug!("AST:\n{}", crate::ast_printer::print(&ast));
resolver.resolve(&ast)?;
interpreter.run(ast)?;