crafting-interpreters/src/lib.rs

100 lines
2.3 KiB
Rust

//! Interpret the Lox language. Either compile (interpret for now though) some source code or run a
//! REPL.
use std::{
fs::{self},
io::{self, Write},
path::Path,
};
use interpreter::{Interpreter, InterpreterError};
use parser::ParserError;
use resolver::{Resolver, ResolverError};
use thiserror::Error;
use tracing::{debug, error};
pub mod ast_printer;
pub mod callable;
pub mod class;
pub mod cli;
pub mod environment;
pub mod expression;
pub mod function;
pub mod instance;
pub mod interpreter;
pub mod keywords;
pub mod native_functions;
pub mod parser;
pub mod resolver;
pub mod scanner;
pub mod statement;
pub mod token;
pub mod tokenizer {
pub mod comment;
pub mod identifier;
pub mod interface;
pub mod lookahead;
pub mod newline;
pub mod number;
pub mod single_char;
pub mod string;
pub mod whitespace;
}
pub mod value;
#[derive(Error, Debug)]
pub enum RoxError {
#[error("parser failed: {0}")]
ParseError(#[from] ParserError),
#[error("resolver failed: {0}")]
ResolverError(#[from] ResolverError),
#[error("interpreter failed: {0}")]
InterpreterError(#[from] InterpreterError),
}
/// Read the source code in a file and scan it to tokens.
pub fn compile(source: &Path) -> Result<(), io::Error> {
let input = fs::read_to_string(source)?;
let mut interpreter = Interpreter::default();
run(&input, &mut interpreter);
Ok(())
}
/// Run a Lox REPL until SIGINT.
pub fn repl() {
let mut interpreter = Interpreter::default();
loop {
print!("> ");
let _ = io::stdout().flush();
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {}
Err(e) => error!("{}", e),
}
let input = input.trim().to_string();
run(&input, &mut interpreter);
}
}
/// Evaluate a Lox input string and print errors or output.
fn run(input: &str, interpreter: &mut Interpreter) {
if let Err(e) = run_rox(input, interpreter) {
error!("{e}");
}
}
fn run_rox(input: &str, interpreter: &mut Interpreter) -> Result<(), RoxError> {
let tokens = scanner::tokenize(input);
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)?;
Ok(())
}