use crate::parser::ast::{Expr, Stmt};
use crate::parser::types::{Value, FunctionValue, LambdaParam};
use crate::parser::interpreter::Interpreter;
use crate::parser::interpreter::utils::{
bool_like, eval_bracketed_array, eval_keyed_array, assign_to_expr, assign_keyed_destructure,
};
use crate::parser::interpreter::apply;
fn err_with_pos<S: Into<String>>(msg: S, line: usize, col: usize) -> String {
format!("(at line {}, col {}) {}", line, col, msg.into())
}
pub fn eval_expression(
_interp: &mut Interpreter,
expr_str: &str
) -> Result<Value, String> {
let trimmed = expr_str.trim();
if let Ok(i) = trimmed.parse::<i32>() {
return Ok(Value::Int(i));
}
if trimmed.starts_with('"') && trimmed.ends_with('"') && trimmed.len() >= 2 {
let inner = &trimmed[1..trimmed.len() - 1];
return Ok(Value::StrArray(vec![inner.to_string()]));
}
Err(format!("eval_expression => unrecognized expr '{}'", expr_str))
}
impl Interpreter {
pub fn exec_statement(&mut self, stmt: &Stmt) -> Result<Value, String> {
match stmt {
Stmt::ImportSo { path, line, col } => {
if self.is_verbose() {
eprintln!("(Interpreter) extend => {}", path);
}
if !self.can_extend() {
return Err(err_with_pos("extend is disallowed", *line, *col));
}
let expr_for_legacy = format!("extend(\"{}\")", path);
crate::modules::extend::handle_extend_call(self, &expr_for_legacy)
.map_err(|e| err_with_pos(format!("extend error: {}", e), *line, *col))
}
Stmt::Assignment { left, right, line: _line, col: _col } => {
let right_val = self.eval_expression(right)?;
assign_to_expr(self, left, right_val.clone())?;
Ok(right_val)
}
Stmt::AssignmentDestructure { pattern, right, line: _line, col: _col } => {
let right_val = self.eval_expression(right)?;
assign_keyed_destructure(self, pattern, right_val.clone())?;
Ok(right_val)
}
Stmt::AssignmentScoped { left, right, line: _line, col: _col } => {
let val = self.eval_expression(right)?;
match left {
Expr::Ident { name, .. } => {
self.set_variable(name, val.clone());
Ok(val)
}
_ => Err(err_with_pos("Left side of ^=-assignment must be a variable", *_line, *_col)),
}
}
Stmt::ExprStmt { expr, line: _line, col: _col } => self.eval_expression(expr),
}
}
pub fn eval_expression(&mut self, expr: &Expr) -> Result<Value, String> {
use Expr::*;
match expr {
Number { value, .. } => Ok(Value::Int(*value)),
NumberFloat { value, .. } => Ok(Value::Float(*value)),
StrLit { value, .. } => Ok(Value::SingleString(value.clone())),
Bool { value, .. } => Ok(Value::Bool(*value)),
Ident { name, line, col } => {
let v = self.lookup_variable(name)
.ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *line, *col))?;
match v {
Value::Ref(arc_mutex) => Ok(arc_mutex.lock().unwrap().clone()),
v => Ok(v),
}
}
Ref { expr: inner, line, col } => {
match &**inner {
Expr::Ident { name, line: n_line, col: n_col } => {
let storage = self.lookup_variable_storage(name)
.ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *n_line, *n_col))?;
Ok(Value::Ref(storage))
}
_ => Err(err_with_pos("Can only take reference of a variable", *line, *col)),
}
}
Placeholder { line: _line, col: _col } => Ok(Value::Placeholder),
BracketedArray { items, line: _line, col: _col } => eval_bracketed_array(self, items),
KeyedArray { pairs, line: _line, col: _col } => eval_keyed_array(self, pairs),
FunctionCall { callee, args, line, col } => {
let callee_val = self.eval_expression(callee)?;
if let Value::Function(fb) = &callee_val {
if let FunctionValue::InlineLambdaAST { params, .. } = &**fb {
let mut arg_vals = Vec::new();
for (i, a_expr) in args.iter().enumerate() {
let use_ref = params.get(i)
.map(|p| matches!(p, LambdaParam::Ref(_)))
.unwrap_or(false);
if use_ref {
if let Expr::Ident { name, line: v_line, col: v_col } = a_expr {
let storage = self.lookup_variable_storage(name)
.ok_or_else(|| err_with_pos(format!("Undefined variable '{}'", name), *v_line, *v_col))?;
arg_vals.push(Value::Ref(storage));
} else {
let v = self.eval_expression(a_expr)?;
arg_vals.push(Value::Ref(std::sync::Arc::new(std::sync::Mutex::new(v))));
}
} else {
arg_vals.push(self.eval_expression(a_expr)?);
}
}
return apply::apply_n_ary_function_value(self, fb.clone(), arg_vals);
}
}
let mut arg_vals = Vec::new();
for a_expr in args {
arg_vals.push(self.eval_expression(a_expr)?);
}
match callee_val {
Value::Function(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
Value::InkTransform(fb) => apply::apply_n_ary_function_value(self, fb, arg_vals),
Value::Stream(sh) => {
Err(err_with_pos(format!("Cannot call a Stream as a function: stream_id={}", sh.stream_id), *line, *col))
}
other => Err(err_with_pos(format!("Cannot call non-function: {:?}", other), *line, *col)),
}
}
Index { base, index, line: _line, col: _col } => {
let base_val = self.eval_expression(base)?;
let idx_val = self.eval_expression(index)?;
self.eval_index_expr(base_val, idx_val)
}
Gt { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_gt(lv, rv)
}
Lt { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_lt(lv, rv)
}
EqEq { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_eqeq(lv, rv)
}
Le { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_le(lv, rv)
}
Ge { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_ge(lv, rv)
}
Add { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_add(lv, rv)
}
Sub { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_sub(lv, rv)
}
Mul { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_mul(lv, rv)
}
Div { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_div(lv, rv)
}
Mod { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_mod(lv, rv)
}
Ternary { cond, if_true, if_false, line: _line, col: _col } => {
let cval = self.eval_expression(cond)?;
match cval {
Value::Bool(flag) => {
if flag {
self.eval_expression(if_true)
} else {
self.eval_expression(if_false)
}
}
Value::Int(i) => {
if i == 0 {
self.eval_expression(if_false)
} else {
self.eval_expression(if_true)
}
}
Value::Float(f) => {
if f == 0.0 {
self.eval_expression(if_false)
} else {
self.eval_expression(if_true)
}
}
Value::Long(l) => {
if l == 0 {
self.eval_expression(if_false)
} else {
self.eval_expression(if_true)
}
}
_ => Err(err_with_pos("Ternary condition must be bool/int/float/long", *_line, *_col)),
}
}
InlineLambdaAST { params, body, line: _line, col: _col } => {
let fv = FunctionValue::InlineLambdaAST {
params: params.clone(),
body_expr: body.clone(),
};
Ok(Value::Function(Box::new(fv)))
}
Block { stmts, line: _line, col: _col } => {
self.push_scope();
let mut last_val = Value::Bool(true);
for s in stmts {
let v = self.exec_statement(s)?;
last_val = v;
}
self.pop_scope();
Ok(last_val)
}
UnaryMinus { expr: subexpr, line: _line, col: _col } => {
let val = self.eval_expression(subexpr)?;
match val {
Value::Int(i) => {
i.checked_neg()
.map(Value::Int)
.ok_or_else(|| err_with_pos("Overflow in unary minus", *_line, *_col))
}
Value::Long(l) => {
l.checked_neg()
.map(Value::Long)
.ok_or_else(|| err_with_pos("Overflow in unary minus (long)", *_line, *_col))
}
Value::Float(ff) => Ok(Value::Float(-ff)),
other => Err(err_with_pos(format!("Cannot apply unary minus to {:?}", other), *_line, *_col)),
}
}
AndAnd { left, right, line: _line, col: _col } => {
let left_val = self.eval_expression(left)?;
let left_truth = bool_like(&left_val)?;
if !left_truth {
Ok(Value::Bool(false))
} else {
let right_val = self.eval_expression(right)?;
let right_truth = bool_like(&right_val)?;
Ok(Value::Bool(right_truth))
}
}
UnaryNot { expr: subexpr, line: _line, col: _col } => {
let val = self.eval_expression(subexpr)?;
let truth = bool_like(&val)?;
Ok(Value::Bool(!truth))
}
Ne { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_ne(lv, rv)
}
BitAnd { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_bitand(lv, rv)
}
OrOr { left, right, line: _line, col: _col } => {
let left_val = self.eval_expression(left)?;
let left_truth = bool_like(&left_val)?;
if left_truth {
Ok(Value::Bool(true))
} else {
let right_val = self.eval_expression(right)?;
let right_truth = bool_like(&right_val)?;
Ok(Value::Bool(right_truth))
}
}
Shl { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_shl(lv, rv)
}
Shr { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_shr(lv, rv)
}
BitXor { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_bitxor(lv, rv)
}
BitTilde { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_bittilde(lv, rv)
}
BitOr { left, right, line: _line, col: _col } => {
let lv = self.eval_expression(left)?;
let rv = self.eval_expression(right)?;
self.eval_bitor(lv, rv)
}
}
}
fn eval_index_expr(&mut self, base_val: Value, idx_val: Value) -> Result<Value, String> {
let actual_base = match base_val {
Value::Ref(arc_mutex) => arc_mutex.lock().unwrap().clone(),
v => v,
};
match (actual_base, idx_val) {
(Value::IntArray(xs), Value::Int(i)) => {
let len = xs.len() as i32;
let idx = if i < 0 { len + i } else { i };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(Value::Int(xs[idx as usize]))
}
(Value::FloatArray(ffs), Value::Int(i)) => {
let len = ffs.len() as i32;
let idx = if i < 0 { len + i } else { i };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(Value::Float(ffs[idx as usize]))
}
(Value::StrArray(ss), Value::Int(i)) => {
let len = ss.len() as i32;
let idx = if i < 0 { len + i } else { i };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(Value::SingleString(ss[idx as usize].clone()))
}
(Value::Int2DArray(rows), Value::Int(r)) => {
let len = rows.len() as i32;
let idx = if r < 0 { len + r } else { r };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(Value::IntArray(rows[idx as usize].clone()))
}
(Value::Float2DArray(rows), Value::Int(r)) => {
let len = rows.len() as i32;
let idx = if r < 0 { len + r } else { r };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(Value::FloatArray(rows[idx as usize].clone()))
}
(Value::MixedArray(items), Value::Int(i)) => {
let len = items.len() as i32;
let idx = if i < 0 { len + i } else { i };
if idx < 0 || idx >= len {
return Ok(Value::Placeholder);
}
Ok(items[idx as usize].clone())
}
(Value::KeyedArray(map), Value::SingleString(key)) => {
if let Some(v) = map.get(&key) {
Ok(v.clone())
} else {
Ok(Value::Placeholder)
}
}
(Value::KeyedArray(map), Value::StrArray(arr)) if arr.len() == 1 => {
if let Some(v) = map.get(&arr[0]) {
Ok(v.clone())
} else {
Ok(Value::Placeholder)
}
}
(Value::KeyedArray(_), Value::Int(_)) => {
Err("Cannot index into a KeyedArray with an integer".to_string())
}
other => Err(format!("Cannot index into {:?}", other)),
}
}
}