add ast printer
This commit is contained in:
parent
8c500ab6a9
commit
6e02a1a644
6 changed files with 314 additions and 1 deletions
100
lox/bf.lox
Normal file
100
lox/bf.lox
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
class Cell {
|
||||||
|
init(previous, next, data) {
|
||||||
|
this.previous = previous;
|
||||||
|
this.next = next;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tape {
|
||||||
|
init() {
|
||||||
|
this.current = Cell(nil, nil, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
backward() {
|
||||||
|
if (this.current.previous == nil) {
|
||||||
|
this.current.previous = Cell(nil, this.current, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = this.current.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
forward() {
|
||||||
|
if (this.current.next == nil) {
|
||||||
|
this.current.next = Cell(this.current, nil, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.current = this.current.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
increment() {
|
||||||
|
this.current.data = this.current.data + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
decrement() {
|
||||||
|
this.current.data = this.current.data - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Interpreter {
|
||||||
|
init(bfpath) {
|
||||||
|
this.bfpath = bfpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
var tape = Tape();
|
||||||
|
var instruction = read(this.bfpath);
|
||||||
|
|
||||||
|
while (instruction != nil) {
|
||||||
|
if (instruction == ">") {
|
||||||
|
tape.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == "<") {
|
||||||
|
tape.backward();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == "+") {
|
||||||
|
tape.increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == "-") {
|
||||||
|
tape.decrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == ".") {
|
||||||
|
asciiOut(tape.current.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == ",") {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == "[" and tape.current.data < 0.0001) {
|
||||||
|
instruction = read(this.bfpath);
|
||||||
|
var bracketCount = 1;
|
||||||
|
while (bracketCount > 0 and instruction != nil) {
|
||||||
|
if (instruction == "[") { bracketCount = bracketCount + 1; }
|
||||||
|
if (instruction == "]") { bracketCount = bracketCount - 1; }
|
||||||
|
if (bracketCount > 0) { instruction = read(this.bfpath); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction == "]" and tape.current.data >= 0.0001) {
|
||||||
|
instruction = read(this.bfpath, true);
|
||||||
|
var bracketCount = 1;
|
||||||
|
while (bracketCount > 0 and instruction != nil) {
|
||||||
|
if (instruction == "]") { bracketCount = bracketCount + 1; }
|
||||||
|
if (instruction == "[") { bracketCount = bracketCount - 1; }
|
||||||
|
if (bracketCount > 0) { instruction = read(this.bfpath, true); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction = read(this.bfpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var interpreter = Interpreter("bf/helloworld.bf");
|
||||||
|
interpreter.run();
|
7
lox/error.lox
Normal file
7
lox/error.lox
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
var a = 1;
|
||||||
|
while (a < 10) {
|
||||||
|
a = a + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print a;
|
||||||
|
|
22
lox/for_closure_in_body_lox
Normal file
22
lox/for_closure_in_body_lox
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
var f1;
|
||||||
|
var f2;
|
||||||
|
var f3;
|
||||||
|
|
||||||
|
for (var i = 1; i < 4; i = i + 1) {
|
||||||
|
var j = i;
|
||||||
|
fun f() {
|
||||||
|
print i;
|
||||||
|
print j;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j == 1) f1 = f;
|
||||||
|
else if (j == 2) f2 = f;
|
||||||
|
else f3 = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
f1(); // expect: 4
|
||||||
|
// expect: 1
|
||||||
|
f2(); // expect: 4
|
||||||
|
// expect: 2
|
||||||
|
f3(); // expect: 4
|
||||||
|
// expect: 3
|
8
lox/shadow_local.lox
Normal file
8
lox/shadow_local.lox
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
var a = "local";
|
||||||
|
{
|
||||||
|
var a = "shadow";
|
||||||
|
print a; // expect: shadow
|
||||||
|
}
|
||||||
|
print a; // expect: local
|
||||||
|
}
|
173
src/ast_printer.rs
Normal file
173
src/ast_printer.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,8 +11,9 @@ use interpreter::{Interpreter, InterpreterError};
|
||||||
use parser::ParserError;
|
use parser::ParserError;
|
||||||
use resolver::{Resolver, ResolverError};
|
use resolver::{Resolver, ResolverError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tracing::error;
|
use tracing::{debug, error};
|
||||||
|
|
||||||
|
pub mod ast_printer;
|
||||||
pub mod callable;
|
pub mod callable;
|
||||||
pub mod class;
|
pub mod class;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
@ -90,6 +91,8 @@ fn run_rox(input: &str, interpreter: &mut Interpreter) -> Result<(), RoxError> {
|
||||||
let mut resolver = Resolver::new(interpreter);
|
let mut resolver = Resolver::new(interpreter);
|
||||||
|
|
||||||
let ast = parser::ast(tokens)?;
|
let ast = parser::ast(tokens)?;
|
||||||
|
debug!("AST:\n{}", crate::ast_printer::print(&ast));
|
||||||
|
|
||||||
resolver.resolve(&ast)?;
|
resolver.resolve(&ast)?;
|
||||||
interpreter.run(ast)?;
|
interpreter.run(ast)?;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue