#![allow(clippy::unused_self)] #![allow(clippy::only_used_in_recursion)] #![allow(clippy::uninlined_format_args)] #![allow(clippy::cast_precision_loss)] #![allow(clippy::expect_used)] #![allow(clippy::cast_possible_truncation)]
use super::eval_expr;
use super::eval_literal;
use super::eval_operations;
pub use super::value::{DataFrameColumn, Value};
pub use super::interpreter_types::{CallFrame, InterpreterError, InterpreterResult};
use crate::frontend::ast::{
BinaryOp as AstBinaryOp, ComprehensionClause, Expr, ExprKind, Literal, Pattern, StringPart,
};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
#[derive(Debug)]
pub(crate) enum LoopControlOrError {
Break(Option<String>, Value),
Continue(Option<String>),
Return(Value), Error(InterpreterError),
}
#[derive(Debug)]
pub struct Interpreter {
stack: Vec<Value>,
pub(crate) env_stack: Vec<Rc<RefCell<HashMap<std::string::String, Value>>>>,
#[allow(dead_code)]
frames: Vec<CallFrame>,
#[allow(dead_code)]
execution_counts: HashMap<usize, u32>,
field_caches: HashMap<String, InlineCache>,
type_feedback: TypeFeedback,
gc: ConservativeGC,
error_scopes: Vec<ErrorScope>,
stdout_buffer: Vec<String>,
module_loader: crate::backend::module_loader::ModuleLoader,
}
#[derive(Debug, Clone)]
struct ErrorScope {
env_depth: usize,
}
pub use super::type_feedback::{
CacheEntry, CacheState, CallSiteFeedback, InlineCache, OperationFeedback,
SpecializationCandidate, SpecializationKind, TypeFeedback, TypeFeedbackStats,
VariableTypeFeedback,
};
pub use super::gc_impl::{ConservativeGC, GCInfo, GCObject, GCStats};
pub use super::compilation::{
DirectThreadedInterpreter, InstructionResult, InterpreterState, ThreadedInstruction,
};
impl Interpreter {
pub fn new() -> Self {
let global_env = crate::runtime::builtin_init::init_global_environment();
Self {
stack: Vec::with_capacity(1024), env_stack: vec![Rc::new(RefCell::new(global_env))], frames: Vec::new(),
execution_counts: HashMap::new(),
field_caches: HashMap::new(),
type_feedback: TypeFeedback::new(),
gc: ConservativeGC::new(),
error_scopes: Vec::new(),
stdout_buffer: Vec::new(), module_loader: crate::backend::module_loader::ModuleLoader::new(), }
}
pub fn eval_expr(&mut self, expr: &Expr) -> Result<Value, InterpreterError> {
self.eval_expr_kind(&expr.kind)
}
pub(crate) fn eval_expr_kind(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Literal(_) | ExprKind::Identifier(_) => self.eval_simple_expr(expr_kind),
ExprKind::Binary { .. }
| ExprKind::Unary { .. }
| ExprKind::Call { .. }
| ExprKind::MethodCall { .. }
| ExprKind::DataFrameOperation { .. }
| ExprKind::IndexAccess { .. }
| ExprKind::FieldAccess { .. }
| ExprKind::TypeCast { .. } => self.eval_operation_expr(expr_kind),
ExprKind::Function { .. } | ExprKind::Lambda { .. } => {
self.eval_function_expr(expr_kind)
}
kind if Self::is_control_flow_expr(kind) => self.eval_control_flow_expr(kind),
kind if Self::is_data_structure_expr(kind) => self.eval_data_structure_expr(kind),
kind if Self::is_assignment_expr(kind) => self.eval_assignment_expr(kind),
_ => self.eval_misc_expr(expr_kind),
}
}
pub(crate) fn eval_simple_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Literal(lit) => Ok(eval_literal::eval_literal(lit)),
ExprKind::Identifier(name) => self.lookup_variable(name),
_ => unreachable!("eval_simple_expr called with non-simple expression"),
}
}
pub(crate) fn eval_operation_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Binary { left, op, right } => self.eval_binary_expr(left, *op, right),
ExprKind::Unary { op, operand } => self.eval_unary_expr(*op, operand),
ExprKind::Call { func, args } => self.eval_function_call(func, args),
ExprKind::MethodCall {
receiver,
method,
args,
} => self.eval_method_call(receiver, method, args),
ExprKind::DataFrameOperation { source, operation } => {
self.eval_dataframe_operation(source, operation)
}
ExprKind::IndexAccess { object, index } => self.eval_index_access(object, index),
ExprKind::FieldAccess { object, field } => self.eval_field_access(object, field),
ExprKind::TypeCast { expr, target_type } => self.eval_type_cast(expr, target_type),
_ => unreachable!("eval_operation_expr called with non-operation expression"),
}
}
pub(crate) fn eval_function_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Function {
name, params, body, ..
} => self.eval_function(name, params, body),
ExprKind::Lambda { params, body } => self.eval_lambda(params, body),
_ => unreachable!("eval_function_expr called with non-function expression"),
}
}
pub(crate) fn is_type_definition(expr_kind: &ExprKind) -> bool {
matches!(
expr_kind,
ExprKind::Actor { .. }
| ExprKind::Effect { .. }
| ExprKind::Handle { .. }
| ExprKind::Enum { .. }
| ExprKind::Struct { .. }
| ExprKind::TupleStruct { .. }
| ExprKind::Class { .. }
| ExprKind::Impl { .. }
)
}
pub(crate) fn is_actor_operation(expr_kind: &ExprKind) -> bool {
matches!(
expr_kind,
ExprKind::Spawn { .. } | ExprKind::ActorSend { .. } | ExprKind::ActorQuery { .. }
)
}
pub(crate) fn is_special_form(expr_kind: &ExprKind) -> bool {
matches!(
expr_kind,
ExprKind::None
| ExprKind::Some { .. }
| ExprKind::Set(_)
| ExprKind::LetPattern { .. }
| ExprKind::StringInterpolation { .. }
| ExprKind::QualifiedName { .. }
| ExprKind::ObjectLiteral { .. }
| ExprKind::StructLiteral { .. }
)
}
pub(crate) fn eval_type_definition(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Actor {
name,
state,
handlers,
} => self.eval_actor_definition(name, state, handlers),
ExprKind::Effect { .. } => Ok(Value::Nil),
ExprKind::Handle { expr, .. } => {
self.eval_expr(expr)?;
Ok(Value::Nil)
}
ExprKind::Enum {
name,
type_params,
variants,
is_pub,
} => self.eval_enum_definition(name, type_params, variants, *is_pub),
ExprKind::Struct {
name,
type_params,
fields,
methods,
derives: _,
is_pub,
} => self.eval_struct_definition(name, type_params, fields, methods, *is_pub),
ExprKind::TupleStruct { .. } => {
Ok(Value::Nil)
}
ExprKind::Class {
name,
type_params,
superclass,
traits,
fields,
constructors,
methods,
constants,
properties: _,
derives,
is_pub,
is_sealed: _,
is_abstract: _,
decorators: _,
} => self.eval_class_definition(
name,
type_params,
superclass.as_ref(),
traits,
fields,
constructors,
methods,
constants,
derives,
*is_pub,
),
ExprKind::Impl {
trait_name: _,
for_type,
methods,
..
} => self.eval_impl_block(for_type, methods),
_ => unreachable!("eval_type_definition called with non-type-definition"),
}
}
pub(crate) fn eval_actor_operation(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Spawn { actor } => self.eval_spawn_actor(actor),
ExprKind::ActorSend { actor, message } => self.eval_actor_send(actor, message),
ExprKind::ActorQuery { actor, message } => self.eval_actor_query(actor, message),
_ => unreachable!("eval_actor_operation called with non-actor-operation"),
}
}
pub(crate) fn eval_special_form(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::None => Ok(Value::EnumVariant {
enum_name: "Option".to_string(),
variant_name: "None".to_string(),
data: None,
}),
ExprKind::Some { value } => Ok(Value::EnumVariant {
enum_name: "Option".to_string(),
variant_name: "Some".to_string(),
data: Some(vec![self.eval_expr(value)?]),
}),
ExprKind::Set(statements) => {
let mut result = Value::Nil;
for stmt in statements {
result = self.eval_expr(stmt)?;
}
Ok(result)
}
ExprKind::LetPattern {
pattern,
value,
body,
..
} => self.eval_let_pattern(pattern, value, body),
ExprKind::StringInterpolation { parts } => self.eval_string_interpolation(parts),
ExprKind::QualifiedName { module, name } => self.eval_qualified_name(module, name),
ExprKind::ObjectLiteral { fields } => self.eval_object_literal(fields),
ExprKind::StructLiteral {
name,
fields,
base: _,
} => self.eval_struct_literal(name, fields),
_ => unreachable!("eval_special_form called with non-special-form"),
}
}
pub(crate) fn resolve_module_path(&self, module: &str) -> Option<Value> {
let parts: Vec<&str> = module.split("::").collect();
let first_part = parts.first()?;
let global_env_ref = self.env_stack.first()?;
let global_env = global_env_ref.borrow();
let mut current_value = global_env.get(*first_part)?.clone();
for &part in parts.iter().skip(1) {
if let Value::Object(obj) = current_value {
current_value = obj.get(part)?.clone();
} else {
return None;
}
}
Some(current_value)
}
pub(crate) fn format_string_with_values(format_str: &str, values: &[Value]) -> String {
crate::runtime::value_format::format_string_with_values(format_str, values)
}
pub(crate) fn eval_misc_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
if Self::is_type_definition(expr_kind) {
return self.eval_type_definition(expr_kind);
}
if Self::is_actor_operation(expr_kind) {
return self.eval_actor_operation(expr_kind);
}
if Self::is_special_form(expr_kind) {
return self.eval_special_form(expr_kind);
}
match expr_kind {
ExprKind::ImportAll { module, alias } => {
let parts: Vec<&str> = module.split("::").collect();
if let Some(value) = self.resolve_module_path(module) {
let import_name = if alias == "*" {
return Ok(Value::Nil);
} else if !alias.is_empty() && alias != "*" {
alias.clone()
} else {
(*parts.last().unwrap_or(&"")).to_string()
};
if let Some(global_env_ref) = self.env_stack.first() {
global_env_ref.borrow_mut().insert(import_name, value); }
}
Ok(Value::Nil)
}
ExprKind::Import { module, items: _ } => {
if module.starts_with("std::") {
let parts: Vec<&str> = module.split("::").collect();
if let Some(value) = self.resolve_module_path(module) {
let import_name = (*parts.last().unwrap_or(&"")).to_string();
if let Some(global_env_ref) = self.env_stack.first() {
global_env_ref.borrow_mut().insert(import_name, value);
}
}
return Ok(Value::Nil);
}
let parsed_module = self.module_loader.load_module(module).map_err(|e| {
InterpreterError::RuntimeError(format!(
"Failed to load module '{}': {}",
module, e
))
})?;
let module_env_ref = Rc::new(RefCell::new(HashMap::new()));
self.env_stack.push(Rc::clone(&module_env_ref));
let eval_result = self.eval_expr(&parsed_module.ast);
self.env_stack.pop();
eval_result?;
let mut module_object = std::collections::HashMap::new();
for (name, value) in module_env_ref.borrow().iter() {
module_object.insert(name.clone(), value.clone());
}
if let Some(global_env_ref) = self.env_stack.first() {
global_env_ref
.borrow_mut()
.insert(module.clone(), Value::Object(module_object.into()));
}
Ok(Value::Nil)
}
ExprKind::ImportDefault { .. } => {
Ok(Value::Nil)
}
ExprKind::Macro { name, args } => {
if name == "vec" {
let mut elements = Vec::new();
for arg in args {
let value = self.eval_expr(arg)?;
elements.push(value);
}
Ok(Value::Array(elements.into()))
} else if name == "println" {
if args.is_empty() {
println!();
} else if args.len() == 1 {
let value = self.eval_expr(&args[0])?;
println!("{}", value);
} else {
let format_val = self.eval_expr(&args[0])?;
let format_str = match format_val {
Value::String(ref s) => s.as_ref().to_string(),
_ => format_val.to_string(),
};
let mut values = Vec::new();
for arg in &args[1..] {
values.push(self.eval_expr(arg)?);
}
let result = Self::format_string_with_values(&format_str, &values);
println!("{}", result);
}
Ok(Value::Nil)
} else if name == "format" {
if args.is_empty() {
return Err(InterpreterError::RuntimeError(
"format!() requires at least one argument".to_string(),
));
}
let format_val = self.eval_expr(&args[0])?;
let format_str = format_val.to_string();
let mut values = Vec::new();
for arg in &args[1..] {
values.push(self.eval_expr(arg)?);
}
let mut result = String::new();
let mut chars = format_str.chars().peekable();
let mut value_index = 0;
while let Some(ch) = chars.next() {
if ch == '{' {
if chars.peek() == Some(&':') {
chars.next(); if chars.peek() == Some(&'?') {
chars.next(); if chars.peek() == Some(&'}') {
chars.next(); if value_index < values.len() {
result.push_str(&format!("{:?}", values[value_index]));
value_index += 1;
} else {
result.push_str("{:?}"); }
} else {
result.push_str("{:?"); }
} else {
result.push_str("{:"); }
} else if chars.peek() == Some(&'}') {
chars.next(); if value_index < values.len() {
result.push_str(&values[value_index].to_string());
value_index += 1;
} else {
result.push_str("{}"); }
} else {
result.push(ch);
}
} else {
result.push(ch);
}
}
Ok(Value::from_string(result))
} else {
Err(InterpreterError::RuntimeError(format!(
"Macro '{}!' not yet implemented",
name
)))
}
}
ExprKind::MacroInvocation { name, args } => {
if name == "vec" {
let mut elements = Vec::new();
for arg in args {
let value = self.eval_expr(arg)?;
elements.push(value);
}
Ok(Value::Array(elements.into()))
} else if name == "println" {
if args.is_empty() {
println!();
} else if args.len() == 1 {
let value = self.eval_expr(&args[0])?;
println!("{}", value);
} else {
let format_val = self.eval_expr(&args[0])?;
let format_str = match format_val {
Value::String(ref s) => s.as_ref().to_string(),
_ => format_val.to_string(),
};
let mut values = Vec::new();
for arg in &args[1..] {
values.push(self.eval_expr(arg)?);
}
let result = Self::format_string_with_values(&format_str, &values);
println!("{}", result);
}
Ok(Value::Nil)
} else if name == "format" {
if args.is_empty() {
return Err(InterpreterError::RuntimeError(
"format!() requires at least one argument".to_string(),
));
}
let format_val = self.eval_expr(&args[0])?;
let format_str = format_val.to_string();
let mut values = Vec::new();
for arg in &args[1..] {
values.push(self.eval_expr(arg)?);
}
let mut result = String::new();
let mut chars = format_str.chars().peekable();
let mut value_index = 0;
while let Some(ch) = chars.next() {
if ch == '{' {
if chars.peek() == Some(&':') {
chars.next(); if chars.peek() == Some(&'?') {
chars.next(); if chars.peek() == Some(&'}') {
chars.next(); if value_index < values.len() {
result.push_str(&format!("{:?}", values[value_index]));
value_index += 1;
} else {
result.push_str("{:?}"); }
} else {
result.push_str("{:?"); }
} else {
result.push_str("{:"); }
} else if chars.peek() == Some(&'}') {
chars.next(); if value_index < values.len() {
result.push_str(&values[value_index].to_string());
value_index += 1;
} else {
result.push_str("{}"); }
} else {
result.push(ch);
}
} else {
result.push(ch);
}
}
Ok(Value::from_string(result))
} else {
Err(InterpreterError::RuntimeError(format!(
"Macro '{}!' not yet implemented",
name
)))
}
}
ExprKind::Try { expr } => {
let result_value = self.eval_expr(expr)?;
match &result_value {
Value::EnumVariant {
enum_name,
variant_name,
data,
} if enum_name == "Result" => {
match variant_name.as_str() {
"Ok" => {
if let Some(values) = data {
if let Some(value) = values.first() {
Ok(value.clone())
} else {
Err(InterpreterError::RuntimeError(
"Try operator: Ok variant has no data".to_string(),
))
}
} else {
Err(InterpreterError::RuntimeError(
"Try operator: Ok variant has no data".to_string(),
))
}
}
"Err" => {
Err(InterpreterError::Return(Value::EnumVariant {
enum_name: enum_name.clone(),
variant_name: variant_name.clone(),
data: data.clone(),
}))
}
_ => Err(InterpreterError::RuntimeError(format!(
"Try operator: unexpected Result variant '{}'",
variant_name
))),
}
}
Value::Object(obj)
if obj.get("__type").and_then(|v| {
if let Value::String(s) = v {
Some(s.as_ref())
} else {
None
}
}) == Some("Message") =>
{
if let Some(Value::String(variant)) = obj.get("type") {
match variant.as_ref() {
"Ok" => {
if let Some(Value::Array(data_arr)) = obj.get("data") {
if let Some(value) = data_arr.first() {
Ok(value.clone())
} else {
Err(InterpreterError::RuntimeError(
"Try operator: Ok has empty data".to_string(),
))
}
} else {
Err(InterpreterError::RuntimeError(
"Try operator: Ok missing data field".to_string(),
))
}
}
"Err" => {
Err(InterpreterError::Return(result_value))
}
_ => Err(InterpreterError::RuntimeError(format!(
"Try operator: unexpected type '{}'",
variant
))),
}
} else {
Err(InterpreterError::RuntimeError(
"Try operator: Message object missing 'type' field".to_string(),
))
}
}
_ => Err(InterpreterError::RuntimeError(format!(
"Try operator expects Result enum, got: {:?}",
result_value
))),
}
}
ExprKind::Pipeline { expr, stages } => {
let mut current_value = self.eval_expr(expr)?;
for stage in stages {
if let ExprKind::Identifier(method_name) = &stage.op.kind {
let is_user_function = self
.lookup_variable(method_name)
.map(|v| matches!(v, Value::Closure { .. }))
.unwrap_or(false);
if is_user_function {
let func_val = self.lookup_variable(method_name)?;
current_value = self.call_function(func_val, &[current_value])?;
} else {
current_value =
self.dispatch_method_call(¤t_value, method_name, &[], true)?;
}
} else if let ExprKind::Call { func, args } = &stage.op.kind {
if let ExprKind::Identifier(method_name) = &func.kind {
let is_user_function = self
.lookup_variable(method_name)
.map(|v| matches!(v, Value::Closure { .. }))
.unwrap_or(false);
if is_user_function {
let func_val = self.lookup_variable(method_name)?;
let arg_values: Result<Vec<_>, _> =
args.iter().map(|arg| self.eval_expr(arg)).collect();
let mut all_args = vec![current_value];
all_args.extend(arg_values?);
current_value = self.call_function(func_val, &all_args)?;
} else {
let arg_values: Result<Vec<_>, _> =
args.iter().map(|arg| self.eval_expr(arg)).collect();
current_value = self.dispatch_method_call(
¤t_value,
method_name,
&arg_values?,
args.is_empty(),
)?;
}
} else {
let func_val = self.eval_expr(func)?;
let arg_values: Result<Vec<_>, _> =
args.iter().map(|arg| self.eval_expr(arg)).collect();
let mut all_args = vec![current_value];
all_args.extend(arg_values?);
current_value = self.call_function(func_val, &all_args)?;
}
} else {
let func_val = self.eval_expr(&stage.op)?;
current_value = self.call_function(func_val, &[current_value])?;
}
}
Ok(current_value)
}
ExprKind::Lazy { expr } => {
self.eval_expr(expr)
}
ExprKind::AsyncBlock { body } => {
self.eval_expr(body)
}
ExprKind::Module { name, body } => self.eval_module_expr(name, body),
ExprKind::ModuleDeclaration { name } => Err(InterpreterError::RuntimeError(format!(
"Module '{}' not resolved. Use `ruchy compile` or ensure module file exists.",
name
))),
ExprKind::IfLet {
pattern,
expr,
then_branch,
else_branch,
} => {
let value = self.eval_expr(expr)?;
if let Some(bindings) = self.try_pattern_match(pattern, &value)? {
self.push_scope();
for (name, val) in bindings {
self.env_set(name, val);
}
let result = self.eval_expr(then_branch);
self.pop_scope();
result
} else if let Some(else_expr) = else_branch {
self.eval_expr(else_expr)
} else {
Ok(Value::Nil)
}
}
ExprKind::WhileLet {
label: _,
pattern,
expr,
body,
} => {
let mut last_value = Value::Nil;
loop {
let value = self.eval_expr(expr)?;
if let Some(bindings) = self.try_pattern_match(pattern, &value)? {
self.push_scope();
for (name, val) in bindings {
self.env_set(name, val);
}
match self.eval_expr(body) {
Ok(v) => last_value = v,
Err(InterpreterError::Break(_, v)) => {
self.pop_scope();
return Ok(v);
}
Err(InterpreterError::Continue(_)) => {
self.pop_scope();
continue;
}
Err(e) => {
self.pop_scope();
return Err(e);
}
}
self.pop_scope();
} else {
break;
}
}
Ok(last_value)
}
ExprKind::ListComprehension { element, clauses } => {
self.eval_list_comprehension(element, clauses)
}
_ => {
Err(InterpreterError::RuntimeError(format!(
"Expression type not yet implemented: {expr_kind:?}"
)))
}
}
}
pub(crate) fn eval_list_comprehension(
&mut self,
element: &Expr,
clauses: &[ComprehensionClause],
) -> Result<Value, InterpreterError> {
let mut results = Vec::new();
self.eval_comprehension_clauses(&mut results, element, clauses, 0)?;
Ok(Value::Array(Arc::from(results)))
}
pub(crate) fn eval_comprehension_clauses(
&mut self,
results: &mut Vec<Value>,
element: &Expr,
clauses: &[ComprehensionClause],
clause_idx: usize,
) -> Result<(), InterpreterError> {
if clause_idx >= clauses.len() {
results.push(self.eval_expr(element)?);
return Ok(());
}
let clause = &clauses[clause_idx];
let iterable = self.eval_expr(&clause.iterable)?;
self.push_scope();
match iterable {
Value::Array(ref arr) => {
for item in arr.iter() {
self.env_set(clause.variable.clone(), item.clone());
if !self.check_comprehension_condition(clause.condition.as_deref())? {
continue;
}
self.eval_comprehension_clauses(results, element, clauses, clause_idx + 1)?;
}
}
Value::Range {
ref start,
ref end,
inclusive,
} => {
let (start_val, end_val) = self.extract_range_bounds(start, end)?;
for i in self.create_range_iterator(start_val, end_val, inclusive) {
self.env_set(clause.variable.clone(), Value::Integer(i));
if !self.check_comprehension_condition(clause.condition.as_deref())? {
continue;
}
self.eval_comprehension_clauses(results, element, clauses, clause_idx + 1)?;
}
}
_ => {
self.pop_scope();
return Err(InterpreterError::TypeError(
"List comprehension requires an iterable".to_string(),
));
}
}
self.pop_scope();
Ok(())
}
pub(crate) fn check_comprehension_condition(
&mut self,
condition: Option<&Expr>,
) -> Result<bool, InterpreterError> {
if let Some(cond) = condition {
let cond_val = self.eval_expr(cond)?;
Ok(cond_val.is_truthy())
} else {
Ok(true)
}
}
pub(crate) fn eval_spawn_actor(&mut self, actor: &Expr) -> Result<Value, InterpreterError> {
if let ExprKind::Identifier(name) = &actor.kind {
if let Ok(def_value) = self.lookup_variable(name) {
if let Value::Object(ref obj) = def_value {
if let Some(Value::String(type_str)) = obj.get("__type") {
if type_str.as_ref() == "Actor" {
let constructor_marker =
Value::from_string(format!("__actor_constructor__:{}", name));
return self.call_function(constructor_marker, &[]);
}
}
}
}
}
if let ExprKind::Call { func, args } = &actor.kind {
if let ExprKind::Identifier(name) = &func.kind {
if let Ok(def_value) = self.lookup_variable(name) {
if let Value::Object(ref obj) = def_value {
if let Some(Value::String(type_str)) = obj.get("__type") {
if type_str.as_ref() == "Actor" {
let constructor_marker =
Value::from_string(format!("__actor_constructor__:{}", name));
let arg_vals: Result<Vec<Value>, _> =
args.iter().map(|arg| self.eval_expr(arg)).collect();
let arg_vals = arg_vals?;
return self.call_function(constructor_marker, &arg_vals);
}
}
}
}
}
}
let actor_value = self.eval_expr(actor)?;
Ok(actor_value)
}
pub(crate) fn eval_actor_send(
&mut self,
actor: &Expr,
message: &Expr,
) -> Result<Value, InterpreterError> {
let actor_value = self.eval_expr(actor)?;
let message_value = self.eval_message_expr(message)?;
if let Value::ObjectMut(cell_rc) = actor_value {
self.process_actor_message_sync_mut(&cell_rc, &message_value)?;
Ok(Value::Nil)
} else {
Err(InterpreterError::RuntimeError(format!(
"ActorSend requires an actor instance, got {}",
actor_value.type_name()
)))
}
}
pub(crate) fn eval_actor_query(
&mut self,
actor: &Expr,
message: &Expr,
) -> Result<Value, InterpreterError> {
let actor_value = self.eval_expr(actor)?;
let message_value = self.eval_message_expr(message)?;
if let Value::ObjectMut(cell_rc) = actor_value {
self.process_actor_message_sync_mut(&cell_rc, &message_value)
} else {
Err(InterpreterError::RuntimeError(format!(
"ActorQuery requires an actor instance, got {}",
actor_value.type_name()
)))
}
}
pub(crate) fn extract_message_type_and_data(
message: &Value,
) -> Result<(String, Vec<Value>), InterpreterError> {
crate::runtime::eval_actor::extract_message_type_and_data(message)
}
pub(crate) fn is_control_flow_expr(expr_kind: &ExprKind) -> bool {
eval_expr::is_control_flow_expr(expr_kind)
}
pub(crate) fn is_data_structure_expr(expr_kind: &ExprKind) -> bool {
eval_expr::is_data_structure_expr(expr_kind)
}
pub(crate) fn is_assignment_expr(expr_kind: &ExprKind) -> bool {
eval_expr::is_assignment_expr(expr_kind)
}
pub(crate) fn eval_control_flow_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::If {
condition,
then_branch,
else_branch,
} => self.eval_if_expr(condition, then_branch, else_branch.as_deref()),
ExprKind::Ternary {
condition,
true_expr,
false_expr,
} => {
let cond_value = self.eval_expr(condition)?;
if cond_value.is_truthy() {
self.eval_expr(true_expr)
} else {
self.eval_expr(false_expr)
}
}
ExprKind::Let {
name, value, body, ..
} => self.eval_let_expr(name, value, body),
ExprKind::For {
label,
var,
pattern,
iter,
body,
} => self.eval_for_loop(label.as_ref(), var, pattern.as_ref(), iter, body),
ExprKind::While {
label,
condition,
body,
} => self.eval_while_loop(label.as_ref(), condition, body),
ExprKind::Loop { label, body } => self.eval_loop(label.as_ref(), body),
ExprKind::Match { expr, arms } => self.eval_match(expr, arms),
ExprKind::Break { label, value } => {
let break_val = if let Some(expr) = value {
self.eval_expr(expr)?
} else {
Value::Nil
};
Err(InterpreterError::Break(label.clone(), break_val))
}
ExprKind::Continue { label } => Err(InterpreterError::Continue(label.clone())),
ExprKind::Return { value } => self.eval_return_expr(value.as_deref()),
ExprKind::TryCatch {
try_block,
catch_clauses,
finally_block,
} => crate::runtime::eval_try_catch::eval_try_catch(
self,
try_block,
catch_clauses,
finally_block.as_deref(),
),
ExprKind::Throw { expr } => crate::runtime::eval_try_catch::eval_throw(self, expr),
ExprKind::Await { expr } => self.eval_expr(expr),
_ => unreachable!("Non-control-flow expression passed to eval_control_flow_expr"),
}
}
pub(crate) fn eval_data_structure_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::List(elements) => self.eval_list_expr(elements),
ExprKind::Block(statements) => self.eval_block_expr(statements),
ExprKind::Tuple(elements) => self.eval_tuple_expr(elements),
ExprKind::Range {
start,
end,
inclusive,
} => self.eval_range_expr(start, end, *inclusive),
ExprKind::ArrayInit { value, size } => self.eval_array_init_expr(value, size),
ExprKind::DataFrame { columns } => self.eval_dataframe_literal(columns),
_ => unreachable!("Non-data-structure expression passed to eval_data_structure_expr"),
}
}
pub(crate) fn eval_assignment_expr(
&mut self,
expr_kind: &ExprKind,
) -> Result<Value, InterpreterError> {
match expr_kind {
ExprKind::Assign { target, value } => self.eval_assign(target, value),
ExprKind::CompoundAssign { target, op, value } => {
self.eval_compound_assign(target, *op, value)
}
_ => unreachable!("Non-assignment expression passed to eval_assignment_expr"),
}
}
pub(crate) fn eval_literal(&self, lit: &Literal) -> Value {
match lit {
Literal::Integer(i, _) => Value::from_i64(*i),
Literal::Float(f) => Value::from_f64(*f),
Literal::String(s) => Value::from_string(s.clone()),
Literal::Bool(b) => Value::from_bool(*b),
Literal::Char(c) => Value::from_string(c.to_string()),
Literal::Byte(b) => Value::Byte(*b),
Literal::Unit => Value::nil(),
Literal::Null => Value::nil(),
Literal::Atom(s) => Value::Atom(s.clone()),
}
}
pub(crate) fn lookup_variable(&self, name: &str) -> Result<Value, InterpreterError> {
if name == "Option::None" {
return Ok(Value::EnumVariant {
enum_name: "Option".to_string(),
variant_name: "None".to_string(),
data: None,
});
}
if name.contains("::") {
let parts: Vec<&str> = name.split("::").collect();
if parts.len() == 2 {
let type_name = parts[0];
let method_name = parts[1];
for env_ref in self.env_stack.iter().rev() {
if let Some(value) = env_ref.borrow().get(type_name) {
if let Value::Object(ref info) = value {
if let Some(Value::String(ref type_str)) = info.get("__type") {
if type_str.as_ref() == "Class" {
if let Some(Value::Object(ref methods)) = info.get("__methods")
{
if let Some(Value::Object(ref method_meta)) =
methods.get(method_name)
{
if let Some(Value::Bool(true)) =
method_meta.get("is_static")
{
return Ok(Value::from_string(format!(
"__class_static_method__:{}:{}",
type_name, method_name
)));
}
}
}
if let Some(Value::Object(ref constructors)) =
info.get("__constructors")
{
if constructors.contains_key(method_name) {
return Ok(Value::from_string(format!(
"__class_constructor__:{}:{}",
type_name, method_name
)));
}
}
} else if type_str.as_ref() == "Struct" && method_name == "new" {
for env_ref in self.env_stack.iter().rev() {
if let Some(method_value) = env_ref.borrow().get(name) {
return Ok(method_value.clone());
}
}
return Ok(Value::from_string(format!(
"__struct_constructor__:{}",
type_name
)));
} else if type_str.as_ref() == "Actor" && method_name == "new" {
return Ok(Value::from_string(format!(
"__actor_constructor__:{}",
type_name
)));
}
}
}
}
}
}
}
if name == "JSON" {
let mut json_obj = HashMap::new();
json_obj.insert("__type".to_string(), Value::from_string("JSON".to_string()));
return Ok(Value::Object(Arc::new(json_obj)));
}
if name == "File" {
let mut file_obj = HashMap::new();
file_obj.insert("__type".to_string(), Value::from_string("File".to_string()));
return Ok(Value::Object(Arc::new(file_obj)));
}
for env_ref in self.env_stack.iter().rev() {
if let Some(value) = env_ref.borrow().get(name) {
return Ok(value.clone());
}
}
Err(InterpreterError::RuntimeError(format!(
"Undefined variable: {name}"
)))
}
#[allow(clippy::expect_used)] pub fn current_env(&self) -> &Rc<RefCell<HashMap<String, Value>>> {
self.env_stack
.last()
.expect("Environment stack should never be empty")
}
#[allow(clippy::expect_used)] pub(crate) fn env_set(&mut self, name: String, value: Value) {
self.record_variable_assignment_feedback(&name, &value);
let env_ref = self
.env_stack
.last()
.expect("Environment stack should never be empty");
env_ref.borrow_mut().insert(name, value); }
pub(crate) fn env_set_mut(&mut self, name: String, value: Value) {
self.record_variable_assignment_feedback(&name, &value);
let mut found_idx: Option<usize> = None;
for (idx, env_ref) in self.env_stack.iter().enumerate().rev() {
if env_ref.borrow().contains_key(&name) {
found_idx = Some(idx);
break;
}
}
if let Some(idx) = found_idx {
self.env_stack[idx].borrow_mut().insert(name, value);
} else {
let env_ref = self
.env_stack
.last()
.expect("Environment stack should never be empty");
env_ref.borrow_mut().insert(name, value);
}
}
pub(crate) fn env_push(&mut self, env: HashMap<String, Value>) {
self.env_stack.push(Rc::new(RefCell::new(env)));
}
pub(crate) fn env_pop(&mut self) -> Option<Rc<RefCell<HashMap<String, Value>>>> {
if self.env_stack.len() > 1 {
self.env_stack.pop()
} else {
None
}
}
pub(crate) fn eval_function_call_value(
&mut self,
func: &Value,
args: &[Value],
) -> Result<Value, InterpreterError> {
self.call_function(func.clone(), args)
}
pub(crate) fn call_function(
&mut self,
func: Value,
args: &[Value],
) -> Result<Value, InterpreterError> {
match func {
Value::String(ref s) if s.starts_with("__class_constructor__:") => {
let parts: Vec<&str> = s
.strip_prefix("__class_constructor__:")
.expect("prefix exists due to starts_with guard")
.split(':')
.collect();
if parts.len() == 2 {
let class_name = parts[0];
let constructor_name = parts[1];
self.instantiate_class_with_constructor(class_name, constructor_name, args)
} else {
self.instantiate_class_with_constructor(parts[0], "new", args)
}
}
Value::String(ref s) if s.starts_with("__class_static_method__:") => {
let parts: Vec<&str> = s
.strip_prefix("__class_static_method__:")
.expect("prefix exists due to starts_with guard")
.split(':')
.collect();
if parts.len() == 2 {
let class_name = parts[0];
let method_name = parts[1];
self.call_static_method(class_name, method_name, args)
} else {
Err(InterpreterError::RuntimeError(
"Invalid static method marker".to_string(),
))
}
}
Value::String(ref s) if s.starts_with("__struct_constructor__:") => {
let struct_name = s
.strip_prefix("__struct_constructor__:")
.expect("prefix exists due to starts_with guard");
self.instantiate_struct_with_args(struct_name, args)
}
Value::String(ref s) if s.starts_with("__actor_constructor__:") => {
let actor_name = s
.strip_prefix("__actor_constructor__:")
.expect("prefix exists due to starts_with guard");
self.instantiate_actor_with_args(actor_name, args)
}
Value::String(s) if s.starts_with("__builtin_") => {
match crate::runtime::eval_builtin::eval_builtin_function(&s, args)? {
Some(result) => Ok(result),
None => Err(InterpreterError::RuntimeError(format!(
"Unknown builtin function: {}",
s
))),
}
}
Value::Closure { params, body, env } => {
crate::runtime::eval_function::check_recursion_depth()?;
let required_count = params
.iter()
.filter(|(_, default)| default.is_none())
.count();
let total_count = params.len();
if args.len() < required_count || args.len() > total_count {
crate::runtime::eval_function::decrement_depth();
return Err(InterpreterError::RuntimeError(format!(
"Function expects {}-{} arguments, got {}",
required_count,
total_count,
args.len()
)));
}
self.env_stack.push(env);
let mut local_env = HashMap::new();
for (i, (param_name, default_value)) in params.iter().enumerate() {
let value = if i < args.len() {
args[i].clone()
} else if let Some(default_expr) = default_value {
self.eval_expr(default_expr)?
} else {
unreachable!("Missing required parameter");
};
local_env.insert(param_name.clone(), value);
}
self.env_push(local_env);
let result = match &body.kind {
crate::frontend::ast::ExprKind::Block(statements) => {
match crate::runtime::eval_control_flow_new::eval_block_expr(
statements,
|e| self.eval_expr(e),
) {
Err(InterpreterError::Return(val)) => Ok(val),
other => other,
}
}
_ => match self.eval_expr(&body) {
Err(InterpreterError::Return(val)) => Ok(val),
other => other,
},
};
self.env_pop(); self.env_pop();
crate::runtime::eval_function::decrement_depth();
result
}
Value::Object(ref obj) => {
if let Some(Value::String(type_str)) = obj.get("__type") {
match type_str.as_ref() {
"Struct" => {
if let Some(Value::String(name)) = obj.get("__name") {
self.instantiate_struct_with_args(name.as_ref(), args)
} else {
Err(InterpreterError::RuntimeError(
"Struct missing __name field".to_string(),
))
}
}
"Actor" => {
if let Some(Value::String(name)) = obj.get("__name") {
self.instantiate_actor_with_args(name.as_ref(), args)
} else {
Err(InterpreterError::RuntimeError(
"Actor missing __name field".to_string(),
))
}
}
"Class" => {
if let Some(Value::String(name)) = obj.get("__name") {
self.instantiate_class_with_args(name.as_ref(), args)
} else {
Err(InterpreterError::RuntimeError(
"Class missing __name field".to_string(),
))
}
}
_ => Err(InterpreterError::TypeError(format!(
"Cannot call object of type: {}",
type_str
))),
}
} else {
Err(InterpreterError::TypeError(format!(
"Cannot call non-function value: {}",
func.type_name()
)))
}
}
_ => Err(InterpreterError::TypeError(format!(
"Cannot call non-function value: {}",
func.type_name()
))),
}
}
pub(crate) fn eval_binary_op(
&self,
op: AstBinaryOp,
left: &Value,
right: &Value,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_operations::eval_binary_op(op, left, right)
}
pub(crate) fn eval_unary_op(
&self,
op: crate::frontend::ast::UnaryOp,
operand: &Value,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_operations::eval_unary_op(op, operand)
}
pub(crate) fn eval_binary_expr(
&mut self,
left: &Expr,
op: crate::frontend::ast::BinaryOp,
right: &Expr,
) -> Result<Value, InterpreterError> {
match op {
crate::frontend::ast::BinaryOp::Send => {
let left_val = self.eval_expr(left)?;
let message_val = self.eval_message_expr(right)?;
if let Value::ObjectMut(cell_rc) = left_val {
self.process_actor_message_sync_mut(&cell_rc, &message_val)?;
Ok(Value::Nil)
} else {
Err(InterpreterError::RuntimeError(format!(
"Send operator requires an actor instance, got {}",
left_val.type_name()
)))
}
}
crate::frontend::ast::BinaryOp::NullCoalesce => {
let left_val = self.eval_expr(left)?;
if matches!(left_val, Value::Nil) {
self.eval_expr(right)
} else {
Ok(left_val)
}
}
crate::frontend::ast::BinaryOp::And => {
let left_val = self.eval_expr(left)?;
if left_val.is_truthy() {
self.eval_expr(right)
} else {
Ok(left_val)
}
}
crate::frontend::ast::BinaryOp::Or => {
let left_val = self.eval_expr(left)?;
if left_val.is_truthy() {
Ok(left_val)
} else {
self.eval_expr(right)
}
}
crate::frontend::ast::BinaryOp::In => {
let element = self.eval_expr(left)?;
let collection = self.eval_expr(right)?;
let result = self.eval_contains(&element, &collection)?;
Ok(Value::Bool(result))
}
_ => {
let left_val = self.eval_expr(left)?;
let right_val = self.eval_expr(right)?;
let result = self.eval_binary_op(op, &left_val, &right_val)?;
let site_id = left.span.start; self.record_binary_op_feedback(site_id, &left_val, &right_val, &result);
Ok(result)
}
}
}
pub(crate) fn eval_contains(
&self,
element: &Value,
collection: &Value,
) -> Result<bool, InterpreterError> {
match collection {
Value::String(s) => {
if let Value::String(substr) = element {
Ok(s.contains(&**substr))
} else {
Err(InterpreterError::RuntimeError(
"String containment requires string element".to_string(),
))
}
}
Value::Array(items) => Ok(items.iter().any(|item| item == element)),
Value::Tuple(items) => Ok(items.iter().any(|item| item == element)),
Value::Object(map) => {
if let Value::String(key) = element {
Ok(map.contains_key(&**key))
} else {
let key_str = format!("{element}");
Ok(map.contains_key(&key_str))
}
}
_ => Err(InterpreterError::RuntimeError(format!(
"'in' operator not supported for type {}",
collection.type_name()
))),
}
}
pub(crate) fn eval_unary_expr(
&mut self,
op: crate::frontend::ast::UnaryOp,
operand: &Expr,
) -> Result<Value, InterpreterError> {
let operand_val = self.eval_expr(operand)?;
self.eval_unary_op(op, &operand_val)
}
pub(crate) fn eval_type_cast(
&mut self,
expr: &Expr,
target_type: &str,
) -> Result<Value, InterpreterError> {
if matches!(target_type, "i32" | "i64" | "isize") {
if let ExprKind::FieldAccess { object, field } = &expr.kind {
if let ExprKind::Identifier(enum_name) = &object.kind {
let variant_name = field;
if let Some(Value::Object(enum_def)) = self.get_variable(enum_name) {
if let Some(Value::Object(variants)) = enum_def.get("__variants") {
if let Some(Value::Object(variant_info)) = variants.get(variant_name) {
if let Some(Value::Integer(disc)) = variant_info.get("discriminant")
{
return Ok(Value::Integer(*disc));
}
}
}
}
}
}
}
let value = self.eval_expr(expr)?;
match (value, target_type) {
(Value::Integer(i), "f64" | "f32") => Ok(Value::Float(i as f64)),
(Value::Float(f), "i32" | "i64" | "isize") => Ok(Value::Integer(f as i64)),
(Value::Integer(i), "i32" | "i64" | "isize") => Ok(Value::Integer(i)),
(Value::Float(f), "f64" | "f32") => Ok(Value::Float(f)),
(
Value::EnumVariant {
enum_name,
variant_name,
..
},
"i32" | "i64" | "isize",
) => {
if let Some(Value::Object(enum_def)) = self.get_variable(&enum_name) {
if let Some(Value::Object(variants)) = enum_def.get("__variants") {
if let Some(Value::Object(variant_info)) = variants.get(&variant_name) {
if let Some(Value::Integer(disc)) = variant_info.get("discriminant") {
return Ok(Value::Integer(*disc));
}
}
}
}
Err(InterpreterError::TypeError(format!(
"Cannot cast enum variant {}::{} to integer: enum definition not found",
enum_name, variant_name
)))
}
(val, target) => Err(InterpreterError::TypeError(format!(
"Cannot cast {} to {}",
val.type_name(),
target
))),
}
}
pub(crate) fn eval_if_expr(
&mut self,
condition: &Expr,
then_branch: &Expr,
else_branch: Option<&Expr>,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_if_expr(
condition,
then_branch,
else_branch,
|e| self.eval_expr(e),
)
}
pub(crate) fn eval_let_expr(
&mut self,
name: &str,
value: &Expr,
body: &Expr,
) -> Result<Value, InterpreterError> {
let val = self.eval_expr(value)?;
self.env_set(name.to_string(), val.clone());
match &body.kind {
ExprKind::Literal(Literal::Unit) => Ok(val),
_ => self.eval_expr(body),
}
}
pub(crate) fn eval_return_expr(
&mut self,
value: Option<&Expr>,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_return_expr(value, |e| self.eval_expr(e))
}
pub(crate) fn eval_list_expr(&mut self, elements: &[Expr]) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_list_expr(elements, |e| self.eval_expr(e))
}
pub(crate) fn eval_array_init_expr(
&mut self,
value_expr: &Expr,
size_expr: &Expr,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_array_init_expr(value_expr, size_expr, |e| {
self.eval_expr(e)
})
}
pub(crate) fn eval_block_expr(
&mut self,
statements: &[Expr],
) -> Result<Value, InterpreterError> {
self.push_scope();
let result = crate::runtime::eval_control_flow_new::eval_block_expr(statements, |e| {
self.eval_expr(e)
});
self.pop_scope();
result
}
pub(crate) fn eval_tuple_expr(&mut self, elements: &[Expr]) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_tuple_expr(elements, |e| self.eval_expr(e))
}
pub(crate) fn eval_dataframe_literal(
&mut self,
columns: &[crate::frontend::ast::DataFrameColumn],
) -> Result<Value, InterpreterError> {
let mut evaluated_columns = Vec::new();
for col in columns {
let mut evaluated_values = Vec::new();
for value_expr in &col.values {
evaluated_values.push(self.eval_expr(value_expr)?);
}
evaluated_columns.push(DataFrameColumn {
name: col.name.clone(),
values: evaluated_values,
});
}
Ok(Value::DataFrame {
columns: evaluated_columns,
})
}
pub(crate) fn eval_range_expr(
&mut self,
start: &Expr,
end: &Expr,
inclusive: bool,
) -> Result<Value, InterpreterError> {
crate::runtime::eval_control_flow_new::eval_range_expr(start, end, inclusive, |e| {
self.eval_expr(e)
})
}
pub(crate) fn json_parse(&self, json_str: &str) -> Result<Value, InterpreterError> {
crate::runtime::eval_json::json_parse(json_str)
}
pub(crate) fn json_stringify(&self, value: &Value) -> Result<Value, InterpreterError> {
crate::runtime::eval_json::json_stringify(value)
}
pub(crate) fn serde_to_value(json: &serde_json::Value) -> Result<Value, InterpreterError> {
crate::runtime::eval_json::serde_to_value(json)
}
pub(crate) fn value_to_serde(value: &Value) -> Result<serde_json::Value, InterpreterError> {
crate::runtime::eval_json::value_to_serde(value)
}
#[cfg(test)]
pub fn eval_string(&mut self, input: &str) -> Result<Value, Box<dyn std::error::Error>> {
use crate::frontend::parser::Parser;
let mut parser = Parser::new(input);
let expr = parser.parse_expr()?;
Ok(self.eval_expr(&expr)?)
}
pub fn push(&mut self, value: Value) -> Result<(), InterpreterError> {
if self.stack.len() >= 10_000 {
return Err(InterpreterError::StackOverflow);
}
self.stack.push(value);
Ok(())
}
pub fn pop(&mut self) -> Result<Value, InterpreterError> {
self.stack.pop().ok_or(InterpreterError::StackUnderflow)
}
pub fn peek(&self, depth: usize) -> Result<Value, InterpreterError> {
let index = self
.stack
.len()
.checked_sub(depth + 1)
.ok_or(InterpreterError::StackUnderflow)?;
Ok(self.stack[index].clone())
}
pub fn binary_op(&mut self, op: BinaryOp) -> Result<(), InterpreterError> {
let right = self.pop()?;
let left = self.pop()?;
let result = match op {
BinaryOp::Add => eval_operations::eval_binary_op(AstBinaryOp::Add, &left, &right)?,
BinaryOp::Sub => eval_operations::eval_binary_op(AstBinaryOp::Subtract, &left, &right)?,
BinaryOp::Mul => eval_operations::eval_binary_op(AstBinaryOp::Multiply, &left, &right)?,
BinaryOp::Div => eval_operations::eval_binary_op(AstBinaryOp::Divide, &left, &right)?,
BinaryOp::Eq => eval_operations::eval_binary_op(AstBinaryOp::Equal, &left, &right)?,
BinaryOp::Lt => eval_operations::eval_binary_op(AstBinaryOp::Less, &left, &right)?,
BinaryOp::Gt => eval_operations::eval_binary_op(AstBinaryOp::Greater, &left, &right)?,
};
self.push(result)?;
Ok(())
}
pub fn set_variable_string(&mut self, name: String, value: Value) {
self.env_set(name, value);
}
pub(crate) fn apply_binary_op(
&self,
left: &Value,
op: AstBinaryOp,
right: &Value,
) -> Result<Value, InterpreterError> {
self.eval_binary_op(op, left, right)
}
pub(crate) fn try_pattern_match(
&self,
pattern: &Pattern,
value: &Value,
) -> Result<Option<Vec<(String, Value)>>, InterpreterError> {
crate::runtime::eval_pattern_match::try_pattern_match(pattern, value, &|lit| {
self.eval_literal(lit)
})
}
pub(crate) fn pattern_matches_internal(
&self,
pattern: &Pattern,
value: &Value,
) -> Result<bool, InterpreterError> {
crate::runtime::eval_pattern_match::pattern_matches(pattern, value, &|lit| {
self.eval_literal(lit)
})
}
pub fn push_scope(&mut self) {
let new_env = HashMap::new();
self.env_push(new_env);
}
pub fn pop_scope(&mut self) {
self.env_pop();
}
pub(crate) fn match_tuple_pattern(
&self,
patterns: &[Pattern],
value: &Value,
) -> Result<bool, InterpreterError> {
crate::runtime::eval_pattern_match::match_tuple_pattern(patterns, value, |lit| {
self.eval_literal(lit)
})
}
pub(crate) fn match_list_pattern(
&self,
patterns: &[Pattern],
value: &Value,
) -> Result<bool, InterpreterError> {
crate::runtime::eval_pattern_match::match_list_pattern(patterns, value, |lit| {
self.eval_literal(lit)
})
}
pub(crate) fn match_or_pattern(
&self,
patterns: &[Pattern],
value: &Value,
) -> Result<bool, InterpreterError> {
crate::runtime::eval_pattern_match::match_or_pattern(patterns, value, |lit| {
self.eval_literal(lit)
})
}
pub fn get_field_cached(
&mut self,
obj: &Value,
field_name: &str,
) -> Result<Value, InterpreterError> {
let cache_key = format!("{:?}::{}", obj.type_id(), field_name);
if let Some(cache) = self.field_caches.get_mut(&cache_key) {
if let Some(cached_result) = cache.lookup(obj, field_name) {
return Ok(cached_result);
}
}
let result = self.compute_field_access(obj, field_name)?;
let cache = self.field_caches.entry(cache_key).or_default();
cache.insert(obj, field_name.to_string(), result.clone());
Ok(result)
}
pub(crate) fn compute_field_access(
&self,
obj: &Value,
field_name: &str,
) -> Result<Value, InterpreterError> {
match (obj, field_name) {
(Value::String(s), "len") => Ok(Value::Integer(s.len().try_into().unwrap_or(i64::MAX))),
(Value::String(s), "to_upper") => Ok(Value::from_string(s.to_uppercase())),
(Value::String(s), "to_lower") => Ok(Value::from_string(s.to_lowercase())),
(Value::String(s), "trim") => Ok(Value::from_string(s.trim().to_string())),
(Value::Array(arr), "len") => {
Ok(Value::Integer(arr.len().try_into().unwrap_or(i64::MAX)))
}
(Value::Array(arr), "first") => arr
.first()
.cloned()
.ok_or_else(|| InterpreterError::RuntimeError("Array is empty".to_string())),
(Value::Array(arr), "last") => arr
.last()
.cloned()
.ok_or_else(|| InterpreterError::RuntimeError("Array is empty".to_string())),
(Value::Array(arr), "is_empty") => Ok(Value::from_bool(arr.is_empty())),
(obj, "type") => Ok(Value::from_string(obj.type_name().to_string())),
_ => Err(InterpreterError::RuntimeError(format!(
"Field '{}' not found on type '{}'",
field_name,
obj.type_name()
))),
}
}
pub fn get_cache_stats(&self) -> HashMap<String, f64> {
let mut stats = HashMap::new();
for (key, cache) in &self.field_caches {
stats.insert(key.clone(), cache.hit_rate());
}
stats
}
pub fn clear_caches(&mut self) {
self.field_caches.clear();
}
#[allow(dead_code)] pub(crate) fn record_binary_op_feedback(
&mut self,
site_id: usize,
left: &Value,
right: &Value,
result: &Value,
) {
self.type_feedback
.record_binary_op(site_id, left, right, result);
}
#[allow(dead_code)] pub(crate) fn record_variable_assignment_feedback(&mut self, var_name: &str, value: &Value) {
let type_id = value.type_id();
self.type_feedback
.record_variable_assignment(var_name, type_id);
}
pub(crate) fn record_function_call_feedback(
&mut self,
site_id: usize,
func_name: &str,
args: &[Value],
result: &Value,
) {
self.type_feedback
.record_function_call(site_id, func_name, args, result);
}
pub fn get_type_feedback_stats(&self) -> TypeFeedbackStats {
self.type_feedback.get_statistics()
}
pub fn get_specialization_candidates(&self) -> Vec<SpecializationCandidate> {
self.type_feedback.get_specialization_candidates()
}
pub fn clear_type_feedback(&mut self) {
self.type_feedback = TypeFeedback::new();
}
pub fn gc_track(&mut self, value: Value) -> usize {
self.gc.track_object(value)
}
pub fn gc_collect(&mut self) -> GCStats {
self.gc.force_collect()
}
pub fn gc_stats(&self) -> GCStats {
self.gc.get_stats()
}
pub fn gc_info(&self) -> GCInfo {
self.gc.get_info()
}
pub fn gc_set_threshold(&mut self, threshold: usize) {
self.gc.set_collection_threshold(threshold);
}
pub fn gc_set_auto_collect(&mut self, enabled: bool) {
self.gc.set_auto_collect(enabled);
}
pub fn gc_clear(&mut self) {
self.gc.clear();
}
pub fn gc_alloc_array(&mut self, elements: Vec<Value>) -> Value {
let array_value = Value::from_array(elements);
self.gc.track_object(array_value.clone());
array_value
}
pub fn gc_alloc_string(&mut self, content: String) -> Value {
let string_value = Value::from_string(content);
self.gc.track_object(string_value.clone());
string_value
}
pub fn gc_alloc_closure(
&mut self,
params: Vec<(String, Option<Arc<Expr>>)>, body: Arc<Expr>,
env: Rc<RefCell<HashMap<String, Value>>>, ) -> Value {
let closure_value = Value::Closure { params, body, env };
self.gc.track_object(closure_value.clone());
closure_value
}
pub fn get_global_bindings(&self) -> HashMap<String, Value> {
if let Some(global_env) = self.env_stack.first() {
global_env.borrow().clone() } else {
HashMap::new()
}
}
pub fn set_global_binding(&mut self, name: String, value: Value) {
if let Some(global_env) = self.env_stack.first() {
global_env.borrow_mut().insert(name, value); }
}
pub fn clear_user_variables(&mut self) {
if let Some(global_env) = self.env_stack.first() {
global_env
.borrow_mut()
.retain(|name, _| name.starts_with("__builtin_") || name == "nil");
}
}
pub fn get_current_bindings(&self) -> HashMap<String, Value> {
if let Some(current_env) = self.env_stack.last() {
current_env.borrow().clone() } else {
HashMap::new()
}
}
pub(crate) fn eval_string_interpolation(
&mut self,
parts: &[StringPart],
) -> Result<Value, InterpreterError> {
use crate::runtime::eval_string_interpolation::format_value_for_interpolation;
let mut result = String::new();
for part in parts {
match part {
StringPart::Text(text) => result.push_str(text),
StringPart::Expr(expr) => {
let value = self.eval_expr(expr)?;
result.push_str(&format_value_for_interpolation(&value));
}
StringPart::ExprWithFormat { expr, format_spec } => {
let value = self.eval_expr(expr)?;
let formatted = Self::format_value_with_spec(&value, format_spec);
result.push_str(&formatted);
}
}
}
Ok(Value::from_string(result))
}
pub(crate) fn format_value_with_spec(value: &Value, spec: &str) -> String {
crate::runtime::value_format::format_value_with_spec(value, spec)
}
pub fn push_error_scope(&mut self) {
self.error_scopes.push(ErrorScope {
env_depth: self.env_stack.len(),
});
}
pub fn pop_error_scope(&mut self) {
self.error_scopes.pop();
}
pub fn set_variable(&mut self, name: &str, value: Value) {
self.env_set_mut(name.to_string(), value);
}
pub fn get_variable(&self, name: &str) -> Option<Value> {
for env in self.env_stack.iter().rev() {
if let Some(value) = env.borrow().get(name) {
return Some(value.clone());
}
}
None
}
pub fn pattern_matches(
&mut self,
pattern: &Pattern,
value: &Value,
) -> Result<bool, InterpreterError> {
match pattern {
Pattern::Identifier(_) => Ok(true), Pattern::Wildcard => Ok(true),
Pattern::Literal(literal) => Ok(self.literal_matches(literal, value)),
_ => Ok(false), }
}
pub(crate) fn literal_matches(&self, literal: &Literal, value: &Value) -> bool {
match (literal, value) {
(Literal::Integer(a, _), Value::Integer(b)) => a == b,
(Literal::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
(Literal::String(a), Value::String(b)) => a == b.as_ref(),
(Literal::Bool(a), Value::Bool(b)) => a == b,
_ => false,
}
}
pub fn capture_stdout(&mut self, output: String) {
self.stdout_buffer.push(output);
}
pub fn get_stdout(&self) -> String {
self.stdout_buffer.join("\n")
}
pub fn clear_stdout(&mut self) {
self.stdout_buffer.clear();
}
pub fn has_stdout(&self) -> bool {
!self.stdout_buffer.is_empty()
}
}
impl Default for Interpreter {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub enum BinaryOp {
Add,
Sub,
Mul,
Div,
Eq,
Lt,
Gt,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frontend::ast::{Expr, ExprKind, Literal, Span, UnaryOp};
fn make_interpreter() -> Interpreter {
Interpreter::new()
}
fn make_expr(kind: ExprKind) -> Expr {
Expr {
kind,
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
}
}
#[test]
fn test_interpreter_new() {
let interp = make_interpreter();
assert!(interp.stack.is_empty());
assert_eq!(interp.env_stack.len(), 1); }
#[test]
fn test_interpreter_default() {
let interp = Interpreter::default();
assert!(interp.stack.is_empty());
}
#[test]
fn test_eval_expr_integer() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_expr_float() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Float(3.14)));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Float(3.14));
}
#[test]
fn test_eval_expr_string() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::String("hello".to_string())));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_eval_expr_bool_true() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Bool(true)));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_eval_expr_bool_false() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Bool(false)));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Bool(false));
}
#[test]
fn test_is_type_definition_struct() {
let kind = ExprKind::Struct {
name: "Point".to_string(),
type_params: vec![],
fields: vec![],
methods: vec![],
derives: vec![],
is_pub: true,
};
assert!(Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_type_definition_class() {
let kind = ExprKind::Class {
name: "MyClass".to_string(),
type_params: vec![],
superclass: None,
traits: vec![],
fields: vec![],
constructors: vec![],
methods: vec![],
constants: vec![],
properties: vec![],
derives: vec![],
decorators: vec![],
is_pub: true,
is_abstract: false,
is_sealed: false,
};
assert!(Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_type_definition_enum() {
let kind = ExprKind::Enum {
name: "Color".to_string(),
type_params: vec![],
variants: vec![],
is_pub: true,
};
assert!(Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_type_definition_actor() {
let kind = ExprKind::Actor {
name: "Counter".to_string(),
state: vec![],
handlers: vec![],
};
assert!(Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_type_definition_impl() {
let kind = ExprKind::Impl {
trait_name: None,
for_type: "Point".to_string(),
type_params: vec![],
methods: vec![],
is_pub: true,
};
assert!(Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_type_definition_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_type_definition(&kind));
}
#[test]
fn test_is_actor_operation_spawn() {
let inner = make_expr(ExprKind::Identifier("Counter".to_string()));
let kind = ExprKind::Spawn {
actor: Box::new(inner),
};
assert!(Interpreter::is_actor_operation(&kind));
}
#[test]
fn test_is_actor_operation_send() {
let actor = Box::new(make_expr(ExprKind::Identifier("counter".to_string())));
let msg = Box::new(make_expr(ExprKind::Identifier("Inc".to_string())));
let kind = ExprKind::ActorSend {
actor,
message: msg,
};
assert!(Interpreter::is_actor_operation(&kind));
}
#[test]
fn test_is_actor_operation_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_actor_operation(&kind));
}
#[test]
fn test_is_special_form_none() {
let kind = ExprKind::None;
assert!(Interpreter::is_special_form(&kind));
}
#[test]
fn test_is_special_form_some() {
let inner = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let kind = ExprKind::Some {
value: Box::new(inner),
};
assert!(Interpreter::is_special_form(&kind));
}
#[test]
fn test_is_special_form_struct_literal() {
let kind = ExprKind::StructLiteral {
name: "Point".to_string(),
fields: vec![],
base: None,
};
assert!(Interpreter::is_special_form(&kind));
}
#[test]
fn test_is_special_form_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_special_form(&kind));
}
#[test]
fn test_is_control_flow_if() {
let cond = Box::new(make_expr(ExprKind::Literal(Literal::Bool(true))));
let then_branch = Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None))));
let kind = ExprKind::If {
condition: cond,
then_branch,
else_branch: None,
};
assert!(Interpreter::is_control_flow_expr(&kind));
}
#[test]
fn test_is_control_flow_return() {
let kind = ExprKind::Return { value: None };
assert!(Interpreter::is_control_flow_expr(&kind));
}
#[test]
fn test_is_control_flow_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_control_flow_expr(&kind));
}
#[test]
fn test_is_data_structure_list() {
let kind = ExprKind::List(vec![]);
assert!(Interpreter::is_data_structure_expr(&kind));
}
#[test]
fn test_is_data_structure_tuple() {
let kind = ExprKind::Tuple(vec![]);
assert!(Interpreter::is_data_structure_expr(&kind));
}
#[test]
fn test_is_data_structure_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_data_structure_expr(&kind));
}
#[test]
fn test_is_assignment_assign() {
let target = Box::new(make_expr(ExprKind::Identifier("x".to_string())));
let value = Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None))));
let kind = ExprKind::Assign { target, value };
assert!(Interpreter::is_assignment_expr(&kind));
}
#[test]
fn test_is_assignment_false() {
let kind = ExprKind::Literal(Literal::Integer(42, None));
assert!(!Interpreter::is_assignment_expr(&kind));
}
#[test]
fn test_push_and_pop() {
let mut interp = make_interpreter();
interp.push(Value::Integer(42)).unwrap();
let result = interp.pop().unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_pop_empty_stack() {
let mut interp = make_interpreter();
let result = interp.pop();
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Stack underflow"));
}
#[test]
fn test_peek() {
let mut interp = make_interpreter();
interp.push(Value::Integer(1)).unwrap();
interp.push(Value::Integer(2)).unwrap();
let top = interp.peek(0).unwrap();
assert_eq!(top, Value::Integer(2));
let second = interp.peek(1).unwrap();
assert_eq!(second, Value::Integer(1));
}
#[test]
fn test_peek_out_of_bounds() {
let mut interp = make_interpreter();
interp.push(Value::Integer(1)).unwrap();
let result = interp.peek(5);
assert!(result.is_err());
}
#[test]
fn test_capture_stdout() {
let mut interp = make_interpreter();
interp.capture_stdout("hello".to_string());
assert!(interp.has_stdout());
assert_eq!(interp.get_stdout(), "hello");
}
#[test]
fn test_get_stdout_multiple() {
let mut interp = make_interpreter();
interp.capture_stdout("line1".to_string());
interp.capture_stdout("line2".to_string());
assert_eq!(interp.get_stdout(), "line1\nline2");
}
#[test]
fn test_clear_stdout() {
let mut interp = make_interpreter();
interp.capture_stdout("test".to_string());
interp.clear_stdout();
assert!(!interp.has_stdout());
assert_eq!(interp.get_stdout(), "");
}
#[test]
fn test_set_variable() {
let mut interp = make_interpreter();
interp.set_variable("x", Value::Integer(42));
let result = interp.lookup_variable("x").unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_lookup_variable_not_found() {
let interp = make_interpreter();
let result = interp.lookup_variable("nonexistent");
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Undefined variable"));
}
#[test]
fn test_current_env() {
let interp = make_interpreter();
let env = interp.current_env();
assert!(env.borrow().contains_key("max"));
}
#[test]
fn test_env_push_pop() {
let mut interp = make_interpreter();
let initial_depth = interp.env_stack.len();
let mut new_env = HashMap::new();
new_env.insert("local".to_string(), Value::Integer(42));
interp.env_push(new_env);
assert_eq!(interp.env_stack.len(), initial_depth + 1);
assert_eq!(interp.lookup_variable("local").unwrap(), Value::Integer(42));
interp.env_pop();
assert_eq!(interp.env_stack.len(), initial_depth);
assert!(interp.lookup_variable("local").is_err());
}
#[test]
fn test_env_set() {
let mut interp = make_interpreter();
interp.env_set("x".to_string(), Value::Integer(1));
assert_eq!(interp.lookup_variable("x").unwrap(), Value::Integer(1));
}
#[test]
fn test_env_set_mut_updates_parent() {
let mut interp = make_interpreter();
interp.set_variable("x", Value::Integer(1));
interp.env_push(HashMap::new());
interp.env_set_mut("x".to_string(), Value::Integer(2));
interp.env_pop();
assert_eq!(interp.lookup_variable("x").unwrap(), Value::Integer(2));
}
#[test]
fn test_format_string_with_values() {
let result = Interpreter::format_string_with_values(
"Hello {} and {}!",
&[Value::from_string("world".to_string()), Value::Integer(42)],
);
assert_eq!(result, "Hello world and 42!");
}
#[test]
fn test_format_string_with_values_fewer_args() {
let result = Interpreter::format_string_with_values(
"Hello {} and {}!",
&[Value::from_string("world".to_string())],
);
assert_eq!(result, "Hello world and {}!");
}
#[test]
fn test_eval_literal_unit() {
let interp = make_interpreter();
let result = interp.eval_literal(&Literal::Unit);
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_literal_char() {
let interp = make_interpreter();
let result = interp.eval_literal(&Literal::Char('a'));
assert_eq!(result, Value::from_string("a".to_string()));
}
#[test]
fn test_eval_list_expr() {
let mut interp = make_interpreter();
let elements = vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
];
let result = interp.eval_list_expr(&elements).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 2);
assert_eq!(arr[0], Value::Integer(1));
assert_eq!(arr[1], Value::Integer(2));
} else {
panic!("Expected Array");
}
}
#[test]
fn test_eval_tuple_expr() {
let mut interp = make_interpreter();
let elements = vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::String("hello".to_string()))),
];
let result = interp.eval_tuple_expr(&elements).unwrap();
if let Value::Tuple(tuple) = result {
assert_eq!(tuple.len(), 2);
} else {
panic!("Expected Tuple");
}
}
#[test]
fn test_eval_block_expr_empty() {
let mut interp = make_interpreter();
let result = interp.eval_block_expr(&[]).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_block_expr_single() {
let mut interp = make_interpreter();
let stmts = vec![make_expr(ExprKind::Literal(Literal::Integer(42, None)))];
let result = interp.eval_block_expr(&stmts).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_return_expr_with_value() {
let mut interp = make_interpreter();
let val_expr = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp.eval_return_expr(Some(&val_expr));
match result {
Err(InterpreterError::Return(v)) => assert_eq!(v, Value::Integer(42)),
_ => panic!("Expected Return error"),
}
}
#[test]
fn test_eval_return_expr_without_value() {
let mut interp = make_interpreter();
let result = interp.eval_return_expr(None);
match result {
Err(InterpreterError::Return(v)) => assert_eq!(v, Value::Nil),
_ => panic!("Expected Return error"),
}
}
#[test]
fn test_eval_string_simple() {
let mut interp = make_interpreter();
let result = interp.eval_string("42").unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_string_expression() {
let mut interp = make_interpreter();
let result = interp.eval_string("2 + 3").unwrap();
assert_eq!(result, Value::Integer(5));
}
#[test]
fn test_json_parse_object() {
let interp = make_interpreter();
let result = interp.json_parse(r#"{"a": 1}"#).unwrap();
if let Value::Object(obj) = result {
assert_eq!(obj.get("a"), Some(&Value::Integer(1)));
} else {
panic!("Expected Object");
}
}
#[test]
fn test_json_parse_array() {
let interp = make_interpreter();
let result = interp.json_parse("[1, 2, 3]").unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 3);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_json_stringify() {
let interp = make_interpreter();
let result = interp.json_stringify(&Value::Integer(42)).unwrap();
assert_eq!(result, Value::from_string("42".to_string()));
}
#[test]
fn test_serde_to_value_null() {
let result = Interpreter::serde_to_value(&serde_json::Value::Null).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_serde_to_value_bool() {
let result = Interpreter::serde_to_value(&serde_json::Value::Bool(true)).unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_serde_to_value_number_int() {
let result = Interpreter::serde_to_value(&serde_json::json!(42)).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_serde_to_value_number_float() {
let result = Interpreter::serde_to_value(&serde_json::json!(3.14)).unwrap();
assert_eq!(result, Value::Float(3.14));
}
#[test]
fn test_serde_to_value_string() {
let result = Interpreter::serde_to_value(&serde_json::json!("hello")).unwrap();
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_value_to_serde_nil() {
let result = Interpreter::value_to_serde(&Value::Nil).unwrap();
assert_eq!(result, serde_json::Value::Null);
}
#[test]
fn test_value_to_serde_bool() {
let result = Interpreter::value_to_serde(&Value::Bool(true)).unwrap();
assert_eq!(result, serde_json::Value::Bool(true));
}
#[test]
fn test_value_to_serde_integer() {
let result = Interpreter::value_to_serde(&Value::Integer(42)).unwrap();
assert_eq!(result, serde_json::json!(42));
}
#[test]
fn test_value_to_serde_float() {
let result = Interpreter::value_to_serde(&Value::Float(3.14)).unwrap();
assert_eq!(result, serde_json::json!(3.14));
}
#[test]
fn test_value_to_serde_string() {
let result = Interpreter::value_to_serde(&Value::from_string("hello".to_string())).unwrap();
assert_eq!(result, serde_json::json!("hello"));
}
#[test]
fn test_eval_contains_array_found() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.eval_contains(&Value::Integer(1), &arr).unwrap();
assert!(result);
}
#[test]
fn test_eval_contains_array_not_found() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.eval_contains(&Value::Integer(3), &arr).unwrap();
assert!(!result);
}
#[test]
fn test_eval_contains_string_found() {
let interp = make_interpreter();
let s = Value::from_string("hello world".to_string());
let result = interp
.eval_contains(&Value::from_string("world".to_string()), &s)
.unwrap();
assert!(result);
}
#[test]
fn test_eval_contains_string_not_found() {
let interp = make_interpreter();
let s = Value::from_string("hello world".to_string());
let result = interp
.eval_contains(&Value::from_string("foo".to_string()), &s)
.unwrap();
assert!(!result);
}
#[test]
fn test_eval_range_expr_exclusive() {
let mut interp = make_interpreter();
let start = make_expr(ExprKind::Literal(Literal::Integer(0, None)));
let end = make_expr(ExprKind::Literal(Literal::Integer(5, None)));
let result = interp.eval_range_expr(&start, &end, false).unwrap();
if let Value::Range {
start: s,
end: e,
inclusive,
} = result
{
assert_eq!(*s, Value::Integer(0));
assert_eq!(*e, Value::Integer(5));
assert!(!inclusive);
} else {
panic!("Expected Range");
}
}
#[test]
fn test_eval_range_expr_inclusive() {
let mut interp = make_interpreter();
let start = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let end = make_expr(ExprKind::Literal(Literal::Integer(10, None)));
let result = interp.eval_range_expr(&start, &end, true).unwrap();
if let Value::Range {
start: s,
end: e,
inclusive,
} = result
{
assert_eq!(*s, Value::Integer(1));
assert_eq!(*e, Value::Integer(10));
assert!(inclusive);
} else {
panic!("Expected Range");
}
}
#[test]
fn test_gc_track() {
let mut interp = make_interpreter();
let id = interp.gc_track(Value::Integer(42));
assert!(id >= 0);
}
#[test]
fn test_gc_collect() {
let mut interp = make_interpreter();
interp.gc_track(Value::Integer(1));
interp.gc_track(Value::Integer(2));
let stats = interp.gc_collect();
let _ = stats.collections; }
#[test]
fn test_gc_stats() {
let interp = make_interpreter();
let stats = interp.gc_stats();
let _ = stats.collections; }
#[test]
fn test_gc_info() {
let interp = make_interpreter();
let info = interp.gc_info();
let _ = info.tracked_count; }
#[test]
fn test_gc_set_threshold() {
let mut interp = make_interpreter();
interp.gc_set_threshold(1000);
}
#[test]
fn test_gc_set_auto_collect() {
let mut interp = make_interpreter();
interp.gc_set_auto_collect(false);
interp.gc_set_auto_collect(true);
}
#[test]
fn test_gc_clear() {
let mut interp = make_interpreter();
interp.gc_track(Value::Integer(1));
interp.gc_clear();
}
#[test]
fn test_gc_alloc_array() {
let mut interp = make_interpreter();
let arr = interp.gc_alloc_array(vec![Value::Integer(1), Value::Integer(2)]);
if let Value::Array(a) = arr {
assert_eq!(a.len(), 2);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_gc_alloc_string() {
let mut interp = make_interpreter();
let s = interp.gc_alloc_string("hello".to_string());
assert_eq!(s, Value::from_string("hello".to_string()));
}
#[test]
fn test_gc_alloc_closure() {
let mut interp = make_interpreter();
let body = Arc::new(make_expr(ExprKind::Literal(Literal::Integer(42, None))));
let env = Rc::new(RefCell::new(HashMap::new()));
let closure = interp.gc_alloc_closure(vec![("x".to_string(), None)], body, env);
assert!(matches!(closure, Value::Closure { .. }));
}
#[test]
fn test_get_field_cached_string_len() {
let mut interp = make_interpreter();
let s = Value::from_string("hello".to_string());
let result = interp.get_field_cached(&s, "len").unwrap();
assert_eq!(result, Value::Integer(5));
}
#[test]
fn test_get_field_cached_string_to_upper() {
let mut interp = make_interpreter();
let s = Value::from_string("hello".to_string());
let result = interp.get_field_cached(&s, "to_upper").unwrap();
assert_eq!(result, Value::from_string("HELLO".to_string()));
}
#[test]
fn test_compute_field_access_string_to_lower() {
let interp = make_interpreter();
let s = Value::from_string("HELLO".to_string());
let result = interp.compute_field_access(&s, "to_lower").unwrap();
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_compute_field_access_string_trim() {
let interp = make_interpreter();
let s = Value::from_string(" hello ".to_string());
let result = interp.compute_field_access(&s, "trim").unwrap();
assert_eq!(result, Value::from_string("hello".to_string()));
}
#[test]
fn test_compute_field_access_array_len() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.compute_field_access(&arr, "len").unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_compute_field_access_array_first() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.compute_field_access(&arr, "first").unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_compute_field_access_array_last() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.compute_field_access(&arr, "last").unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_compute_field_access_array_is_empty() {
let interp = make_interpreter();
let arr = Value::Array(Arc::from(vec![]));
let result = interp.compute_field_access(&arr, "is_empty").unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_compute_field_access_type() {
let interp = make_interpreter();
let result = interp
.compute_field_access(&Value::Integer(42), "type")
.unwrap();
assert_eq!(result, Value::from_string("integer".to_string()));
}
#[test]
fn test_compute_field_access_unknown_field() {
let interp = make_interpreter();
let result = interp.compute_field_access(&Value::Integer(42), "unknown");
assert!(result.is_err());
}
#[test]
fn test_get_cache_stats() {
let mut interp = make_interpreter();
let s = Value::from_string("test".to_string());
let _ = interp.get_field_cached(&s, "len");
let stats = interp.get_cache_stats();
assert!(!stats.is_empty());
}
#[test]
fn test_clear_caches() {
let mut interp = make_interpreter();
let s = Value::from_string("test".to_string());
let _ = interp.get_field_cached(&s, "len");
interp.clear_caches();
assert!(interp.get_cache_stats().is_empty());
}
#[test]
fn test_record_binary_op_feedback() {
let mut interp = make_interpreter();
interp.record_binary_op_feedback(
0,
&Value::Integer(1),
&Value::Integer(2),
&Value::Integer(3),
);
}
#[test]
fn test_record_variable_assignment_feedback() {
let mut interp = make_interpreter();
interp.record_variable_assignment_feedback("x", &Value::Integer(42));
}
#[test]
fn test_record_function_call_feedback() {
let mut interp = make_interpreter();
interp.record_function_call_feedback(0, "test", &[Value::Integer(1)], &Value::Integer(2));
}
#[test]
fn test_get_type_feedback_stats() {
let mut interp = make_interpreter();
interp.record_binary_op_feedback(
0,
&Value::Integer(1),
&Value::Integer(2),
&Value::Integer(3),
);
let stats = interp.get_type_feedback_stats();
let _ = stats.total_operation_sites; }
#[test]
fn test_get_specialization_candidates() {
let interp = make_interpreter();
let candidates = interp.get_specialization_candidates();
let _ = candidates.len();
}
#[test]
fn test_clear_type_feedback() {
let mut interp = make_interpreter();
interp.record_binary_op_feedback(
0,
&Value::Integer(1),
&Value::Integer(2),
&Value::Integer(3),
);
interp.clear_type_feedback();
}
#[test]
fn test_push_pop_error_scope() {
let mut interp = make_interpreter();
interp.push_error_scope();
interp.pop_error_scope();
}
#[test]
fn test_get_global_bindings() {
let interp = make_interpreter();
let bindings = interp.get_global_bindings();
assert!(bindings.contains_key("max"));
}
#[test]
fn test_set_global_binding() {
let mut interp = make_interpreter();
interp.set_global_binding("test_var".to_string(), Value::Integer(42));
let bindings = interp.get_global_bindings();
assert_eq!(bindings.get("test_var"), Some(&Value::Integer(42)));
}
#[test]
fn test_clear_user_variables() {
let mut interp = make_interpreter();
interp.set_global_binding("test_var".to_string(), Value::Integer(42));
interp.clear_user_variables();
let bindings = interp.get_global_bindings();
assert!(!bindings.contains_key("test_var"));
}
#[test]
fn test_get_current_bindings() {
let mut interp = make_interpreter();
interp.push_scope();
interp.env_set("local_var".to_string(), Value::Integer(100));
let bindings = interp.get_current_bindings();
assert_eq!(bindings.get("local_var"), Some(&Value::Integer(100)));
interp.pop_scope();
}
#[test]
fn test_binary_op_add() {
let mut interp = make_interpreter();
interp.push(Value::Integer(2)).unwrap();
interp.push(Value::Integer(3)).unwrap();
interp.binary_op(BinaryOp::Add).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Integer(5));
}
#[test]
fn test_binary_op_sub() {
let mut interp = make_interpreter();
interp.push(Value::Integer(10)).unwrap();
interp.push(Value::Integer(3)).unwrap();
interp.binary_op(BinaryOp::Sub).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Integer(7));
}
#[test]
fn test_binary_op_mul() {
let mut interp = make_interpreter();
interp.push(Value::Integer(4)).unwrap();
interp.push(Value::Integer(5)).unwrap();
interp.binary_op(BinaryOp::Mul).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Integer(20));
}
#[test]
fn test_binary_op_div() {
let mut interp = make_interpreter();
interp.push(Value::Integer(20)).unwrap();
interp.push(Value::Integer(4)).unwrap();
interp.binary_op(BinaryOp::Div).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Integer(5));
}
#[test]
fn test_binary_op_eq() {
let mut interp = make_interpreter();
interp.push(Value::Integer(5)).unwrap();
interp.push(Value::Integer(5)).unwrap();
interp.binary_op(BinaryOp::Eq).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Bool(true));
}
#[test]
fn test_binary_op_lt() {
let mut interp = make_interpreter();
interp.push(Value::Integer(3)).unwrap();
interp.push(Value::Integer(5)).unwrap();
interp.binary_op(BinaryOp::Lt).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Bool(true));
}
#[test]
fn test_binary_op_gt() {
let mut interp = make_interpreter();
interp.push(Value::Integer(10)).unwrap();
interp.push(Value::Integer(5)).unwrap();
interp.binary_op(BinaryOp::Gt).unwrap();
assert_eq!(interp.pop().unwrap(), Value::Bool(true));
}
#[test]
fn test_apply_binary_op() {
let interp = make_interpreter();
let result = interp
.apply_binary_op(&Value::Integer(2), AstBinaryOp::Add, &Value::Integer(3))
.unwrap();
assert_eq!(result, Value::Integer(5));
}
#[test]
fn test_pattern_matches_identifier() {
let mut interp = make_interpreter();
let pattern = Pattern::Identifier("x".to_string());
let result = interp
.pattern_matches(&pattern, &Value::Integer(42))
.unwrap();
assert!(result);
}
#[test]
fn test_pattern_matches_wildcard() {
let mut interp = make_interpreter();
let pattern = Pattern::Wildcard;
let result = interp
.pattern_matches(&pattern, &Value::Integer(42))
.unwrap();
assert!(result);
}
#[test]
fn test_pattern_matches_literal_int() {
let mut interp = make_interpreter();
let pattern = Pattern::Literal(Literal::Integer(42, None));
let result = interp
.pattern_matches(&pattern, &Value::Integer(42))
.unwrap();
assert!(result);
}
#[test]
fn test_pattern_matches_literal_int_mismatch() {
let mut interp = make_interpreter();
let pattern = Pattern::Literal(Literal::Integer(42, None));
let result = interp
.pattern_matches(&pattern, &Value::Integer(99))
.unwrap();
assert!(!result);
}
#[test]
fn test_literal_matches_float() {
let interp = make_interpreter();
let result = interp.literal_matches(&Literal::Float(3.14), &Value::Float(3.14));
assert!(result);
}
#[test]
fn test_literal_matches_string() {
let interp = make_interpreter();
let result = interp.literal_matches(
&Literal::String("hello".to_string()),
&Value::from_string("hello".to_string()),
);
assert!(result);
}
#[test]
fn test_literal_matches_bool() {
let interp = make_interpreter();
let result = interp.literal_matches(&Literal::Bool(true), &Value::Bool(true));
assert!(result);
}
#[test]
fn test_try_pattern_match_identifier() {
let interp = make_interpreter();
let pattern = Pattern::Identifier("x".to_string());
let result = interp
.try_pattern_match(&pattern, &Value::Integer(42))
.unwrap();
assert!(result.is_some());
let bindings = result.unwrap();
assert_eq!(bindings.len(), 1);
assert_eq!(bindings[0], ("x".to_string(), Value::Integer(42)));
}
#[test]
fn test_pattern_matches_internal() {
let interp = make_interpreter();
let pattern = Pattern::Wildcard;
let result = interp
.pattern_matches_internal(&pattern, &Value::Integer(42))
.unwrap();
assert!(result);
}
#[test]
fn test_push_pop_scope() {
let mut interp = make_interpreter();
let initial_depth = interp.env_stack.len();
interp.push_scope();
assert_eq!(interp.env_stack.len(), initial_depth + 1);
interp.pop_scope();
assert_eq!(interp.env_stack.len(), initial_depth);
}
#[test]
fn test_lookup_option_none() {
let interp = make_interpreter();
let result = interp.lookup_variable("Option::None").unwrap();
if let Value::EnumVariant {
enum_name,
variant_name,
..
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "None");
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_lookup_json_global() {
let interp = make_interpreter();
let result = interp.lookup_variable("JSON").unwrap();
if let Value::Object(obj) = result {
assert_eq!(
obj.get("__type"),
Some(&Value::from_string("JSON".to_string()))
);
} else {
panic!("Expected Object");
}
}
#[test]
fn test_lookup_file_global() {
let interp = make_interpreter();
let result = interp.lookup_variable("File").unwrap();
if let Value::Object(obj) = result {
assert_eq!(
obj.get("__type"),
Some(&Value::from_string("File".to_string()))
);
} else {
panic!("Expected Object");
}
}
#[test]
fn test_get_variable_found() {
let mut interp = make_interpreter();
interp.set_variable("test", Value::Integer(42));
assert_eq!(interp.get_variable("test"), Some(Value::Integer(42)));
}
#[test]
fn test_get_variable_not_found() {
let interp = make_interpreter();
assert_eq!(interp.get_variable("nonexistent"), None);
}
#[test]
fn test_eval_contains_tuple() {
let interp = make_interpreter();
let tuple = Value::Tuple(Arc::from(vec![Value::Integer(1), Value::Integer(2)]));
let result = interp.eval_contains(&Value::Integer(1), &tuple).unwrap();
assert!(result);
}
#[test]
fn test_eval_contains_object_key_string() {
let interp = make_interpreter();
let mut map = HashMap::new();
map.insert("key".to_string(), Value::Integer(1));
let obj = Value::Object(Arc::new(map));
let result = interp
.eval_contains(&Value::from_string("key".to_string()), &obj)
.unwrap();
assert!(result);
}
#[test]
fn test_eval_contains_object_key_nonstring() {
let interp = make_interpreter();
let mut map = HashMap::new();
map.insert("42".to_string(), Value::Integer(1));
let obj = Value::Object(Arc::new(map));
let result = interp.eval_contains(&Value::Integer(42), &obj).unwrap();
assert!(result);
}
#[test]
fn test_eval_contains_unsupported() {
let interp = make_interpreter();
let result = interp.eval_contains(&Value::Integer(1), &Value::Integer(42));
assert!(result.is_err());
}
#[test]
fn test_eval_contains_string_invalid_element() {
let interp = make_interpreter();
let s = Value::from_string("hello".to_string());
let result = interp.eval_contains(&Value::Integer(1), &s);
assert!(result.is_err());
}
#[test]
fn test_eval_literal_byte() {
let interp = make_interpreter();
let result = interp.eval_literal(&Literal::Byte(42));
assert_eq!(result, Value::Byte(42));
}
#[test]
fn test_eval_literal_null() {
let interp = make_interpreter();
let result = interp.eval_literal(&Literal::Null);
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_literal_atom() {
let interp = make_interpreter();
let result = interp.eval_literal(&Literal::Atom("test".to_string()));
assert_eq!(result, Value::Atom("test".to_string()));
}
#[test]
fn test_has_stdout_empty() {
let interp = make_interpreter();
assert!(!interp.has_stdout());
}
#[test]
fn test_set_variable_string() {
let mut interp = make_interpreter();
interp.set_variable_string("x".to_string(), Value::Integer(42));
assert_eq!(interp.lookup_variable("x").unwrap(), Value::Integer(42));
}
#[test]
fn test_eval_function_call_value() {
let mut interp = make_interpreter();
let body = Arc::new(make_expr(ExprKind::Literal(Literal::Integer(42, None))));
let env = Rc::new(RefCell::new(HashMap::new()));
let closure = Value::Closure {
params: vec![],
body,
env,
};
let result = interp.eval_function_call_value(&closure, &[]).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_dataframe_literal() {
use crate::frontend::ast::DataFrameColumn as AstDFColumn;
let mut interp = make_interpreter();
let columns = vec![AstDFColumn {
name: "x".to_string(),
values: vec![make_expr(ExprKind::Literal(Literal::Integer(1, None)))],
}];
let result = interp.eval_dataframe_literal(&columns).unwrap();
assert!(matches!(result, Value::DataFrame { .. }));
}
#[test]
fn test_push_stack_overflow() {
let mut interp = make_interpreter();
for i in 0..10_000 {
interp.push(Value::Integer(i as i64)).unwrap();
}
let result = interp.push(Value::Integer(0));
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Stack overflow"));
}
#[test]
fn test_eval_array_init_expr() {
let mut interp = make_interpreter();
let value_expr = make_expr(ExprKind::Literal(Literal::Integer(0, None)));
let size_expr = make_expr(ExprKind::Literal(Literal::Integer(5, None)));
let result = interp
.eval_array_init_expr(&value_expr, &size_expr)
.unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 5);
for v in arr.iter() {
assert_eq!(*v, Value::Integer(0));
}
} else {
panic!("Expected Array");
}
}
#[test]
fn test_eval_special_form_none() {
let mut interp = make_interpreter();
let kind = ExprKind::None;
let result = interp.eval_special_form(&kind).unwrap();
if let Value::EnumVariant {
enum_name,
variant_name,
data,
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "None");
assert!(data.is_none());
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_eval_special_form_some() {
let mut interp = make_interpreter();
let inner = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let kind = ExprKind::Some {
value: Box::new(inner),
};
let result = interp.eval_special_form(&kind).unwrap();
if let Value::EnumVariant {
enum_name,
variant_name,
data,
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "Some");
assert!(data.is_some());
let values = data.unwrap();
assert_eq!(values[0], Value::Integer(42));
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_eval_special_form_set_empty() {
let mut interp = make_interpreter();
let kind = ExprKind::Set(vec![]);
let result = interp.eval_special_form(&kind).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_special_form_set_with_statements() {
let mut interp = make_interpreter();
let kind = ExprKind::Set(vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
]);
let result = interp.eval_special_form(&kind).unwrap();
assert_eq!(result, Value::Integer(2)); }
#[test]
fn test_eval_special_form_object_literal() {
use crate::frontend::ast::ObjectField;
let mut interp = make_interpreter();
let kind = ExprKind::ObjectLiteral {
fields: vec![ObjectField::KeyValue {
key: "x".to_string(),
value: make_expr(ExprKind::Literal(Literal::Integer(1, None))),
}],
};
let result = interp.eval_special_form(&kind).unwrap();
if let Value::Object(obj) = result {
assert_eq!(obj.get("x"), Some(&Value::Integer(1)));
} else {
panic!("Expected Object");
}
}
#[test]
fn test_resolve_module_path_not_found() {
let interp = make_interpreter();
let result = interp.resolve_module_path("nonexistent::module");
assert!(result.is_none());
}
#[test]
fn test_resolve_module_path_std() {
let interp = make_interpreter();
let result = interp.resolve_module_path("std");
assert!(result.is_some());
}
#[test]
fn test_eval_type_cast_int_to_float() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp.eval_type_cast(&expr, "f64").unwrap();
assert_eq!(result, Value::Float(42.0));
}
#[test]
fn test_eval_type_cast_float_to_int() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Float(3.9)));
let result = interp.eval_type_cast(&expr, "i64").unwrap();
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_eval_type_cast_int_to_int() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp.eval_type_cast(&expr, "i32").unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_type_cast_float_to_float() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::Float(3.14)));
let result = interp.eval_type_cast(&expr, "f32").unwrap();
assert_eq!(result, Value::Float(3.14));
}
#[test]
fn test_eval_type_cast_unsupported() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Literal(Literal::String("hello".to_string())));
let result = interp.eval_type_cast(&expr, "i32");
assert!(result.is_err());
}
#[test]
fn test_call_function_closure_no_args() {
let mut interp = make_interpreter();
let body = Arc::new(make_expr(ExprKind::Literal(Literal::Integer(42, None))));
let env = Rc::new(RefCell::new(HashMap::new()));
let closure = Value::Closure {
params: vec![],
body,
env,
};
let result = interp.call_function(closure, &[]).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_call_function_closure_with_args() {
let mut interp = make_interpreter();
let body = Arc::new(make_expr(ExprKind::Identifier("x".to_string())));
let env = Rc::new(RefCell::new(HashMap::new()));
let closure = Value::Closure {
params: vec![("x".to_string(), None)],
body,
env,
};
let result = interp
.call_function(closure, &[Value::Integer(42)])
.unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_call_function_wrong_arg_count() {
let mut interp = make_interpreter();
let body = Arc::new(make_expr(ExprKind::Literal(Literal::Integer(42, None))));
let env = Rc::new(RefCell::new(HashMap::new()));
let closure = Value::Closure {
params: vec![("x".to_string(), None)],
body,
env,
};
let result = interp.call_function(closure, &[]); assert!(result.is_err());
}
#[test]
fn test_call_function_non_callable() {
let mut interp = make_interpreter();
let result = interp.call_function(Value::Integer(42), &[]);
assert!(result.is_err());
}
#[test]
fn test_eval_binary_expr_null_coalesce_nil() {
let mut interp = make_interpreter();
let left = make_expr(ExprKind::Literal(Literal::Null));
let right = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp
.eval_binary_expr(&left, AstBinaryOp::NullCoalesce, &right)
.unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_binary_expr_null_coalesce_not_nil() {
let mut interp = make_interpreter();
let left = make_expr(ExprKind::Literal(Literal::Integer(10, None)));
let right = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp
.eval_binary_expr(&left, AstBinaryOp::NullCoalesce, &right)
.unwrap();
assert_eq!(result, Value::Integer(10));
}
#[test]
fn test_eval_binary_expr_and_short_circuit() {
let mut interp = make_interpreter();
let left = make_expr(ExprKind::Literal(Literal::Bool(false)));
let right = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp
.eval_binary_expr(&left, AstBinaryOp::And, &right)
.unwrap();
assert_eq!(result, Value::Bool(false));
}
#[test]
fn test_eval_binary_expr_or_short_circuit() {
let mut interp = make_interpreter();
let left = make_expr(ExprKind::Literal(Literal::Bool(true)));
let right = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp
.eval_binary_expr(&left, AstBinaryOp::Or, &right)
.unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_eval_binary_expr_in_array() {
let mut interp = make_interpreter();
let element = make_expr(ExprKind::Literal(Literal::Integer(2, None)));
let collection = make_expr(ExprKind::List(vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
make_expr(ExprKind::Literal(Literal::Integer(3, None))),
]));
let result = interp
.eval_binary_expr(&element, AstBinaryOp::In, &collection)
.unwrap();
assert_eq!(result, Value::Bool(true));
}
#[test]
fn test_eval_unary_expr_negate() {
let mut interp = make_interpreter();
let operand = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let result = interp.eval_unary_expr(UnaryOp::Negate, &operand).unwrap();
assert_eq!(result, Value::Integer(-42));
}
#[test]
fn test_eval_unary_expr_not() {
let mut interp = make_interpreter();
let operand = make_expr(ExprKind::Literal(Literal::Bool(true)));
let result = interp.eval_unary_expr(UnaryOp::Not, &operand).unwrap();
assert_eq!(result, Value::Bool(false));
}
#[test]
fn test_eval_if_expr_true_branch() {
let mut interp = make_interpreter();
let cond = make_expr(ExprKind::Literal(Literal::Bool(true)));
let then_branch = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let else_branch = make_expr(ExprKind::Literal(Literal::Integer(2, None)));
let result = interp
.eval_if_expr(&cond, &then_branch, Some(&else_branch))
.unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_eval_if_expr_false_branch() {
let mut interp = make_interpreter();
let cond = make_expr(ExprKind::Literal(Literal::Bool(false)));
let then_branch = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let else_branch = make_expr(ExprKind::Literal(Literal::Integer(2, None)));
let result = interp
.eval_if_expr(&cond, &then_branch, Some(&else_branch))
.unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_eval_if_expr_no_else() {
let mut interp = make_interpreter();
let cond = make_expr(ExprKind::Literal(Literal::Bool(false)));
let then_branch = make_expr(ExprKind::Literal(Literal::Integer(1, None)));
let result = interp.eval_if_expr(&cond, &then_branch, None).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_let_expr() {
let mut interp = make_interpreter();
let value = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let body = make_expr(ExprKind::Identifier("x".to_string()));
let result = interp.eval_let_expr("x", &value, &body).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_let_expr_unit_body() {
let mut interp = make_interpreter();
let value = make_expr(ExprKind::Literal(Literal::Integer(42, None)));
let body = make_expr(ExprKind::Literal(Literal::Unit));
let result = interp.eval_let_expr("x", &value, &body).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_eval_block_expr_multiple() {
let mut interp = make_interpreter();
let stmts = vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
make_expr(ExprKind::Literal(Literal::Integer(3, None))),
];
let result = interp.eval_block_expr(&stmts).unwrap();
assert_eq!(result, Value::Integer(3)); }
#[test]
fn test_eval_string_interpolation_text_only() {
use crate::frontend::ast::StringPart;
let mut interp = make_interpreter();
let parts = vec![StringPart::Text("hello world".to_string())];
let result = interp.eval_string_interpolation(&parts).unwrap();
assert_eq!(result, Value::from_string("hello world".to_string()));
}
#[test]
fn test_eval_string_interpolation_with_expr() {
use crate::frontend::ast::StringPart;
let mut interp = make_interpreter();
interp.set_variable("x", Value::Integer(42));
let parts = vec![
StringPart::Text("x = ".to_string()),
StringPart::Expr(Box::new(make_expr(ExprKind::Identifier("x".to_string())))),
];
let result = interp.eval_string_interpolation(&parts).unwrap();
assert_eq!(result, Value::from_string("x = 42".to_string()));
}
#[test]
fn test_eval_vec_macro() {
let mut interp = make_interpreter();
let result = interp.eval_string("vec![1, 2, 3]").unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 3);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_eval_list_comprehension_simple() {
use crate::frontend::ast::ComprehensionClause;
let mut interp = make_interpreter();
let element = make_expr(ExprKind::Identifier("x".to_string()));
let clauses = vec![ComprehensionClause {
variable: "x".to_string(),
iterable: Box::new(make_expr(ExprKind::List(vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
]))),
condition: None,
}];
let result = interp.eval_list_comprehension(&element, &clauses).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 2);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_check_comprehension_condition_none() {
let mut interp = make_interpreter();
let result = interp.check_comprehension_condition(None).unwrap();
assert!(result);
}
#[test]
fn test_check_comprehension_condition_true() {
let mut interp = make_interpreter();
let cond = make_expr(ExprKind::Literal(Literal::Bool(true)));
let result = interp.check_comprehension_condition(Some(&cond)).unwrap();
assert!(result);
}
#[test]
fn test_check_comprehension_condition_false() {
let mut interp = make_interpreter();
let cond = make_expr(ExprKind::Literal(Literal::Bool(false)));
let result = interp.check_comprehension_condition(Some(&cond)).unwrap();
assert!(!result);
}
#[test]
fn test_vec_macro_empty() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "vec".to_string(),
args: vec![],
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 0);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_vec_macro_with_elements() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "vec".to_string(),
args: vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
make_expr(ExprKind::Literal(Literal::Integer(3, None))),
],
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 3);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_format_macro_simple() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![make_expr(ExprKind::Literal(Literal::String(
"hello".to_string(),
)))],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(matches!(result, Value::String(_)));
}
#[test]
fn test_format_macro_with_placeholder() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![
make_expr(ExprKind::Literal(Literal::String("x = {}".to_string()))),
make_expr(ExprKind::Literal(Literal::Integer(42, None))),
],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(matches!(result, Value::String(_)));
let result_str = result.to_string();
assert!(result_str.contains("42"));
}
#[test]
fn test_format_macro_empty_error() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![],
});
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_format_macro_debug_placeholder() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![
make_expr(ExprKind::Literal(Literal::String("val = {:?}".to_string()))),
make_expr(ExprKind::Literal(Literal::Integer(5, None))),
],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(result.to_string().contains("5") || result.to_string().contains("Integer"));
}
#[test]
fn test_unknown_macro_error() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "unknown_macro".to_string(),
args: vec![],
});
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_ternary_true() {
let mut interp = make_interpreter();
let expr = Expr {
kind: ExprKind::Ternary {
condition: Box::new(make_expr(ExprKind::Literal(Literal::Bool(true)))),
true_expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
false_expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(2, None)))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_ternary_false() {
let mut interp = make_interpreter();
let expr = Expr {
kind: ExprKind::Ternary {
condition: Box::new(make_expr(ExprKind::Literal(Literal::Bool(false)))),
true_expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
false_expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(2, None)))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_break_with_value() {
let mut interp = make_interpreter();
let expr = Expr {
kind: ExprKind::Break {
label: None,
value: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
42, None,
))))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr);
assert!(matches!(
result,
Err(InterpreterError::Break(None, Value::Integer(42)))
));
}
#[test]
fn test_break_with_label() {
let mut interp = make_interpreter();
let expr = Expr {
kind: ExprKind::Break {
label: Some("outer".to_string()),
value: None,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr);
assert!(matches!(
result,
Err(InterpreterError::Break(Some(label), Value::Nil)) if label == "outer"
));
}
#[test]
fn test_continue_with_label() {
let mut interp = make_interpreter();
let expr = Expr {
kind: ExprKind::Continue {
label: Some("inner".to_string()),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&expr);
assert!(matches!(
result,
Err(InterpreterError::Continue(Some(label))) if label == "inner"
));
}
#[test]
fn test_none_special_form() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::None);
let result = interp.eval_expr(&expr).unwrap();
if let Value::EnumVariant {
enum_name,
variant_name,
data,
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "None");
assert!(data.is_none());
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_some_special_form() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Some {
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(42, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::EnumVariant {
enum_name,
variant_name,
data,
} = result
{
assert_eq!(enum_name, "Option");
assert_eq!(variant_name, "Some");
assert!(data.is_some());
} else {
panic!("Expected EnumVariant");
}
}
#[test]
fn test_set_special_form() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Set(vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
make_expr(ExprKind::Literal(Literal::Integer(3, None))),
]));
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_import_all_wildcard() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::ImportAll {
module: "std::math".to_string(),
alias: "*".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_import_default() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::ImportDefault {
module: "mymodule".to_string(),
name: "mm".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_env_set_mut_coverage() {
let mut interp = make_interpreter();
interp.env_set_mut("mutable_var_cov".to_string(), Value::Integer(1));
assert!(interp.lookup_variable("mutable_var_cov").is_ok());
}
#[test]
fn test_is_actor_operation_coverage() {
let actor_expr = Box::new(make_expr(ExprKind::Identifier("actor".to_string())));
assert!(Interpreter::is_actor_operation(&ExprKind::Spawn {
actor: actor_expr,
}));
}
#[test]
fn test_is_special_form_coverage() {
assert!(Interpreter::is_special_form(&ExprKind::None));
assert!(Interpreter::is_special_form(&ExprKind::Some {
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
}));
}
#[test]
fn test_is_control_flow_expr_coverage() {
assert!(Interpreter::is_control_flow_expr(&ExprKind::If {
condition: Box::new(make_expr(ExprKind::Literal(Literal::Bool(true)))),
then_branch: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
else_branch: None,
}));
}
#[test]
fn test_is_data_structure_expr_coverage() {
assert!(Interpreter::is_data_structure_expr(&ExprKind::List(vec![])));
}
#[test]
fn test_is_assignment_expr_coverage() {
assert!(Interpreter::is_assignment_expr(&ExprKind::Assign {
target: Box::new(make_expr(ExprKind::Identifier("x".to_string()))),
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
}));
}
#[test]
fn test_macro_invocation_vec() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::MacroInvocation {
name: "vec".to_string(),
args: vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Literal(Literal::Integer(2, None))),
],
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 2);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_macro_invocation_format() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::MacroInvocation {
name: "format".to_string(),
args: vec![make_expr(ExprKind::Literal(Literal::String(
"test".to_string(),
)))],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(matches!(result, Value::String(_)));
}
#[test]
fn test_macro_invocation_unknown() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::MacroInvocation {
name: "unknown_macro".to_string(),
args: vec![],
});
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_try_operator_ok() {
let mut interp = make_interpreter();
let ok_value = make_expr(ExprKind::Call {
func: Box::new(make_expr(ExprKind::Identifier("Ok".to_string()))),
args: vec![make_expr(ExprKind::Literal(Literal::Integer(42, None)))],
});
interp.set_variable(
"Ok",
Value::Closure {
params: vec![("value".to_string(), None)],
body: std::sync::Arc::new(make_expr(ExprKind::Block(vec![]))),
env: interp.current_env().clone(),
},
);
let ok_enum = Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Ok".to_string(),
data: Some(vec![Value::Integer(42)]),
};
interp.set_variable("result_val", ok_enum);
let try_expr = make_expr(ExprKind::Try {
expr: Box::new(make_expr(ExprKind::Identifier("result_val".to_string()))),
});
let result = interp.eval_expr(&try_expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_try_operator_err() {
let mut interp = make_interpreter();
let err_enum = Value::EnumVariant {
enum_name: "Result".to_string(),
variant_name: "Err".to_string(),
data: Some(vec![Value::from_string("error".to_string())]),
};
interp.set_variable("err_val", err_enum);
let try_expr = make_expr(ExprKind::Try {
expr: Box::new(make_expr(ExprKind::Identifier("err_val".to_string()))),
});
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_try_operator_invalid_type() {
let mut interp = make_interpreter();
interp.set_variable("not_result", Value::Integer(42));
let try_expr = make_expr(ExprKind::Try {
expr: Box::new(make_expr(ExprKind::Identifier("not_result".to_string()))),
});
let result = interp.eval_expr(&try_expr);
assert!(result.is_err());
}
#[test]
fn test_lazy_expr() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Lazy {
expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(42, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_async_block() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::AsyncBlock {
body: Box::new(make_expr(ExprKind::Literal(Literal::Integer(100, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(100));
}
#[test]
fn test_if_let_match() {
let mut interp = make_interpreter();
let some_val = Value::EnumVariant {
enum_name: "Option".to_string(),
variant_name: "Some".to_string(),
data: Some(vec![Value::Integer(42)]),
};
interp.set_variable("opt", some_val);
let expr = make_expr(ExprKind::IfLet {
pattern: Pattern::Identifier("x".to_string()),
expr: Box::new(make_expr(ExprKind::Identifier("opt".to_string()))),
then_branch: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
else_branch: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
0, None,
))))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(1));
}
#[test]
fn test_if_let_no_match() {
let mut interp = make_interpreter();
interp.set_variable("opt", Value::Nil);
let expr = make_expr(ExprKind::IfLet {
pattern: Pattern::Literal(Literal::Integer(5, None)),
expr: Box::new(make_expr(ExprKind::Identifier("opt".to_string()))),
then_branch: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
else_branch: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
0, None,
))))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(0));
}
#[test]
fn test_if_let_no_else() {
let mut interp = make_interpreter();
interp.set_variable("val", Value::Integer(10));
let expr = make_expr(ExprKind::IfLet {
pattern: Pattern::Literal(Literal::Integer(5, None)), expr: Box::new(make_expr(ExprKind::Identifier("val".to_string()))),
then_branch: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
else_branch: None,
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_module_declaration_error() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::ModuleDeclaration {
name: "unresolved_module".to_string(),
});
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_pipeline_with_method() {
let mut interp = make_interpreter();
interp.set_variable(
"double",
Value::Closure {
params: vec![("x".to_string(), None)],
body: std::sync::Arc::new(make_expr(ExprKind::Binary {
left: Box::new(make_expr(ExprKind::Identifier("x".to_string()))),
op: crate::frontend::ast::BinaryOp::Multiply,
right: Box::new(make_expr(ExprKind::Literal(Literal::Integer(2, None)))),
})),
env: interp.current_env().clone(),
},
);
let expr = make_expr(ExprKind::Pipeline {
expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(5, None)))),
stages: vec![crate::frontend::ast::PipelineStage {
op: Box::new(make_expr(ExprKind::Identifier("double".to_string()))),
span: Span::default(),
}],
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(10));
}
#[test]
fn test_format_debug_incomplete() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![make_expr(ExprKind::Literal(Literal::String(
"{:?x".to_string(),
)))],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(matches!(result, Value::String(_)));
}
#[test]
fn test_format_colon_only() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![make_expr(ExprKind::Literal(Literal::String(
"{:x".to_string(),
)))],
});
let result = interp.eval_expr(&expr).unwrap();
assert!(matches!(result, Value::String(_)));
}
#[test]
fn test_format_excess_placeholders() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Macro {
name: "format".to_string(),
args: vec![make_expr(ExprKind::Literal(Literal::String(
"{} {} {}".to_string(),
)))],
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::String(s) = result {
assert!(s.as_ref().contains("{}"));
} else {
panic!("Expected String");
}
}
#[test]
fn test_import_stdlib() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Import {
module: "std::env".to_string(),
items: None,
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_import_all_with_alias() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::ImportAll {
module: "std::math".to_string(),
alias: "m".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Nil);
}
#[test]
fn test_eval_string_interpolation_empty() {
let mut interp = make_interpreter();
let parts = vec![];
let expr = make_expr(ExprKind::StringInterpolation { parts });
let result = interp.eval_expr(&expr).unwrap();
if let Value::String(s) = result {
assert_eq!(s.as_ref(), "");
} else {
panic!("Expected String");
}
}
#[test]
fn test_eval_qualified_name() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::QualifiedName {
module: "std".to_string(),
name: "env".to_string(),
});
let _result = interp.eval_expr(&expr);
}
#[test]
fn test_loop_expression() {
let mut interp = make_interpreter();
interp.set_variable("counter", Value::Integer(0));
let loop_expr = Expr {
kind: ExprKind::Loop {
label: None,
body: Box::new(make_expr(ExprKind::Break {
label: None,
value: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
42, None,
))))),
})),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&loop_expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_labeled_loop() {
let mut interp = make_interpreter();
let loop_expr = Expr {
kind: ExprKind::Loop {
label: Some("outer".to_string()),
body: Box::new(make_expr(ExprKind::Break {
label: Some("outer".to_string()),
value: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
99, None,
))))),
})),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = interp.eval_expr(&loop_expr).unwrap();
assert_eq!(result, Value::Integer(99));
}
#[test]
fn test_return_expr() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Return {
value: Some(Box::new(make_expr(ExprKind::Literal(Literal::Integer(
123, None,
))))),
});
let result = interp.eval_expr(&expr);
assert!(matches!(
result,
Err(InterpreterError::Return(Value::Integer(123)))
));
}
#[test]
fn test_return_expr_no_value() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Return { value: None });
let result = interp.eval_expr(&expr);
assert!(matches!(result, Err(InterpreterError::Return(Value::Nil))));
}
#[test]
fn test_array_init_expr() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::ArrayInit {
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(0, None)))),
size: Box::new(make_expr(ExprKind::Literal(Literal::Integer(5, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::Array(arr) = result {
assert_eq!(arr.len(), 5);
} else {
panic!("Expected Array");
}
}
#[test]
fn test_index_access_tuple() {
let mut interp = make_interpreter();
let tuple = Value::Tuple(std::sync::Arc::from(vec![
Value::Integer(1),
Value::Integer(2),
Value::Integer(3),
]));
interp.set_variable("t", tuple);
let expr = make_expr(ExprKind::IndexAccess {
object: Box::new(make_expr(ExprKind::Identifier("t".to_string()))),
index: Box::new(make_expr(ExprKind::Literal(Literal::Integer(1, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(2));
}
#[test]
fn test_call_function_class_constructor() {
let mut interp = make_interpreter();
let mut class_def = HashMap::new();
class_def.insert(
"__type".to_string(),
Value::from_string("Class".to_string()),
);
class_def.insert(
"__name".to_string(),
Value::from_string("Point".to_string()),
);
class_def.insert(
"__fields".to_string(),
Value::Object(std::sync::Arc::new(HashMap::new())),
);
class_def.insert(
"__methods".to_string(),
Value::Array(std::sync::Arc::from(vec![])),
);
interp.set_variable("Point", Value::Object(std::sync::Arc::new(class_def)));
let constructor = Value::from_string("__class_constructor__:Point:new".to_string());
let result = interp.call_function(constructor, &[]);
let _ = result;
}
#[test]
fn test_call_function_struct_constructor() {
let mut interp = make_interpreter();
let mut struct_def = HashMap::new();
struct_def.insert(
"__type".to_string(),
Value::from_string("Struct".to_string()),
);
struct_def.insert(
"__name".to_string(),
Value::from_string("Point".to_string()),
);
struct_def.insert(
"__fields".to_string(),
Value::Object(std::sync::Arc::new(HashMap::new())),
);
interp.set_variable("Point", Value::Object(std::sync::Arc::new(struct_def)));
let constructor = Value::from_string("__struct_constructor__:Point".to_string());
let result = interp.call_function(constructor, &[]);
let _ = result;
}
#[test]
fn test_call_function_closure_with_defaults() {
let mut interp = make_interpreter();
let closure = Value::Closure {
params: vec![
("x".to_string(), None),
(
"y".to_string(),
Some(std::sync::Arc::new(make_expr(ExprKind::Literal(
Literal::Integer(10, None),
)))),
),
],
body: std::sync::Arc::new(make_expr(ExprKind::Binary {
left: Box::new(make_expr(ExprKind::Identifier("x".to_string()))),
op: crate::frontend::ast::BinaryOp::Add,
right: Box::new(make_expr(ExprKind::Identifier("y".to_string()))),
})),
env: interp.current_env().clone(),
};
let result = interp
.call_function(closure.clone(), &[Value::Integer(5)])
.unwrap();
assert_eq!(result, Value::Integer(15));
let result = interp
.call_function(closure, &[Value::Integer(5), Value::Integer(3)])
.unwrap();
assert_eq!(result, Value::Integer(8));
}
#[test]
fn test_call_function_arg_count_errors() {
let mut interp = make_interpreter();
let closure = Value::Closure {
params: vec![("x".to_string(), None), ("y".to_string(), None)],
body: std::sync::Arc::new(make_expr(ExprKind::Literal(Literal::Integer(0, None)))),
env: interp.current_env().clone(),
};
let result = interp.call_function(closure.clone(), &[Value::Integer(1)]);
assert!(result.is_err());
let result = interp.call_function(
closure,
&[Value::Integer(1), Value::Integer(2), Value::Integer(3)],
);
assert!(result.is_err());
}
#[test]
fn test_call_function_builtin() {
let mut interp = make_interpreter();
let builtin = Value::from_string("__builtin_len__".to_string());
let arr = Value::Array(std::sync::Arc::from(vec![
Value::Integer(1),
Value::Integer(2),
Value::Integer(3),
]));
let result = interp.call_function(builtin, &[arr]).unwrap();
assert_eq!(result, Value::Integer(3));
}
#[test]
fn test_spread_in_list_returns_error() {
let mut interp = make_interpreter();
interp.set_variable(
"inner",
Value::Array(std::sync::Arc::from(vec![
Value::Integer(2),
Value::Integer(3),
])),
);
let expr = make_expr(ExprKind::List(vec![
make_expr(ExprKind::Literal(Literal::Integer(1, None))),
make_expr(ExprKind::Spread {
expr: Box::new(make_expr(ExprKind::Identifier("inner".to_string()))),
}),
make_expr(ExprKind::Literal(Literal::Integer(4, None))),
]));
let result = interp.eval_expr(&expr);
assert!(result.is_err());
}
#[test]
fn test_await_expr() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::Await {
expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(42, None)))),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_field_access_object() {
let mut interp = make_interpreter();
let mut obj = HashMap::new();
obj.insert("x".to_string(), Value::Integer(42));
obj.insert("y".to_string(), Value::Integer(100));
interp.set_variable("obj", Value::Object(std::sync::Arc::new(obj)));
let expr = make_expr(ExprKind::FieldAccess {
object: Box::new(make_expr(ExprKind::Identifier("obj".to_string()))),
field: "x".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(42));
}
#[test]
fn test_field_access_struct() {
let mut interp = make_interpreter();
let mut fields = HashMap::new();
fields.insert("name".to_string(), Value::from_string("Alice".to_string()));
let struct_val = Value::Struct {
name: "Person".to_string(),
fields: std::sync::Arc::new(fields),
};
interp.set_variable("person", struct_val);
let expr = make_expr(ExprKind::FieldAccess {
object: Box::new(make_expr(ExprKind::Identifier("person".to_string()))),
field: "name".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::String(s) = result {
assert_eq!(s.as_ref(), "Alice");
} else {
panic!("Expected String");
}
}
#[test]
fn test_compound_add_assign() {
let mut interp = make_interpreter();
interp.set_variable("x", Value::Integer(10));
let expr = make_expr(ExprKind::CompoundAssign {
target: Box::new(make_expr(ExprKind::Identifier("x".to_string()))),
op: crate::frontend::ast::BinaryOp::Add,
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(5, None)))),
});
interp.eval_expr(&expr).unwrap();
let x = interp.lookup_variable("x").unwrap();
assert_eq!(x, Value::Integer(15));
}
#[test]
fn test_compound_mul_assign() {
let mut interp = make_interpreter();
interp.set_variable("x", Value::Integer(3));
let expr = make_expr(ExprKind::CompoundAssign {
target: Box::new(make_expr(ExprKind::Identifier("x".to_string()))),
op: crate::frontend::ast::BinaryOp::Multiply,
value: Box::new(make_expr(ExprKind::Literal(Literal::Integer(4, None)))),
});
interp.eval_expr(&expr).unwrap();
let x = interp.lookup_variable("x").unwrap();
assert_eq!(x, Value::Integer(12));
}
#[test]
fn test_type_cast_int_to_float() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::TypeCast {
expr: Box::new(make_expr(ExprKind::Literal(Literal::Integer(42, None)))),
target_type: "f64".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
if let Value::Float(f) = result {
assert!((f - 42.0).abs() < 0.001);
} else {
panic!("Expected Float");
}
}
#[test]
fn test_type_cast_float_to_int() {
let mut interp = make_interpreter();
let expr = make_expr(ExprKind::TypeCast {
expr: Box::new(make_expr(ExprKind::Literal(Literal::Float(3.7)))),
target_type: "i32".to_string(),
});
let result = interp.eval_expr(&expr).unwrap();
assert_eq!(result, Value::Integer(3));
}
}