devalang_wasm/engine/audio/interpreter/statements/
loop_.rs

1use crate::engine::audio::interpreter::driver::AudioInterpreter;
2use crate::language::syntax::ast::{Statement, Value};
3/// Loop and For statement execution
4use anyhow::Result;
5
6impl AudioInterpreter {
7    /// Execute a Loop statement (repeat N times)
8    pub fn execute_loop(&mut self, count: &Value, body: &[Statement]) -> Result<()> {
9        // Extract loop count
10        let loop_count = match count {
11            Value::Number(n) => (*n) as usize,
12            Value::Identifier(ident) => {
13                // Try to get variable value
14                if let Some(Value::Number(n)) = self.variables.get(ident) {
15                    *n as usize
16                } else {
17                    anyhow::bail!("❌ Loop iterator '{}' must be a number", ident);
18                }
19            }
20            _ => {
21                anyhow::bail!("❌ Loop iterator must be a number, found: {:?}", count);
22            }
23        };
24
25        // Execute body N times
26        for _iteration in 0..loop_count {
27            self.collect_events(body)?;
28        }
29
30        Ok(())
31    }
32
33    /// Execute a For statement (foreach item in array/range)
34    pub fn execute_for(
35        &mut self,
36        variable: &str,
37        iterable: &Value,
38        body: &[Statement],
39    ) -> Result<()> {
40        // Extract items to iterate over
41        let items = match iterable {
42            Value::Array(arr) => arr.clone(),
43            Value::Identifier(ident) => {
44                // Try to get variable value
45                if let Some(Value::Array(arr)) = self.variables.get(ident) {
46                    arr.clone()
47                } else {
48                    anyhow::bail!("❌ For iterable '{}' must be an array", ident);
49                }
50            }
51            Value::Range { start, end } => {
52                // Generate range [start..end]
53                let start_val = match start.as_ref() {
54                    Value::Number(n) => *n as i32,
55                    _ => anyhow::bail!("❌ Range start must be a number"),
56                };
57                let end_val = match end.as_ref() {
58                    Value::Number(n) => *n as i32,
59                    _ => anyhow::bail!("❌ Range end must be a number"),
60                };
61
62                // Create array from range
63                (start_val..=end_val)
64                    .map(|i| Value::Number(i as f32))
65                    .collect()
66            }
67            _ => {
68                anyhow::bail!(
69                    "❌ For iterable must be an array or range, found: {:?}",
70                    iterable
71                );
72            }
73        };
74
75        // Execute body for each item
76        for (_idx, item) in items.iter().enumerate() {
77            // Set loop variable
78            let old_value = self.variables.insert(variable.to_string(), item.clone());
79
80            // Execute body
81            self.collect_events(body)?;
82
83            // Restore old value or remove
84            match old_value {
85                Some(val) => self.variables.insert(variable.to_string(), val),
86                None => self.variables.remove(variable),
87            };
88        }
89
90        Ok(())
91    }
92}