use super::{scope::ScopeRef, TypeConstant};
use crate::core::*;
use anyhow::anyhow;
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub enum ErrorKind {
SystemError(anyhow::Error),
RaisedError(Value),
}
#[derive(Debug)]
pub enum ControlFlow {
Return(Value),
Break(Value),
Continue,
Error(ErrorKind),
}
pub type EvalResult = Result<Value, ControlFlow>;
pub struct Evaluator {
pub globals: ScopeRef,
pub current_env: ScopeRef,
pub current_dir: PathBuf,
}
impl Default for Evaluator {
fn default() -> Self {
Self::new()
}
}
impl Evaluator {
pub fn new() -> Self {
Self::new_with_dir(std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")))
}
pub fn new_with_dir(current_dir: PathBuf) -> Self {
let globals = ScopeRef::new();
let mut evaluator = Evaluator {
globals: globals.clone(),
current_env: globals,
current_dir,
};
evaluator.register_builtins();
evaluator
}
fn register_builtins(&mut self) {
self.register_builtin_fn("print", print);
self.register_builtin_fn("assert", crate::core::assert);
self.register_builtin_fn("is_unit", crate::core::is_unit);
self.register_builtin_fn("str", crate::core::str);
self.register_builtin_fn("int", crate::core::int);
self.register_builtin_fn("float", crate::core::float);
self.register_builtin_fn("raise", crate::core::raise);
self.register_builtin_fn("parse", crate::core::parse_builtin);
self.register_builtin_fn("macro", crate::core::macro_identity_builtin);
self.register_builtin_fn("join", crate::core::join_builtin);
self.register_builtin_fn("range", crate::core::range);
self.register_builtin_fn("sum", crate::core::sum);
self.register_builtin_fn("filter", crate::core::filter);
self.register_builtin_fn("take_while", crate::core::take_while);
crate::core::register_math(self);
self.register_type_constants();
}
fn register_type_constants(&mut self) {
self.globals
.define("Null", Value::from_rust(TypeConstant::new("Null")));
self.globals
.define("Unit", Value::from_rust(TypeConstant::new("Unit")));
self.globals
.define("Bool", Value::from_rust(TypeConstant::new("Bool")));
self.globals
.define("Int", Value::from_rust(TypeConstant::new("Int")));
self.globals
.define("Float", Value::from_rust(TypeConstant::new("Float")));
self.globals
.define("String", Value::from_rust(TypeConstant::new("String")));
self.globals
.define("List", Value::from_rust(TypeConstant::new("List")));
self.globals
.define("Dict", Value::from_rust(TypeConstant::new("Dict")));
self.globals
.define("Range", Value::from_rust(TypeConstant::new("Range")));
self.globals
.define("Function", Value::from_rust(TypeConstant::new("Function")));
}
pub fn register_builtin_fn(
&mut self,
name: &'static str,
func: fn(Args) -> anyhow::Result<Value>,
) {
let rust_fn = Value::from_rust(RustFunction::new(name, func));
self.globals.define(name, rust_fn);
}
pub fn eval(&mut self, eval: &Value) -> EvalResult {
match eval.eval(self) {
Ok(result) => result,
Err(e) => Err(ControlFlow::Error(ErrorKind::SystemError(e))),
}
}
pub fn eval_str(&mut self, source: &str) -> anyhow::Result<Value> {
let ast = crate::parser::Parser::parse_str(source)?;
let eval_ir = crate::eval::Compiler::compile(ast)?;
self.eval(&eval_ir).map_err(|control_flow| {
match control_flow {
ControlFlow::Error(ErrorKind::SystemError(err)) => err,
ControlFlow::Error(ErrorKind::RaisedError(value)) => {
match value {
Value::String(s) => anyhow::anyhow!("{}", s),
_ => anyhow::anyhow!("{:?}", value),
}
}
ControlFlow::Return(val) => anyhow::anyhow!("Unexpected return: {:?}", val),
ControlFlow::Break(val) => anyhow::anyhow!("Unexpected break: {:?}", val),
ControlFlow::Continue => anyhow::anyhow!("Unexpected continue"),
}
})
}
pub fn handle_class_constructor(
&mut self,
class: &crate::eval::Class,
args: &[Value],
) -> EvalResult {
use std::collections::HashMap;
if !args.is_empty() {
return Err(ControlFlow::Error(ErrorKind::SystemError(anyhow::anyhow!(
"Class constructor takes no arguments"
))));
}
let mut fields = HashMap::new();
for (i, field_name) in class.field_names.iter().enumerate() {
let value = if let Some(default_expr) = &class.field_defaults[i] {
self.eval(default_expr)?
} else {
Value::Null
};
fields.insert(field_name.clone(), value);
}
Ok(Value::new_class_instance(crate::eval::ClassInstance {
class_name: class.name.clone(),
fields,
methods: class.methods.clone(),
}))
}
pub fn cleanup_resources(&mut self, resources: &[(String, Value)]) {
for (_name, resource_value) in resources.iter().rev() {
let close_method = resource_value.get_attr("op_close", self);
if let Some(close_method) = close_method {
let args = Args::positional(vec![]);
let _ = close_method.call(args);
}
}
}
pub fn load_module(&self, module_name: &str) -> Result<ScopeRef, ControlFlow> {
let module_path = self.resolve_module_path(module_name)?;
let module_content = std::fs::read_to_string(&module_path).map_err(|e| {
ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Failed to read module '{}' at path '{}': {}",
module_name,
module_path.display(),
e
)))
})?;
let tokens = crate::lexer::Lexer::tokenize(&module_content).map_err(|e| {
ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Failed to tokenize module '{}': {}",
module_name,
e
)))
})?;
let ast = crate::parser::Parser::parse(tokens).map_err(|e| {
ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Failed to parse module '{}': {}",
module_name,
e
)))
})?;
let eval_ir = crate::eval::Compiler::compile(ast).map_err(|e| {
ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Failed to compile module '{}': {}",
module_name,
e
)))
})?;
let module_dir = module_path.parent().unwrap_or(Path::new(".")).to_path_buf();
let mut module_evaluator = Evaluator::new_with_dir(module_dir);
module_evaluator.eval(&eval_ir)?;
Ok(module_evaluator.current_env)
}
fn resolve_module_path(&self, module_name: &str) -> Result<PathBuf, ControlFlow> {
let relative_path = module_name.replace("::", "/") + ".rustleaf";
let full_path = self.current_dir.join(relative_path);
if !full_path.exists() {
return Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Module file not found: {}",
full_path.display()
))));
}
Ok(full_path)
}
#[allow(dead_code)]
pub fn match_pattern(
&mut self,
pattern: &crate::eval::EvalPattern,
value: &Value,
) -> Result<(), ControlFlow> {
use crate::eval::EvalPattern;
match pattern {
EvalPattern::Variable(name) => {
self.current_env.define(name.clone(), value.clone());
Ok(())
}
EvalPattern::List(patterns) => {
match value {
Value::List(list_ref) => {
let list = list_ref.borrow();
if list.len() != patterns.len() {
return Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Cannot destructure list of length {} into pattern with {} elements",
list.len(),
patterns.len()
))));
}
for (pattern, list_value) in patterns.iter().zip(list.iter()) {
self.match_pattern(pattern, list_value)?;
}
Ok(())
}
_ => Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Cannot destructure non-list value {:?} with list pattern",
value
)))),
}
}
EvalPattern::ListRest(patterns, rest_name) => {
match value {
Value::List(list_ref) => {
let list = list_ref.borrow();
if list.len() < patterns.len() {
return Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Cannot destructure list of length {} with rest pattern expecting at least {} elements",
list.len(),
patterns.len()
))));
}
for (i, pattern) in patterns.iter().enumerate() {
let list_value = &list[i];
self.match_pattern(pattern, list_value)?;
}
if let Some(rest_var) = rest_name {
let rest_values: Vec<Value> = list[patterns.len()..].to_vec();
let rest_list = Value::new_list_with_values(rest_values);
self.current_env.define(rest_var.clone(), rest_list);
}
Ok(())
}
_ => Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Cannot destructure non-list value {:?} with list rest pattern",
value
)))),
}
}
EvalPattern::Dict(dict_patterns) => {
match value {
Value::Dict(dict_ref) => {
let dict = dict_ref.borrow();
for dict_pattern in dict_patterns {
let dict_value = dict.get(&dict_pattern.key).ok_or_else(|| {
ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Key '{}' not found in dict during destructuring",
dict_pattern.key
)))
})?;
let var_name = dict_pattern.alias.as_ref().unwrap_or(&dict_pattern.key);
self.current_env
.define(var_name.clone(), dict_value.clone());
}
Ok(())
}
_ => Err(ControlFlow::Error(ErrorKind::SystemError(anyhow!(
"Cannot destructure non-dict value {:?} with dict pattern",
value
)))),
}
}
}
}
pub fn match_pattern_matches(
&mut self,
pattern: &crate::eval::EvalMatchPattern,
value: &Value,
) -> Result<bool, ControlFlow> {
use crate::eval::EvalMatchPattern;
match pattern {
EvalMatchPattern::Literal(literal) => Ok(literal == value),
EvalMatchPattern::Variable(_) => Ok(true),
EvalMatchPattern::Wildcard => Ok(true),
}
}
pub fn get(&self, name: &str) -> anyhow::Result<Value> {
self.globals
.get(name)
.ok_or_else(|| anyhow::anyhow!("Variable '{}' not found", name))
}
pub fn call(&mut self, function: Value, args: &[Value]) -> anyhow::Result<Value> {
use crate::core::Args;
let args_obj = Args::positional(args.to_vec());
function
.call(args_obj)
.map_err(|e| anyhow::anyhow!("Function call failed: {}", e))
}
}