devalang_wasm/language/syntax/parser/driver/
effects.rs

1use crate::language::syntax::ast::Value;
2use anyhow::{Result, anyhow};
3use std::collections::HashMap;
4
5/// Parse a chain of arrow-separated effects
6pub fn parse_chained_effects(effects_str: &str) -> Result<Value> {
7    let effects = effects_str
8        .split("->")
9        .map(str::trim)
10        .filter(|s| !s.is_empty())
11        .try_fold(HashMap::new(), |mut map, effect| {
12            parse_single_effect(effect).map(|(name, params)| {
13                map.insert(name, params);
14                map
15            })
16        })?;
17
18    Ok(Value::Map(effects))
19}
20
21/// Parse a single effect definition into (name, parameters)
22fn parse_single_effect(effect_str: &str) -> Result<(String, Value)> {
23    let effect_str = effect_str.trim();
24    if effect_str.is_empty() {
25        return Err(anyhow!("Empty effect definition"));
26    }
27
28    // Handle function-like syntax: effect_name(param1, param2, ...)
29    if let Some((name, params_str)) = effect_str.split_once('(') {
30        let name = name.trim().to_string();
31        let params_str = params_str.trim_end_matches(')');
32
33        // Handle boolean single parameter
34        if params_str == "true" {
35            return Ok((name, Value::Boolean(true)));
36        } else if params_str == "false" {
37            return Ok((name, Value::Boolean(false)));
38        }
39
40        // Handle numeric single parameter
41        if let Ok(num) = params_str.parse::<f32>() {
42            return Ok((name, Value::Number(num)));
43        }
44
45        // Handle parameter map
46        if params_str.contains('{') && params_str.contains('}') {
47            let map_str = params_str.trim_matches(|c| c == '{' || c == '}');
48            let mut params_map = HashMap::new();
49
50            for pair in map_str.split(',') {
51                if let Some((key, value)) = pair.split_once(':') {
52                    let key = key.trim().to_string();
53                    let value = value.trim();
54
55                    let value = if value == "true" {
56                        Value::Boolean(true)
57                    } else if value == "false" {
58                        Value::Boolean(false)
59                    } else if let Ok(num) = value.parse::<f32>() {
60                        Value::Number(num)
61                    } else {
62                        Value::String(value.trim_matches('"').to_string())
63                    };
64
65                    params_map.insert(key, value);
66                }
67            }
68
69            Ok((name, Value::Map(params_map)))
70        } else {
71            // Single string parameter
72            Ok((
73                name,
74                Value::String(params_str.trim_matches('"').to_string()),
75            ))
76        }
77    } else {
78        // Effect without parameters
79        Ok((effect_str.to_string(), Value::Null))
80    }
81}
82
83#[cfg(test)]
84#[path = "test_effects.rs"]
85mod tests;