devalang_wasm/language/preprocessor/resolver/
value.rs

1use crate::language::syntax::ast::Value;
2use std::collections::HashMap;
3
4/// Resolve a value by recursively expanding identifiers from variable tables
5pub fn resolve_value(value: &Value, variables: &HashMap<String, Value>, depth: usize) -> Value {
6    const MAX_DEPTH: usize = 32;
7
8    if depth > MAX_DEPTH {
9        return value.clone();
10    }
11
12    match value {
13        Value::Identifier(name) => {
14            if let Some(resolved) = variables.get(name) {
15                // Recursively resolve to handle chained identifiers
16                resolve_value(resolved, variables, depth + 1)
17            } else {
18                value.clone()
19            }
20        }
21        Value::Map(map) => {
22            let mut resolved_map = HashMap::new();
23            for (k, v) in map {
24                resolved_map.insert(k.clone(), resolve_value(v, variables, depth + 1));
25            }
26            Value::Map(resolved_map)
27        }
28        Value::Array(arr) => {
29            let resolved: Vec<Value> = arr
30                .iter()
31                .map(|v| resolve_value(v, variables, depth + 1))
32                .collect();
33            Value::Array(resolved)
34        }
35        _ => value.clone(),
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn test_resolve_identifier() {
45        let mut vars = HashMap::new();
46        vars.insert("x".to_string(), Value::Number(42.0));
47
48        let result = resolve_value(&Value::Identifier("x".to_string()), &vars, 0);
49        assert!(matches!(result, Value::Number(n) if (n - 42.0).abs() < f32::EPSILON));
50    }
51
52    #[test]
53    fn test_resolve_chained_identifier() {
54        let mut vars = HashMap::new();
55        vars.insert("x".to_string(), Value::Identifier("y".to_string()));
56        vars.insert("y".to_string(), Value::Number(100.0));
57
58        let result = resolve_value(&Value::Identifier("x".to_string()), &vars, 0);
59        assert!(matches!(result, Value::Number(n) if (n - 100.0).abs() < f32::EPSILON));
60    }
61
62    #[test]
63    fn test_resolve_map() {
64        let mut vars = HashMap::new();
65        vars.insert("gain".to_string(), Value::Number(0.8));
66
67        let mut input_map = HashMap::new();
68        input_map.insert("vol".to_string(), Value::Identifier("gain".to_string()));
69
70        let result = resolve_value(&Value::Map(input_map), &vars, 0);
71        if let Value::Map(m) = result {
72            if let Some(Value::Number(n)) = m.get("vol") {
73                assert!((n - 0.8).abs() < f32::EPSILON);
74                return;
75            }
76        }
77        panic!("Expected resolved map with vol=0.8");
78    }
79}