devalang_wasm/utils/
props.rs

1use crate::language::syntax::ast::Value;
2use std::collections::HashMap;
3
4/// Resolve a dotted identifier like "a.b.c" from a variable table.
5/// Returns Value::Null if resolution fails at any step.
6pub fn resolve_dotted_from_table(name: &str, variables: &HashMap<String, Value>) -> Value {
7    resolve_dotted_with_lookup(name, |k| variables.get(k).cloned())
8}
9
10/// Resolve dotted identifier using a lookup function for the root name.
11pub fn resolve_dotted_with_lookup<F>(name: &str, mut lookup: F) -> Value
12where
13    F: FnMut(&str) -> Option<Value>,
14{
15    if name.is_empty() {
16        return Value::Null;
17    }
18
19    let parts: Vec<&str> = name.split('.').collect();
20    if parts.is_empty() {
21        return Value::Null;
22    }
23
24    // Resolve first part using provided lookup
25    let mut current: Option<Value> = lookup(parts[0]);
26    if current.is_none() {
27        return Value::Null;
28    }
29
30    for prop in parts.iter().skip(1) {
31        match current {
32            Some(Value::Map(ref map)) => {
33                if let Some(next) = map.get(*prop) {
34                    current = Some(next.clone());
35                } else {
36                    return Value::Null;
37                }
38            }
39            _ => return Value::Null,
40        }
41    }
42
43    current.unwrap_or(Value::Null)
44}
45
46/// Ensure a set of default properties exist on an object map.
47/// `kind_hint` can be used to provide specialized defaults for different object kinds.
48pub fn ensure_default_properties(map: &mut HashMap<String, Value>, kind_hint: Option<&str>) {
49    // Common defaults for audio objects
50    map.entry("volume".to_string())
51        .or_insert(Value::Number(1.0));
52    map.entry("gain".to_string()).or_insert(Value::Number(1.0));
53    map.entry("pan".to_string()).or_insert(Value::Number(0.0));
54    map.entry("detune".to_string())
55        .or_insert(Value::Number(0.0));
56    // Provide a visible type for printing
57    map.entry("type".to_string())
58        .or_insert(Value::String("object".to_string()));
59
60    if let Some(kind) = kind_hint {
61        match kind {
62            "synth" => {
63                map.entry("type".to_string())
64                    .or_insert(Value::String("synth".to_string()));
65                map.entry("waveform".to_string())
66                    .or_insert(Value::String("sine".to_string()));
67            }
68            "mapping" => {
69                map.entry("_type".to_string())
70                    .or_insert(Value::String("midi_mapping".to_string()));
71            }
72            "trigger" => {
73                // triggers commonly reference sample URIs; nothing to add by default
74            }
75            _ => {}
76        }
77    }
78}