use super::Aether;
use crate::evaluator::ErrorReport;
use crate::parser::Parser;
use crate::value::Value;
impl Aether {
pub fn eval(&mut self, code: &str) -> Result<Value, String> {
self.evaluator.clear_call_stack();
self.evaluator.reset_step_counter();
let program = if let Some(cached_program) = self.cache.get(code) {
cached_program
} else {
let mut parser = Parser::new(code);
let program = parser
.parse_program()
.map_err(|e| format!("Parse error: {}", e))?;
let optimized = self.optimizer.optimize_program(&program);
self.cache.insert(code, optimized.clone());
optimized
};
self.evaluator
.eval_program(&program)
.map_err(|e| format!("Runtime error: {}", e))
}
pub fn eval_report(&mut self, code: &str) -> Result<Value, ErrorReport> {
self.evaluator.clear_call_stack();
self.evaluator.reset_step_counter();
let program = if let Some(cached_program) = self.cache.get(code) {
cached_program
} else {
let mut parser = Parser::new(code);
let program = parser
.parse_program()
.map_err(|e| ErrorReport::parse_error(e.to_string()))?;
let optimized = self.optimizer.optimize_program(&program);
self.cache.insert(code, optimized.clone());
optimized
};
self.evaluator
.eval_program(&program)
.map_err(|e| e.to_error_report())
}
pub fn set_module_resolver(&mut self, resolver: Box<dyn crate::module_system::ModuleResolver>) {
self.evaluator.set_module_resolver(resolver);
}
pub fn push_import_base(&mut self, module_id: String, base_dir: Option<std::path::PathBuf>) {
self.evaluator.push_import_base(module_id, base_dir);
}
pub fn pop_import_base(&mut self) {
self.evaluator.pop_import_base();
}
pub fn eval_file(&mut self, path: impl AsRef<std::path::Path>) -> Result<Value, String> {
let path = path.as_ref();
let code = std::fs::read_to_string(path).map_err(|e| format!("IO error: {}", e))?;
let canon = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
let base_dir = canon.parent().map(|p| p.to_path_buf());
self.push_import_base(canon.display().to_string(), base_dir);
let res = self.eval(&code);
self.pop_import_base();
res
}
pub fn eval_file_report(
&mut self,
path: impl AsRef<std::path::Path>,
) -> Result<Value, ErrorReport> {
let path = path.as_ref();
let code = std::fs::read_to_string(path)
.map_err(|e| ErrorReport::io_error(format!("IO error: {e}")))?;
let canon = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());
let base_dir = canon.parent().map(|p| p.to_path_buf());
self.push_import_base(canon.display().to_string(), base_dir);
let res = self.eval_report(&code);
self.pop_import_base();
res
}
pub fn set_global(&mut self, name: &str, value: Value) {
self.evaluator.set_global(name.to_string(), value);
}
pub fn reset_env(&mut self) {
self.evaluator.reset_env();
}
pub fn with_isolated_scope<R>(
&mut self,
f: impl FnOnce(&mut Aether) -> Result<R, String>,
) -> Result<R, String> {
let prev_env = self.evaluator.enter_child_scope();
let result = f(self);
self.evaluator.restore_env(prev_env);
result
}
#[cfg(feature = "async")]
pub async fn eval_async(&mut self, code: &str) -> Result<Value, String> {
tokio::task::yield_now().await;
self.eval(code)
}
}