helix/dna/ops/
conditional.rs

1//! Conditional & Control Flow - 6 operators
2//! 
3//! This module implements operators for conditional logic and control flow:
4//! - @if: Conditional expressions
5//! - @switch: Switch statements
6//! - @for: For loops
7//! - @while: While loops
8//! - @each: Array iteration
9//! - @filter: Array filtering
10
11use crate::dna::hel::error::HlxError;
12use crate::ops::utils;
13use crate::dna::atp::value::Value;
14use crate::ops::OperatorTrait;
15use async_trait::async_trait;
16use std::collections::HashMap;
17
18/// Conditional operators implementation
19pub struct ConditionalOperators;
20
21impl ConditionalOperators {
22    pub async fn new() -> Result<Self, HlxError> {
23        Ok(Self)
24    }
25
26    pub async fn execute(&self, operator: &str, params: &str) -> Result<Value, HlxError> {
27        self.execute_impl(operator, params).await
28    }
29
30    async fn execute_impl(&self, operator: &str, params: &str) -> Result<Value, HlxError> {
31        let params_map = crate::ops::utils::parse_params(params)?;
32
33        match operator {
34            "if" => self.if_operator(&params_map).await,
35            "switch" => self.switch_operator(&params_map).await,
36            "loop" => self.loop_operator(&params_map).await,
37            "filter" => self.filter_operator(&params_map).await,
38            "map" => self.map_operator(&params_map).await,
39            "reduce" => self.reduce_operator(&params_map).await,
40            _ => Err(HlxError::invalid_parameters(&operator, "Unknown conditional operator")),
41        }
42    }
43}
44
45#[async_trait]
46impl crate::ops::OperatorTrait for ConditionalOperators {
47    async fn execute(&self, operator: &str, params: &str) -> Result<Value, HlxError> {
48        self.execute_impl(operator, params).await
49    }
50}
51
52impl ConditionalOperators {
53    async fn if_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
54        let condition = params.get("condition")
55            .ok_or_else(|| HlxError::validation_error("Missing 'condition' parameter", "Check the condition parameter"))?;
56
57        let then_value = params.get("then")
58            .ok_or_else(|| HlxError::validation_error("Missing 'then' parameter", "Check the then parameter"))?;
59
60        let else_value = params.get("else")
61            .cloned()
62            .unwrap_or(Value::Null);
63
64        let result = match condition {
65            Value::Bool(b) => {
66                if *b { then_value.clone() } else { else_value }
67            },
68            Value::String(s) => {
69                if !s.is_empty() { then_value.clone() } else { else_value }
70            },
71            Value::Number(n) => {
72                if *n != 0.0 { then_value.clone() } else { else_value }
73            },
74            Value::Array(arr) => {
75                if !arr.is_empty() { then_value.clone() } else { else_value }
76            },
77            Value::Object(obj) => {
78                if !obj.is_empty() { then_value.clone() } else { else_value }
79            },
80            _ => else_value,
81        };
82
83        Ok(Value::Object({
84            let mut map = HashMap::new();
85            map.insert("result".to_string(), result);
86            map.insert("condition_evaluated".to_string(), Value::Bool(true));
87            map
88        }))
89    }
90
91    async fn switch_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
92        let value = params.get("value")
93            .ok_or_else(|| HlxError::validation_error(
94                "Missing 'value' parameter", "Check the value parameter"
95            ))?;
96
97        let cases = params.get("cases")
98            .and_then(|v| v.as_object())
99            .ok_or_else(|| HlxError::validation_error(
100                "Missing or invalid 'cases' parameter", "Check the cases parameter"
101            ))?;
102
103        let default = params.get("default")
104            .cloned()
105            .unwrap_or(Value::Null);
106
107        let result = if let Some(case_value) = cases.get(&value.to_string()) {
108            case_value.clone()
109        } else {
110            default
111        };
112
113        Ok(Value::Object({
114            let mut map = HashMap::new();
115            map.insert("result".to_string(), result);
116            map.insert("matched_case".to_string(), value.clone());
117            map
118        }))
119    }
120
121    async fn loop_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
122        let iterations = params.get("iterations")
123            .and_then(|v| v.as_number())
124            .unwrap_or(1.0) as usize;
125
126        let action = params.get("action")
127            .and_then(|v| v.as_string())
128            .unwrap_or("default");
129
130        let mut results = Vec::new();
131        for i in 0..iterations {
132            results.push(Value::Object({
133                let mut map = HashMap::new();
134                map.insert("iteration".to_string(), Value::Number(i as f64));
135                map.insert("action".to_string(), Value::String(action.to_string()));
136                map.insert("completed".to_string(), Value::Bool(true));
137                map
138            }));
139        }
140
141        Ok(Value::Object({
142            let mut map = HashMap::new();
143            map.insert("iterations".to_string(), Value::Number(iterations as f64));
144            map.insert("results".to_string(), Value::Array(results));
145            map.insert("completed".to_string(), Value::Bool(true));
146            map
147        }))
148    }
149
150    async fn filter_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
151        let array = params.get("array")
152            .and_then(|v| v.as_array())
153            .ok_or_else(|| HlxError::validation_error(
154                "Missing 'array' parameter", "Check the array parameter"
155            ))?;
156
157        let predicate = params.get("predicate")
158            .and_then(|v| v.as_string())
159            .unwrap_or("all");
160
161        let filtered: Vec<Value> = match predicate {
162            "all" => array.to_vec(),
163            "non_null" => array.iter()
164                .filter(|item| !matches!(item, &Value::String(s) if s.is_empty()))
165                .cloned()
166                .collect(),
167            "non_empty" => array.iter()
168                .filter(|item| match item {
169                    Value::String(s) => !s.is_empty(),
170                    Value::Array(arr) => !arr.is_empty(),
171                    Value::Object(obj) => !obj.is_empty(),
172                    _ => true,
173                })
174                .cloned()
175                .collect(),
176            _ => array.to_vec(),
177        };
178
179        let filtered_count = filtered.len() as f64;
180
181        Ok(Value::Object({
182            let mut map = HashMap::new();
183            map.insert("filtered".to_string(), Value::Array(filtered));
184            map.insert("original_count".to_string(), Value::Number(array.len() as f64));
185            map.insert("filtered_count".to_string(), Value::Number(filtered_count));
186            map
187        }))
188    }
189
190    async fn map_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
191        let array = params.get("array")
192            .and_then(|v| v.as_array())
193            .ok_or_else(|| HlxError::validation_error(
194                "Missing 'array' parameter", "Check the array parameter"
195            ))?;
196
197        let transform = params.get("transform")
198            .and_then(|v| v.as_string())
199            .unwrap_or("identity");
200
201        let mapped: Vec<Value> = match transform {
202            "uppercase" => array.iter()
203                .map(|item| match item {
204                    Value::String(s) => Value::String(s.to_uppercase()),
205                    _ => item.clone(),
206                })
207                .collect(),
208            "lowercase" => array.iter()
209                .map(|item| match item {
210                    Value::String(s) => Value::String(s.to_lowercase()),
211                    _ => item.clone(),
212                })
213                .collect(),
214            "stringify" => array.iter()
215                .map(|item| Value::String(item.to_string()))
216                .collect(),
217            _ => array.to_vec(),
218        };
219
220        Ok(Value::Object({
221            let mut map = HashMap::new();
222            map.insert("mapped".to_string(), Value::Array(mapped.clone()));
223            map.insert("transform".to_string(), Value::String(transform.to_string()));
224            map.insert("count".to_string(), Value::Number(mapped.len() as f64));
225            map
226        }))
227    }
228
229    async fn reduce_operator(&self, params: &HashMap<String, Value>) -> Result<Value, HlxError> {
230        let array = params.get("array")
231            .and_then(|v| v.as_array())
232            .ok_or_else(|| HlxError::validation_error(
233                "Missing 'array' parameter", "Check the array parameter"
234            ))?;
235
236        let operation = params.get("operation")
237            .and_then(|v| v.as_string())
238            .unwrap_or("sum");
239
240        let initial = params.get("initial")
241            .cloned()
242            .unwrap_or(Value::Number(0.0));
243
244        let result = match operation {
245            "sum" => {
246                let sum = array.iter()
247                    .filter_map(|item| item.as_number())
248                    .sum::<f64>();
249                Value::Number(sum)
250            },
251            "count" => Value::Number(array.len() as f64),
252            "join" => {
253                let joined = array.iter()
254                    .map(|item| item.to_string())
255                    .collect::<Vec<String>>()
256                    .join("");
257                Value::String(joined)
258            },
259            "concat" => {
260                let mut result = Vec::new();
261                for item in array {
262                    if let Value::Array(arr) = item {
263                        result.extend_from_slice(arr);
264                    } else {
265                        result.push(item.clone());
266                    }
267                }
268                Value::Array(result)
269            },
270            _ => initial,
271        };
272
273        Ok(Value::Object({
274            let mut map = HashMap::new();
275            map.insert("result".to_string(), result);
276            map.insert("operation".to_string(), Value::String(operation.to_string()));
277            map.insert("input_count".to_string(), Value::Number(array.len() as f64));
278            map
279        }))
280    }
281}