use crate::il_extended::{ILContext, ILError, ILExpression, ILOperation, ILPlan};
use crate::RpcTarget;
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub struct ILExecutor {
#[allow(dead_code)] capabilities: Vec<Arc<dyn RpcTarget>>,
}
impl ILExecutor {
pub fn new() -> Self {
Self {
capabilities: Vec::new(),
}
}
pub fn with_capabilities(capabilities: Vec<Arc<dyn RpcTarget>>) -> Self {
Self { capabilities }
}
pub fn execute<'a>(
&'a self,
expr: &'a ILExpression,
context: &'a mut ILContext,
) -> Pin<Box<dyn Future<Output = Result<Value, ILError>> + 'a>> {
Box::pin(self.execute_impl(expr, context))
}
async fn execute_impl(
&self,
expr: &ILExpression,
context: &mut ILContext,
) -> Result<Value, ILError> {
match expr {
ILExpression::Literal(value) => Ok(value.clone()),
ILExpression::Variable { var_ref } => context
.get_variable(*var_ref)
.cloned()
.ok_or(ILError::VariableNotFound(*var_ref)),
ILExpression::Plan { plan } => self.execute_plan(plan, context).await,
ILExpression::Bind { bind } => {
let value = self.execute(&bind.value, context).await?;
let _var_index = context.push_variable(value);
let result = self.execute(&bind.body, context).await?;
Ok(result)
}
ILExpression::If { if_expr } => {
let condition = self.execute(&if_expr.condition, context).await?;
if self.is_truthy(&condition) {
self.execute(&if_expr.then_branch, context).await
} else {
self.execute(&if_expr.else_branch, context).await
}
}
ILExpression::Get { get } => {
let object = self.execute(&get.object, context).await?;
self.get_property(&object, &get.property)
}
ILExpression::Call { call } => {
let target = self.execute(&call.target, context).await?;
let mut args = Vec::new();
for arg_expr in &call.args {
args.push(self.execute(arg_expr, context).await?);
}
self.call_method(target, &call.method, args).await
}
ILExpression::MapOp { map } => {
let array = self.execute(&map.array, context).await?;
self.execute_map(array, &map.function, context).await
}
ILExpression::FilterOp { filter } => {
let array = self.execute(&filter.array, context).await?;
self.execute_filter(array, &filter.predicate, context).await
}
ILExpression::ReduceOp { reduce } => {
let array = self.execute(&reduce.array, context).await?;
let initial = self.execute(&reduce.initial, context).await?;
self.execute_reduce(array, &reduce.function, initial, context)
.await
}
}
}
async fn execute_plan(&self, plan: &ILPlan, context: &mut ILContext) -> Result<Value, ILError> {
for operation in &plan.operations {
match operation {
ILOperation::Store { store } => {
let value = self.execute(&store.value, context).await?;
context.set_variable(store.slot, value)?;
}
ILOperation::Execute { execute } => {
self.execute(execute, context).await?;
}
}
}
self.execute(&plan.result, context).await
}
async fn execute_map(
&self,
array: Value,
function: &ILExpression,
context: &mut ILContext,
) -> Result<Value, ILError> {
match array {
Value::Array(items) => {
let mut results = Vec::new();
for item in items {
let var_index = context.push_variable(item);
let result = if let ILExpression::Bind { .. } = function {
self.execute(function, context).await?
} else {
let bind_expr =
ILExpression::bind(ILExpression::var(var_index), function.clone());
self.execute(&bind_expr, context).await?
};
results.push(result);
}
Ok(Value::Array(results))
}
_ => Err(ILError::TypeError {
expected: "array".to_string(),
actual: self.value_type_name(&array),
}),
}
}
async fn execute_filter(
&self,
array: Value,
predicate: &ILExpression,
context: &mut ILContext,
) -> Result<Value, ILError> {
match array {
Value::Array(items) => {
let mut results = Vec::new();
for item in items {
let mut predicate_context = ILContext::new(context.captures.clone());
predicate_context.set_variable(0, item.clone()).unwrap();
let condition = self.execute(predicate, &mut predicate_context).await?;
if self.is_truthy(&condition) {
results.push(item);
}
}
Ok(Value::Array(results))
}
_ => Err(ILError::TypeError {
expected: "array".to_string(),
actual: self.value_type_name(&array),
}),
}
}
async fn execute_reduce(
&self,
array: Value,
function: &ILExpression,
mut accumulator: Value,
context: &mut ILContext,
) -> Result<Value, ILError> {
match array {
Value::Array(items) => {
for item in items {
let acc_index = context.push_variable(accumulator.clone());
let item_index = context.push_variable(item);
let bind_expr = ILExpression::bind(
ILExpression::var(acc_index),
ILExpression::bind(ILExpression::var(item_index), function.clone()),
);
accumulator = self.execute(&bind_expr, context).await?;
}
Ok(accumulator)
}
_ => Err(ILError::TypeError {
expected: "array".to_string(),
actual: self.value_type_name(&array),
}),
}
}
fn get_property(&self, object: &Value, property: &str) -> Result<Value, ILError> {
match object {
Value::Object(map) => map.get(property).cloned().ok_or_else(|| {
ILError::ExecutionFailed(format!("Property '{}' not found", property))
}),
_ => Err(ILError::TypeError {
expected: "object".to_string(),
actual: self.value_type_name(object),
}),
}
}
async fn call_method(
&self,
_target: Value,
_method: &str,
_args: Vec<Value>,
) -> Result<Value, ILError> {
Err(ILError::ExecutionFailed(
"Method calls require capability resolution (not yet implemented)".to_string(),
))
}
fn is_truthy(&self, value: &Value) -> bool {
match value {
Value::Null => false,
Value::Bool(b) => *b,
Value::Number(n) => n.as_f64().map(|f| f != 0.0).unwrap_or(false),
Value::String(s) => !s.is_empty(),
Value::Array(a) => !a.is_empty(),
Value::Object(_) => true,
}
}
fn value_type_name(&self, value: &Value) -> String {
match value {
Value::Null => "null".to_string(),
Value::Bool(_) => "boolean".to_string(),
Value::Number(_) => "number".to_string(),
Value::String(_) => "string".to_string(),
Value::Array(_) => "array".to_string(),
Value::Object(_) => "object".to_string(),
}
}
}
impl Default for ILExecutor {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::il_extended::FilterExpression;
use serde_json::json;
#[tokio::test]
async fn test_execute_literal() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::literal(json!(42));
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!(42));
}
#[tokio::test]
async fn test_execute_variable() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
context.set_variable(0, json!("hello")).unwrap();
let expr = ILExpression::var(0);
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!("hello"));
}
#[tokio::test]
async fn test_execute_bind() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::bind(
ILExpression::literal(json!(100)),
ILExpression::var(0), );
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!(100));
}
#[tokio::test]
async fn test_execute_if() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::if_expr(
ILExpression::literal(json!(true)),
ILExpression::literal(json!("then")),
ILExpression::literal(json!("else")),
);
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!("then"));
let expr = ILExpression::if_expr(
ILExpression::literal(json!(false)),
ILExpression::literal(json!("then")),
ILExpression::literal(json!("else")),
);
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!("else"));
}
#[tokio::test]
async fn test_execute_get() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::get(
ILExpression::literal(json!({
"name": "John",
"age": 30
})),
"name".to_string(),
);
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert_eq!(result, json!("John"));
}
#[tokio::test]
async fn test_execute_map() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::map(
ILExpression::literal(json!([1, 2, 3])),
ILExpression::var(0),
);
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
assert!(matches!(result, Value::Array(_)));
}
#[tokio::test]
async fn test_execute_filter() {
let executor = ILExecutor::new();
let mut context = ILContext::new(vec![]);
let expr = ILExpression::FilterOp {
filter: FilterExpression {
array: Box::new(ILExpression::literal(json!([true, false, true]))),
predicate: Box::new(ILExpression::var(0)), },
};
let result = executor.execute_impl(&expr, &mut context).await.unwrap();
match result {
Value::Array(items) => {
assert_eq!(items.len(), 2);
assert_eq!(items[0], json!(true));
assert_eq!(items[1], json!(true));
}
_ => panic!("Expected array result"),
}
}
}