2025-10-03 19:07:12 +02:00
|
|
|
mod backend;
|
|
|
|
|
mod frontend;
|
|
|
|
|
mod logging;
|
|
|
|
|
mod prompt;
|
|
|
|
|
mod result;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
backend::{
|
|
|
|
|
environment::Environment,
|
|
|
|
|
interpreter::{EvaluateInterpreter, Interpreter},
|
|
|
|
|
},
|
|
|
|
|
frontend::{
|
|
|
|
|
lexer::Lexer,
|
|
|
|
|
parser::Parser,
|
|
|
|
|
source_registry::{SourceFile, SourceId, SourcePosition, SourceRegistry, SourceSlice},
|
|
|
|
|
},
|
|
|
|
|
prompt::prompt_lines,
|
|
|
|
|
result::{LoxError, LoxResult},
|
|
|
|
|
};
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::{env, error::Error};
|
|
|
|
|
|
|
|
|
|
fn main() -> LoxResult<()> {
|
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
|
let mut lox = LoxInterpreter::new();
|
|
|
|
|
|
2025-10-04 19:02:33 +02:00
|
|
|
let _ = if args.len() > 2 {
|
2025-10-03 19:07:12 +02:00
|
|
|
eprintln!("Usage: {} [script]", args[0]);
|
|
|
|
|
std::process::exit(64);
|
|
|
|
|
} else if args.len() == 2 {
|
|
|
|
|
// Esegui file
|
2025-10-04 19:02:33 +02:00
|
|
|
lox.run_file(&args[1])
|
2025-10-03 19:07:12 +02:00
|
|
|
} else {
|
|
|
|
|
// Modalità interattiva
|
2025-10-04 19:02:33 +02:00
|
|
|
lox.run_prompt()
|
|
|
|
|
};
|
2025-10-03 19:07:12 +02:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct LoxInterpreter {
|
|
|
|
|
source_registry: SourceRegistry,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl LoxInterpreter {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
LoxInterpreter {
|
|
|
|
|
source_registry: SourceRegistry::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ✅ Pipeline funzionale per file
|
|
|
|
|
fn run_file(&mut self, path: &str) -> LoxResult<()> {
|
|
|
|
|
fs::read_to_string(path)
|
|
|
|
|
.map_err(|e| LoxError::IoError {
|
|
|
|
|
message: e.to_string(),
|
|
|
|
|
})
|
|
|
|
|
.and_then(|source| self.source_registry.add_source_string(source))
|
|
|
|
|
.and_then(|source_id| self.process_source(source_id))
|
|
|
|
|
.map(|result| println!("file {}", result))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ✅ Pipeline funzionale per prompt
|
|
|
|
|
fn run_prompt(&mut self) -> LoxResult<()> {
|
|
|
|
|
println!("Lox REPL - Type 'exit' to quit");
|
|
|
|
|
|
|
|
|
|
prompt_lines(|source| self.source_registry.add_source_string(source))
|
|
|
|
|
.for_each(|line| println!("hi: {}", line));
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn process_source(&self, source_id: SourceId) -> LoxResult<String> {
|
|
|
|
|
let mut lexer = Lexer::new(
|
|
|
|
|
self.source_registry.get_by_id(source_id).content.clone(),
|
|
|
|
|
source_id,
|
|
|
|
|
);
|
|
|
|
|
let res = lexer
|
|
|
|
|
.scans_tokens()
|
|
|
|
|
.and_then(|tokens| Parser::new(tokens).parse())
|
|
|
|
|
.and_then(|asts| {
|
|
|
|
|
// println!("asts: {:?}", asts);
|
|
|
|
|
Ok(asts)
|
|
|
|
|
})
|
|
|
|
|
.and_then(|stmts| {
|
|
|
|
|
let mut env = Environment::new();
|
|
|
|
|
let mut interpreter = Interpreter::new(&mut env);
|
|
|
|
|
let mut result = None;
|
2025-10-04 19:02:33 +02:00
|
|
|
for (index, stmt) in stmts.iter().enumerate() {
|
|
|
|
|
println!("executing stmt {}: {:?}", index, stmt);
|
|
|
|
|
result = Some(interpreter.interpret(stmt.clone())?);
|
2025-10-03 19:07:12 +02:00
|
|
|
}
|
|
|
|
|
match result {
|
|
|
|
|
Some(res) => Ok(res),
|
|
|
|
|
_ => Err(LoxError::RuntimeError {
|
|
|
|
|
source_slice: SourceSlice::default(),
|
|
|
|
|
message: "what?????".to_string(),
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.and_then(|result| Ok(format!("{}", result)))
|
|
|
|
|
.or_else(|err| {
|
|
|
|
|
err.print_with_context(&self.source_registry);
|
|
|
|
|
Err(err)
|
|
|
|
|
});
|
|
|
|
|
// println!("result {}", res);
|
|
|
|
|
|
|
|
|
|
res
|
|
|
|
|
}
|
|
|
|
|
}
|