devalang_wasm/engine/functions/
mod.rs

1pub mod chord;
2pub mod effects;
3/// Function execution system for arrow calls
4///
5/// This module provides a modular system for executing chainable functions
6/// like `synth -> note(C4) -> filter(lowpass, 1000)`
7pub mod note;
8
9use crate::language::syntax::ast::nodes::Value;
10use anyhow::Result;
11use std::collections::HashMap;
12
13/// Context passed through function chain
14#[derive(Debug, Clone)]
15pub struct FunctionContext {
16    /// Target object (e.g., synth name, sample name)
17    pub target: String,
18
19    /// Accumulated state (e.g., MIDI notes, audio buffer)
20    pub state: HashMap<String, Value>,
21
22    /// Timing information
23    pub start_time: f32,
24    pub duration: f32,
25
26    /// Tempo for beat calculations
27    pub tempo: f32,
28}
29
30impl FunctionContext {
31    pub fn new(target: String, start_time: f32, tempo: f32) -> Self {
32        Self {
33            target,
34            state: HashMap::new(),
35            start_time,
36            duration: 0.0,
37            tempo,
38        }
39    }
40
41    pub fn set(&mut self, key: impl Into<String>, value: Value) {
42        self.state.insert(key.into(), value);
43    }
44
45    pub fn get(&self, key: &str) -> Option<&Value> {
46        self.state.get(key)
47    }
48}
49
50/// Trait for executable functions
51pub trait FunctionExecutor {
52    /// Execute the function with given arguments
53    fn execute(&self, context: &mut FunctionContext, args: &[Value]) -> Result<()>;
54
55    /// Function name
56    fn name(&self) -> &str;
57}
58
59/// Function registry
60pub struct FunctionRegistry {
61    functions: HashMap<String, Box<dyn FunctionExecutor>>,
62}
63
64impl FunctionRegistry {
65    pub fn new() -> Self {
66        let mut registry = Self {
67            functions: HashMap::new(),
68        };
69
70        // Register built-in functions
71        registry.register(Box::new(note::NoteFunction));
72        registry.register(Box::new(chord::ChordFunction));
73        registry.register(Box::new(effects::VelocityFunction));
74        registry.register(Box::new(effects::DurationFunction));
75        registry.register(Box::new(effects::PanFunction));
76        registry.register(Box::new(effects::DetuneFunction));
77        registry.register(Box::new(effects::SpreadFunction));
78        registry.register(Box::new(effects::GainFunction));
79        registry.register(Box::new(effects::AttackFunction));
80        registry.register(Box::new(effects::ReleaseFunction));
81        registry.register(Box::new(effects::DelayFunction));
82        registry.register(Box::new(effects::ReverbFunction));
83        registry.register(Box::new(effects::DriveFunction));
84        registry.register(Box::new(effects::ChorusFunction));
85        registry.register(Box::new(effects::FlangerFunction));
86        registry.register(Box::new(effects::PhaserFunction));
87        registry.register(Box::new(effects::CompressorFunction));
88        registry.register(Box::new(effects::DistortionFunction));
89
90        registry
91    }
92
93    pub fn register(&mut self, executor: Box<dyn FunctionExecutor>) {
94        self.functions.insert(executor.name().to_string(), executor);
95    }
96
97    pub fn execute(&self, name: &str, context: &mut FunctionContext, args: &[Value]) -> Result<()> {
98        if let Some(func) = self.functions.get(name) {
99            func.execute(context, args)
100        } else {
101            Err(anyhow::anyhow!("Unknown function: {}", name))
102        }
103    }
104
105    pub fn has(&self, name: &str) -> bool {
106        self.functions.contains_key(name)
107    }
108}
109
110impl Default for FunctionRegistry {
111    fn default() -> Self {
112        Self::new()
113    }
114}