gent/interpreter/
block_eval.rs

1//! Block evaluation module
2//!
3//! This module provides async block evaluation for executing tool bodies
4//! with let bindings, return statements, if/else, and expression statements.
5
6use crate::errors::{GentError, GentResult};
7use crate::interpreter::builtins::{call_builtin, is_builtin};
8use crate::interpreter::expr_eval::evaluate_expr;
9use crate::interpreter::array_methods::{call_array_method, call_array_method_with_callback, is_callback_method};
10use crate::interpreter::string_methods::call_string_method;
11use crate::interpreter::types::EnumValue;
12use crate::interpreter::{Environment, Value};
13use crate::parser::ast::{Block, BlockStmt, Expression, MatchBody, MatchPattern};
14use crate::runtime::tools::ToolRegistry;
15
16/// Control flow signal for break/continue/return propagation
17#[derive(Debug, Clone, PartialEq)]
18enum ControlFlow {
19    /// Normal execution, continue to next statement
20    Continue,
21    /// Break out of the current loop
22    Break,
23    /// Skip to next iteration of the current loop
24    LoopContinue,
25    /// Return from the function with the given value (boxed to reduce enum size)
26    Return(Box<Value>),
27}
28
29/// Type alias for async block evaluation result with control flow
30type BlockInternalFuture<'a> =
31    std::pin::Pin<Box<dyn std::future::Future<Output = GentResult<(ControlFlow, Value)>> + 'a>>;
32
33/// Evaluate a block of statements in the given environment
34///
35/// Returns the value of the first return statement encountered,
36/// or Value::Null if the block completes without returning.
37pub fn evaluate_block<'a>(
38    block: &'a Block,
39    env: &'a mut Environment,
40    tools: &'a ToolRegistry,
41) -> std::pin::Pin<Box<dyn std::future::Future<Output = GentResult<Value>> + 'a>> {
42    Box::pin(async move {
43        // Create a new scope for this block
44        env.push_scope();
45
46        let (flow, result) = evaluate_block_internal(block, env, tools).await?;
47
48        // Pop the scope
49        env.pop_scope();
50
51        // Handle control flow that escaped the block
52        match flow {
53            ControlFlow::Return(val) => Ok(*val),
54            ControlFlow::Continue => Ok(result),
55            // Break/LoopContinue outside of a loop is an error, but we treat it as normal
56            // completion for now (the loop handler consumes these signals)
57            ControlFlow::Break | ControlFlow::LoopContinue => Ok(result),
58        }
59    })
60}
61
62/// Internal block evaluation that returns control flow signals
63fn evaluate_block_internal<'a>(
64    block: &'a Block,
65    env: &'a mut Environment,
66    tools: &'a ToolRegistry,
67) -> BlockInternalFuture<'a> {
68    Box::pin(async move {
69        let mut result = Value::Null;
70
71        for stmt in &block.statements {
72            match stmt {
73                BlockStmt::Let(let_stmt) => {
74                    // Check if the value is a mutating array method call (push/pop)
75                    let value = if let Some((arr_var, method_name, args)) = extract_array_method_call(&let_stmt.value) {
76                        if method_name == "push" || method_name == "pop" {
77                            if let Some(Value::Array(arr)) = env.get(&arr_var).cloned() {
78                                let mut arr_mut = arr;
79
80                                // Evaluate arguments
81                                let mut arg_values = Vec::new();
82                                for arg in args {
83                                    let val = evaluate_expr_async(arg, env, tools).await?;
84                                    arg_values.push(val);
85                                }
86
87                                // Call the method and get result
88                                let result = call_array_method(&mut arr_mut, &method_name, &arg_values)?;
89
90                                // Update the array variable with the mutated array
91                                env.set(&arr_var, Value::Array(arr_mut));
92
93                                result
94                            } else {
95                                evaluate_expr_async(&let_stmt.value, env, tools).await?
96                            }
97                        } else {
98                            evaluate_expr_async(&let_stmt.value, env, tools).await?
99                        }
100                    } else {
101                        evaluate_expr_async(&let_stmt.value, env, tools).await?
102                    };
103
104                    // Define the variable in the current scope
105                    env.define(&let_stmt.name, value);
106                }
107
108                BlockStmt::Assignment(assign_stmt) => {
109                    // Evaluate the right-hand side expression
110                    let value = evaluate_expr_async(&assign_stmt.value, env, tools).await?;
111
112                    // Update the variable in the environment
113                    if !env.set(&assign_stmt.name, value) {
114                        return Err(GentError::SyntaxError {
115                            message: format!("Undefined variable: '{}'", assign_stmt.name),
116                            span: assign_stmt.span.clone(),
117                        });
118                    }
119                }
120
121                BlockStmt::Return(return_stmt) => {
122                    // Evaluate the return value (if any)
123                    result = if let Some(ref expr) = return_stmt.value {
124                        evaluate_expr_async(expr, env, tools).await?
125                    } else {
126                        Value::Null
127                    };
128                    return Ok((ControlFlow::Return(Box::new(result)), Value::Null));
129                }
130
131                BlockStmt::If(if_stmt) => {
132                    // Evaluate the condition
133                    let condition = evaluate_expr_async(&if_stmt.condition, env, tools).await?;
134
135                    // Execute the appropriate block
136                    if condition.is_truthy() {
137                        // Execute then block (create a new scope)
138                        env.push_scope();
139                        let (flow, _) = evaluate_block_internal(&if_stmt.then_block, env, tools).await?;
140                        env.pop_scope();
141
142                        // Propagate control flow signals
143                        match flow {
144                            ControlFlow::Continue => {}
145                            other => return Ok((other, Value::Null)),
146                        }
147                    } else if let Some(ref else_block) = if_stmt.else_block {
148                        // Execute else block (create a new scope)
149                        env.push_scope();
150                        let (flow, _) = evaluate_block_internal(else_block, env, tools).await?;
151                        env.pop_scope();
152
153                        // Propagate control flow signals
154                        match flow {
155                            ControlFlow::Continue => {}
156                            other => return Ok((other, Value::Null)),
157                        }
158                    }
159                }
160
161                BlockStmt::For(for_stmt) => {
162                    // Evaluate the iterable expression
163                    let iterable = evaluate_expr(&for_stmt.iterable, env)?;
164
165                    // Convert iterable to a list of items
166                    let items: Vec<Value> = match iterable {
167                        Value::Array(arr) => arr,
168                        Value::String(s) => s.chars().map(|c| Value::String(c.to_string())).collect(),
169                        other => {
170                            return Err(GentError::TypeError {
171                                expected: "Array or String".to_string(),
172                                got: other.type_name().to_string(),
173                                span: for_stmt.span.clone(),
174                            });
175                        }
176                    };
177
178                    // Iterate over items
179                    'outer: for item in items {
180                        env.push_scope();
181                        env.define(&for_stmt.variable, item);
182
183                        // Execute the loop body using internal evaluation
184                        let (flow, _) = evaluate_block_internal(&for_stmt.body, env, tools).await?;
185
186                        env.pop_scope();
187
188                        // Handle control flow from the loop body
189                        match flow {
190                            ControlFlow::Continue => {
191                                // Normal completion, continue to next iteration
192                            }
193                            ControlFlow::LoopContinue => {
194                                // Skip to next iteration (already handled by continuing the loop)
195                                continue 'outer;
196                            }
197                            ControlFlow::Break => {
198                                // Exit the loop
199                                break 'outer;
200                            }
201                            ControlFlow::Return(val) => {
202                                // Propagate return up
203                                return Ok((ControlFlow::Return(val), Value::Null));
204                            }
205                        }
206                    }
207                }
208
209                BlockStmt::Expr(expr) => {
210                    // Check for mutating array method calls (push/pop) and handle specially
211                    if let Some((var_name, method_name, args)) = extract_array_method_call(expr) {
212                        if method_name == "push" || method_name == "pop" {
213                            // Get the current array value
214                            if let Some(Value::Array(arr)) = env.get(&var_name).cloned() {
215                                let mut arr_mut = arr;
216
217                                // Evaluate arguments
218                                let mut arg_values = Vec::new();
219                                for arg in args {
220                                    let val = evaluate_expr_async(arg, env, tools).await?;
221                                    arg_values.push(val);
222                                }
223
224                                // Call the method
225                                call_array_method(&mut arr_mut, &method_name, &arg_values)?;
226
227                                // Update the variable with the mutated array
228                                env.set(&var_name, Value::Array(arr_mut));
229                            }
230                            continue;
231                        }
232                    }
233
234                    // Evaluate the expression for side effects, discarding the result
235                    evaluate_expr_async(expr, env, tools).await?;
236                }
237
238                BlockStmt::While(while_stmt) => {
239                    const MAX_ITERATIONS: usize = 10000; // Prevent infinite loops
240                    let mut iterations = 0;
241
242                    'while_loop: loop {
243                        iterations += 1;
244                        if iterations > MAX_ITERATIONS {
245                            return Err(GentError::SyntaxError {
246                                message: format!(
247                                    "While loop exceeded maximum iterations ({})",
248                                    MAX_ITERATIONS
249                                ),
250                                span: while_stmt.span.clone(),
251                            });
252                        }
253
254                        // Evaluate condition
255                        let condition =
256                            evaluate_expr_async(&while_stmt.condition, env, tools).await?;
257                        if !condition.is_truthy() {
258                            break;
259                        }
260
261                        // Execute body statements with a new scope
262                        env.push_scope();
263                        let (flow, _) =
264                            evaluate_block_internal(&while_stmt.body, env, tools).await?;
265                        env.pop_scope();
266
267                        // Handle control flow from the loop body
268                        match flow {
269                            ControlFlow::Continue => {
270                                // Normal completion, continue to next iteration
271                            }
272                            ControlFlow::LoopContinue => {
273                                // Skip to next iteration
274                                continue 'while_loop;
275                            }
276                            ControlFlow::Break => {
277                                // Exit the loop
278                                break 'while_loop;
279                            }
280                            ControlFlow::Return(val) => {
281                                // Propagate return up
282                                return Ok((ControlFlow::Return(val), Value::Null));
283                            }
284                        }
285                    }
286                }
287
288                BlockStmt::Break(_) => {
289                    // Signal break to the enclosing loop
290                    return Ok((ControlFlow::Break, Value::Null));
291                }
292
293                BlockStmt::Continue(_) => {
294                    // Signal continue to the enclosing loop
295                    return Ok((ControlFlow::LoopContinue, Value::Null));
296                }
297
298                BlockStmt::Try(try_stmt) => {
299                    // Execute try block and capture result
300                    env.push_scope();
301                    let try_result = evaluate_block_internal(&try_stmt.try_block, env, tools).await;
302                    env.pop_scope();
303
304                    match try_result {
305                        Ok((flow, _value)) => {
306                            // Try block succeeded
307                            match flow {
308                                ControlFlow::Return(val) => {
309                                    return Ok((ControlFlow::Return(val), Value::Null));
310                                }
311                                ControlFlow::Break => {
312                                    return Ok((ControlFlow::Break, Value::Null));
313                                }
314                                ControlFlow::LoopContinue => {
315                                    return Ok((ControlFlow::LoopContinue, Value::Null));
316                                }
317                                ControlFlow::Continue => {
318                                    // Normal completion, continue with next statement after try/catch
319                                }
320                            }
321                        }
322                        Err(e) => {
323                            // Error occurred, execute catch block with error bound
324                            env.push_scope();
325                            env.define(&try_stmt.error_var, Value::String(e.to_string()));
326
327                            let catch_result =
328                                evaluate_block_internal(&try_stmt.catch_block, env, tools).await?;
329                            env.pop_scope();
330
331                            match catch_result.0 {
332                                ControlFlow::Return(val) => {
333                                    return Ok((ControlFlow::Return(val), Value::Null));
334                                }
335                                ControlFlow::Break => {
336                                    return Ok((ControlFlow::Break, Value::Null));
337                                }
338                                ControlFlow::LoopContinue => {
339                                    return Ok((ControlFlow::LoopContinue, Value::Null));
340                                }
341                                ControlFlow::Continue => {
342                                    // Normal completion, continue with next statement after try/catch
343                                }
344                            }
345                        }
346                    }
347                }
348            }
349        }
350
351        Ok((ControlFlow::Continue, result))
352    })
353}
354
355/// Evaluate an expression in an async context, handling function calls
356///
357/// This function is similar to evaluate_expr but supports async tool calls.
358pub fn evaluate_expr_async<'a>(
359    expr: &'a Expression,
360    env: &'a Environment,
361    tools: &'a ToolRegistry,
362) -> std::pin::Pin<Box<dyn std::future::Future<Output = GentResult<Value>> + 'a>> {
363    Box::pin(async move {
364        match expr {
365            // Function/tool calls require async context
366            Expression::Call(callee_expr, args, span) => {
367                // Check if this is a method call on a string, array, or enum constructor
368                if let Expression::Member(obj_expr, method_name, _) = callee_expr.as_ref() {
369                    // First check if this could be an enum constructor call: EnumName.Variant(args)
370                    if let Expression::Identifier(name, _) = obj_expr.as_ref() {
371                        if let Some(enum_def) = env.get_enum(name) {
372                            // Find the variant
373                            if let Some(v) = enum_def.variants.iter().find(|v| v.name == *method_name) {
374                                // Evaluate arguments
375                                let mut arg_values = Vec::new();
376                                for arg in args {
377                                    let val = evaluate_expr_async(arg, env, tools).await?;
378                                    arg_values.push(val);
379                                }
380
381                                if arg_values.len() != v.fields.len() {
382                                    return Err(GentError::TypeError {
383                                        expected: format!(
384                                            "Variant '{}' expects {} arguments",
385                                            method_name, v.fields.len()
386                                        ),
387                                        got: format!("{} arguments", arg_values.len()),
388                                        span: span.clone(),
389                                    });
390                                }
391
392                                return Ok(Value::Enum(EnumValue {
393                                    enum_name: name.clone(),
394                                    variant: method_name.clone(),
395                                    data: arg_values,
396                                }));
397                            } else {
398                                return Err(GentError::TypeError {
399                                    expected: format!("valid variant of enum '{}'", name),
400                                    got: method_name.clone(),
401                                    span: span.clone(),
402                                });
403                            }
404                        }
405                    }
406
407                    // Evaluate the object expression
408                    let obj = evaluate_expr_async(obj_expr, env, tools).await?;
409
410                    // If it's a string, dispatch to string methods
411                    if let Value::String(s) = &obj {
412                        // Evaluate method arguments
413                        let mut arg_values = Vec::new();
414                        for arg in args {
415                            let val = evaluate_expr_async(arg, env, tools).await?;
416                            arg_values.push(val);
417                        }
418                        return call_string_method(s, method_name, &arg_values);
419                    }
420
421                    // Check if this is an enum .is() or .data() call
422                    if let Value::Enum(ref enum_val) = obj {
423                        if method_name == "is" {
424                            // Evaluate the argument (should be an EnumValue or EnumConstructor)
425                            if args.len() != 1 {
426                                return Err(GentError::TypeError {
427                                    expected: "1 argument for .is()".to_string(),
428                                    got: format!("{} arguments", args.len()),
429                                    span: span.clone(),
430                                });
431                            }
432
433                            let arg = evaluate_expr_async(&args[0], env, tools).await?;
434                            let matches = match arg {
435                                Value::Enum(other) => {
436                                    enum_val.enum_name == other.enum_name && enum_val.variant == other.variant
437                                }
438                                Value::EnumConstructor(ctor) => {
439                                    enum_val.enum_name == ctor.enum_name && enum_val.variant == ctor.variant
440                                }
441                                _ => false,
442                            };
443
444                            return Ok(Value::Boolean(matches));
445                        }
446
447                        if method_name == "data" {
448                            if args.len() != 1 {
449                                return Err(GentError::TypeError {
450                                    expected: "1 argument for .data()".to_string(),
451                                    got: format!("{} arguments", args.len()),
452                                    span: span.clone(),
453                                });
454                            }
455
456                            let arg = evaluate_expr_async(&args[0], env, tools).await?;
457
458                            match arg {
459                                Value::Number(n) => {
460                                    let idx = n as usize;
461                                    return Ok(enum_val.data.get(idx).cloned().unwrap_or(Value::Null));
462                                }
463                                Value::String(_) => {
464                                    // Named access not yet implemented
465                                    return Err(GentError::TypeError {
466                                        expected: "number index for .data()".to_string(),
467                                        got: "string (named access not yet implemented)".to_string(),
468                                        span: span.clone(),
469                                    });
470                                }
471                                _ => {
472                                    return Err(GentError::TypeError {
473                                        expected: "number index".to_string(),
474                                        got: arg.type_name(),
475                                        span: span.clone(),
476                                    });
477                                }
478                            }
479                        }
480                    }
481
482                    // If it's an array, dispatch to array methods
483                    if let Value::Array(ref arr) = obj {
484                        // Evaluate method arguments
485                        let mut arg_values = Vec::new();
486                        for arg in args {
487                            let val = evaluate_expr_async(arg, env, tools).await?;
488                            arg_values.push(val);
489                        }
490
491                        // Check if this is a callback method (map, filter, reduce, find)
492                        if is_callback_method(method_name) {
493                            let callback = arg_values.first().ok_or_else(|| GentError::TypeError {
494                                expected: "callback function for array method".to_string(),
495                                got: "missing argument".to_string(),
496                                span: span.clone(),
497                            })?;
498                            let extra_args = if arg_values.len() > 1 { &arg_values[1..] } else { &[] };
499                            return call_array_method_with_callback(
500                                arr,
501                                method_name,
502                                callback,
503                                extra_args,
504                                env,
505                                tools,
506                            ).await;
507                        }
508
509                        // Non-callback methods
510                        let mut arr_clone = arr.clone();
511                        let result = call_array_method(
512                            &mut arr_clone,
513                            method_name,
514                            &arg_values,
515                        )?;
516
517                        return Ok(result);
518                    }
519
520                    // For other types, return an error for now
521                    return Err(GentError::TypeError {
522                        expected: "String or Array".to_string(),
523                        got: obj.type_name().to_string(),
524                        span: span.clone(),
525                    });
526                }
527
528                // Get the callable name
529                let callable_name = if let Expression::Identifier(name, _) = callee_expr.as_ref() {
530                    name.clone()
531                } else {
532                    let callee = evaluate_expr(callee_expr, env)?;
533                    return Err(GentError::TypeError {
534                        expected: "function or tool name".to_string(),
535                        got: callee.type_name().to_string(),
536                        span: span.clone(),
537                    });
538                };
539
540                // Evaluate arguments first (needed for both functions and tools)
541                let mut arg_values = Vec::new();
542                for arg in args {
543                    let val = evaluate_expr_async(arg, env, tools).await?;
544                    arg_values.push(val);
545                }
546
547                // Check if it's a built-in function
548                if is_builtin(&callable_name) {
549                    return call_builtin(&callable_name, &arg_values, span);
550                }
551
552                // Check if it's a function in the environment
553                if let Some(Value::Function(fn_val)) = env.get(&callable_name) {
554                    // Clone the function value since we need to borrow env mutably later
555                    let fn_val = fn_val.clone();
556
557                    // Check argument count
558                    if arg_values.len() != fn_val.params.len() {
559                        return Err(GentError::SyntaxError {
560                            message: format!(
561                                "Function '{}' expects {} arguments, got {}",
562                                fn_val.name,
563                                fn_val.params.len(),
564                                arg_values.len()
565                            ),
566                            span: span.clone(),
567                        });
568                    }
569
570                    // Create a new environment with function scope
571                    let mut fn_env = env.clone();
572                    fn_env.push_scope();
573
574                    // Bind parameters to arguments
575                    for (param, arg_val) in fn_val.params.iter().zip(arg_values.iter()) {
576                        fn_env.define(&param.name, arg_val.clone());
577                    }
578
579                    // Evaluate the function body
580                    let result = evaluate_block(&fn_val.body, &mut fn_env, tools).await?;
581                    return Ok(result);
582                }
583
584                // Look up the tool in the registry
585                let tool = tools
586                    .get(&callable_name)
587                    .ok_or_else(|| GentError::UnknownTool {
588                        name: callable_name.clone(),
589                        span: span.clone(),
590                    })?;
591
592                // Convert arguments to JSON for tool execution
593                let json_args = args_to_json(&arg_values);
594
595                // Execute the tool
596                let result = tool
597                    .execute(json_args)
598                    .await
599                    .map_err(|e| GentError::ToolError {
600                        tool: callable_name.clone(),
601                        message: e,
602                    })?;
603
604                // For now, return the result as a string
605                // TODO: Parse JSON results in the future
606                Ok(Value::String(result))
607            }
608
609            // Match expression
610            Expression::Match(match_expr) => {
611                let subject = evaluate_expr_async(&match_expr.subject, env, tools).await?;
612
613                for arm in &match_expr.arms {
614                    if let Some(bindings) = match_pattern(&subject, &arm.pattern) {
615                        // Create new scope with bindings
616                        let mut match_env = env.clone();
617                        match_env.push_scope();
618                        for (name, value) in bindings {
619                            match_env.define(&name, value);
620                        }
621
622                        // Evaluate arm body
623                        let result = match &arm.body {
624                            MatchBody::Expression(expr) => {
625                                evaluate_expr_async(expr, &match_env, tools).await?
626                            }
627                            MatchBody::Block(block) => {
628                                evaluate_block(block, &mut match_env, tools).await?
629                            }
630                        };
631
632                        return Ok(result);
633                    }
634                }
635
636                // No match found
637                Err(GentError::SyntaxError {
638                    message: "Non-exhaustive match: no pattern matched".to_string(),
639                    span: match_expr.span.clone(),
640                })
641            }
642
643            // All other expressions can be evaluated synchronously
644            _ => evaluate_expr(expr, env),
645        }
646    })
647}
648
649/// Convert a vector of Values to a JSON value for tool execution
650fn args_to_json(args: &[Value]) -> serde_json::Value {
651    use serde_json::{json, Map, Value as JsonValue};
652
653    fn value_to_json(val: &Value) -> JsonValue {
654        match val {
655            Value::String(s) => JsonValue::String(s.clone()),
656            Value::Number(n) => json!(n),
657            Value::Boolean(b) => JsonValue::Bool(*b),
658            Value::Null => JsonValue::Null,
659            Value::Array(items) => {
660                let json_items: Vec<JsonValue> = items.iter().map(value_to_json).collect();
661                JsonValue::Array(json_items)
662            }
663            Value::Object(map) => {
664                let mut json_map = Map::new();
665                for (k, v) in map {
666                    json_map.insert(k.clone(), value_to_json(v));
667                }
668                JsonValue::Object(json_map)
669            }
670            Value::Agent(_) => JsonValue::String("<agent>".to_string()),
671            Value::Tool(_) => JsonValue::String("<tool>".to_string()),
672            Value::Function(_) => JsonValue::String("<function>".to_string()),
673            Value::Lambda(_) => JsonValue::String("<lambda>".to_string()),
674            Value::Enum(e) => {
675                if e.data.is_empty() {
676                    JsonValue::String(format!("{}.{}", e.enum_name, e.variant))
677                } else {
678                    let mut map = Map::new();
679                    map.insert("enum".to_string(), JsonValue::String(e.enum_name.clone()));
680                    map.insert(
681                        "variant".to_string(),
682                        JsonValue::String(e.variant.clone()),
683                    );
684                    let data: Vec<JsonValue> = e.data.iter().map(value_to_json).collect();
685                    map.insert("data".to_string(), JsonValue::Array(data));
686                    JsonValue::Object(map)
687                }
688            }
689            Value::EnumConstructor(c) => {
690                JsonValue::String(format!("<enum constructor {}.{}>", c.enum_name, c.variant))
691            }
692            Value::Parallel(p) => JsonValue::String(format!("<parallel {}>", p.name)),
693        }
694    }
695
696    // If there's a single object argument, use it directly
697    // Otherwise, wrap arguments in an array
698    if args.len() == 1 {
699        if let Value::Object(_) = &args[0] {
700            return value_to_json(&args[0]);
701        }
702    }
703
704    // For multiple args or non-object single arg, create an array
705    JsonValue::Array(args.iter().map(value_to_json).collect())
706}
707
708/// Extract variable name, method name, and arguments from a method call expression
709/// Returns Some((var_name, method_name, args)) if this is a method call on an identifier
710fn extract_array_method_call(expr: &Expression) -> Option<(String, String, &Vec<Expression>)> {
711    if let Expression::Call(callee_expr, args, _) = expr {
712        if let Expression::Member(obj_expr, method_name, _) = callee_expr.as_ref() {
713            if let Expression::Identifier(var_name, _) = obj_expr.as_ref() {
714                return Some((var_name.clone(), method_name.clone(), args));
715            }
716        }
717    }
718    None
719}
720
721/// Match a value against a pattern, returning bindings if successful
722fn match_pattern(value: &Value, pattern: &MatchPattern) -> Option<Vec<(String, Value)>> {
723    match pattern {
724        MatchPattern::Wildcard => Some(vec![]),
725        MatchPattern::EnumVariant { enum_name, variant_name, bindings } => {
726            if let Value::Enum(enum_val) = value {
727                if enum_val.enum_name == *enum_name && enum_val.variant == *variant_name {
728                    // Bind data to pattern variables
729                    let mut result = Vec::new();
730                    for (i, binding) in bindings.iter().enumerate() {
731                        if let Some(data) = enum_val.data.get(i) {
732                            result.push((binding.clone(), data.clone()));
733                        }
734                    }
735                    return Some(result);
736                }
737            }
738            None
739        }
740    }
741}