use anyhow::Result;
use std::collections::HashMap;
use super::{scope::ScopeRef, structs::ClassMethod};
use crate::core::{Args, RustValue, Value};
#[derive(Debug, Clone)]
pub struct Class {
pub name: String,
pub field_names: Vec<String>,
pub field_defaults: Vec<Option<Value>>,
pub methods: Vec<ClassMethod>,
}
impl Class {
pub fn new(
name: String,
field_names: Vec<String>,
field_defaults: Vec<Option<Value>>,
methods: Vec<ClassMethod>,
) -> Self {
Self {
name,
field_names,
field_defaults,
methods,
}
}
pub fn find_method(&self, name: &str) -> Option<&ClassMethod> {
self.methods.iter().find(|m| m.name == name)
}
pub fn find_static_method(&self, name: &str) -> Option<&ClassMethod> {
self.methods.iter().find(|m| m.name == name && m.is_static)
}
}
#[crate::rust_value_any]
impl RustValue for Class {
fn dyn_clone(&self) -> Box<dyn RustValue> {
Box::new(self.clone())
}
fn get_attr(&self, name: &str) -> Option<Value> {
self.find_static_method(name).map(|method| {
Value::from_rust(StaticMethod {
class_name: self.name.clone(),
method: method.clone(),
})
})
}
fn set_attr(&mut self, _name: &str, _value: Value) -> Result<(), String> {
Err("Cannot set attributes on class".to_string())
}
fn call(&self, args: Args) -> Result<Value> {
if !args.is_empty() {
return Err(anyhow::anyhow!("Class constructor takes no arguments"));
}
Err(anyhow::anyhow!(
"Class constructor must be handled by evaluator to evaluate default field values"
))
}
}
#[derive(Debug, Clone)]
pub struct ClassInstance {
pub class_name: String,
pub fields: HashMap<String, Value>,
pub methods: Vec<ClassMethod>,
}
impl ClassInstance {
pub fn find_method(&self, name: &str) -> Option<&ClassMethod> {
self.methods.iter().find(|m| m.name == name && !m.is_static)
}
}
#[derive(Debug, Clone)]
pub struct BoundMethod {
pub instance: Value, pub method: ClassMethod,
pub closure_env: ScopeRef, }
#[crate::rust_value_any]
impl RustValue for BoundMethod {
fn dyn_clone(&self) -> Box<dyn RustValue> {
Box::new(self.clone())
}
fn call(&self, mut args: Args) -> Result<Value> {
use super::evaluator::{ControlFlow, ErrorKind, Evaluator};
use anyhow::anyhow;
let expected_args = self.method.params.len(); let provided_args = args.len() + 1;
if provided_args != expected_args {
return Err(anyhow!(
"Method '{}' expects {} arguments, got {}",
self.method.name,
expected_args - 1,
args.len()
));
}
let method_scope = self.closure_env.child();
args.set_function_name(&format!("method {}", self.method.name));
method_scope.define("self".to_string(), self.instance.clone());
for param_name in self.method.params.iter().skip(1) {
let arg_value = args.expect(param_name)?;
method_scope.define(param_name.clone(), arg_value);
}
args.complete()?;
let mut evaluator = Evaluator {
globals: self.closure_env.clone(),
current_env: method_scope,
current_dir: std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
};
match evaluator.eval(&self.method.body) {
Ok(value) => Ok(value),
Err(ControlFlow::Return(value)) => Ok(value),
Err(ControlFlow::Error(ErrorKind::SystemError(err))) => Err(err),
Err(ControlFlow::Error(ErrorKind::RaisedError(value))) => {
match value {
crate::core::Value::String(s) => Err(anyhow!("{}", s)),
_ => Err(anyhow!("{:?}", value)),
}
}
Err(other) => Err(anyhow!("Invalid control flow in method: {:?}", other)),
}
}
}
#[derive(Debug, Clone)]
pub struct StaticMethod {
pub class_name: String,
pub method: ClassMethod,
}
#[crate::rust_value_any]
impl RustValue for StaticMethod {
fn dyn_clone(&self) -> Box<dyn RustValue> {
Box::new(self.clone())
}
fn call(&self, _args: Args) -> Result<Value> {
Err(anyhow::anyhow!("Static method call not yet implemented"))
}
}