devalang_wasm/language/syntax/ast/nodes/
mod.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5#[serde(tag = "type", content = "value")]
6pub enum DurationValue {
7    Number(f32),
8    Identifier(String),
9    Beat(String),
10    Beats(f32),
11    Milliseconds(f32),
12    Auto,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(tag = "type", content = "value")]
17pub enum Value {
18    Boolean(bool),
19    Number(f32),
20    Duration(DurationValue),
21    Identifier(String),
22    String(String),
23    Array(Vec<Value>),
24    Map(HashMap<String, Value>),
25    Block(Vec<Statement>),
26    Sample(String),
27    Beat(String),
28    Statement(Box<Statement>),
29    StatementKind(Box<StatementKind>),
30    Midi(String),
31    Range { start: Box<Value>, end: Box<Value> },
32    Unknown,
33    Null,
34}
35
36impl Default for Value {
37    fn default() -> Self {
38        Value::Null
39    }
40}
41
42impl Value {
43    pub fn get(&self, key: &str) -> Option<&Value> {
44        if let Value::Map(map) = self {
45            map.get(key)
46        } else {
47            None
48        }
49    }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53#[serde(tag = "kind")]
54pub enum StatementKind {
55    Tempo,
56    Print,
57    Pattern {
58        name: String,
59        target: Option<String>,
60    },
61    Trigger {
62        entity: String,
63        duration: DurationValue,
64        effects: Option<Value>,
65    },
66    Sleep,
67    Call {
68        name: String,
69        args: Vec<Value>,
70    },
71    Load {
72        source: String,
73        alias: String,
74    },
75    Use {
76        name: String,
77        alias: Option<String>,
78    },
79    UsePlugin {
80        author: String,
81        name: String,
82        alias: String,
83    },
84    Automate {
85        target: String,
86    },
87    ArrowCall {
88        target: String,
89        method: String,
90        args: Vec<Value>,
91    },
92    Function {
93        name: String,
94        parameters: Vec<String>,
95        body: Vec<Statement>,
96    },
97    Assign {
98        target: String,
99        property: String,
100    },
101    Synth,
102    Bank {
103        name: String,
104        alias: Option<String>,
105    },
106    Let {
107        name: String,
108        value: Option<Value>,
109    },
110    Var {
111        name: String,
112        value: Option<Value>,
113    },
114    Const {
115        name: String,
116        value: Option<Value>,
117    },
118    Group {
119        name: String,
120        body: Vec<Statement>,
121    },
122    Spawn {
123        name: String,
124        args: Vec<Value>,
125    },
126    Loop {
127        count: Value,
128        body: Vec<Statement>,
129    },
130    For {
131        variable: String,
132        iterable: Value,
133        body: Vec<Statement>,
134    },
135    Routing,
136    Bind {
137        source: String,
138        target: String,
139    },
140    FxPipeline {
141        effects: Vec<Value>,
142        subject: String,
143    },
144    Node {
145        name: String,
146    },
147    Sidechain {
148        source: String,
149        effect: Value,
150        target: Option<String>,
151    },
152    Include(String),
153    Export {
154        names: Vec<String>,
155        source: String,
156    },
157    Import {
158        names: Vec<String>,
159        source: String,
160    },
161    On {
162        event: String,
163        args: Option<Vec<Value>>,
164        body: Vec<Statement>,
165    },
166    Emit {
167        event: String,
168        payload: Option<Value>,
169    },
170    If {
171        condition: Value,
172        body: Vec<Statement>,
173        else_body: Option<Vec<Statement>>, // Can contain statements or another If for else if
174    },
175    Comment,
176    Indent,
177    Dedent,
178    NewLine,
179    Unknown,
180    Error {
181        message: String,
182    },
183}
184
185impl Default for StatementKind {
186    fn default() -> Self {
187        StatementKind::Unknown
188    }
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
192pub struct Statement {
193    pub kind: StatementKind,
194    #[serde(default)]
195    pub value: Value,
196    pub indent: usize,
197    pub line: usize,
198    pub column: usize,
199}
200
201impl Statement {
202    pub fn new(
203        kind: StatementKind,
204        value: Value,
205        indent: usize,
206        line: usize,
207        column: usize,
208    ) -> Self {
209        Self {
210            kind,
211            value,
212            indent,
213            line,
214            column,
215        }
216    }
217
218    pub fn tempo(value: f32, line: usize, column: usize) -> Self {
219        Self::new(StatementKind::Tempo, Value::Number(value), 0, line, column)
220    }
221
222    pub fn print(message: impl Into<String>, line: usize, column: usize) -> Self {
223        Self::new(
224            StatementKind::Print,
225            Value::String(message.into()),
226            0,
227            line,
228            column,
229        )
230    }
231
232    pub fn trigger(
233        entity: impl Into<String>,
234        duration: DurationValue,
235        effects: Option<Value>,
236        line: usize,
237        column: usize,
238    ) -> Self {
239        Self::new(
240            StatementKind::Trigger {
241                entity: entity.into(),
242                duration,
243                effects,
244            },
245            Value::Null,
246            0,
247            line,
248            column,
249        )
250    }
251
252    pub fn unknown() -> Self {
253        Self::default()
254    }
255
256    pub fn unknown_with_pos(indent: usize, line: usize, column: usize) -> Self {
257        Self::new(StatementKind::Unknown, Value::Null, indent, line, column)
258    }
259
260    pub fn error_with_pos(indent: usize, line: usize, column: usize, message: String) -> Self {
261        Self::new(
262            StatementKind::Error { message },
263            Value::Null,
264            indent,
265            line,
266            column,
267        )
268    }
269}