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 Automate {
80 target: String,
81 },
82 ArrowCall {
83 target: String,
84 method: String,
85 args: Vec<Value>,
86 },
87 Function {
88 name: String,
89 parameters: Vec<String>,
90 body: Vec<Statement>,
91 },
92 Assign {
93 target: String,
94 property: String,
95 },
96 Synth,
97 Bank {
98 name: String,
99 alias: Option<String>,
100 },
101 Let {
102 name: String,
103 value: Option<Value>,
104 },
105 Var {
106 name: String,
107 value: Option<Value>,
108 },
109 Const {
110 name: String,
111 value: Option<Value>,
112 },
113 Group {
114 name: String,
115 body: Vec<Statement>,
116 },
117 Spawn {
118 name: String,
119 args: Vec<Value>,
120 },
121 Loop {
122 count: Value,
123 body: Vec<Statement>,
124 },
125 For {
126 variable: String,
127 iterable: Value,
128 body: Vec<Statement>,
129 },
130 Routing,
131 Bind {
132 source: String,
133 target: String,
134 },
135 FxPipeline {
136 effects: Vec<Value>,
137 subject: String,
138 },
139 Node {
140 name: String,
141 },
142 Sidechain {
143 source: String,
144 effect: Value,
145 target: Option<String>,
146 },
147 Include(String),
148 Export {
149 names: Vec<String>,
150 source: String,
151 },
152 Import {
153 names: Vec<String>,
154 source: String,
155 },
156 On {
157 event: String,
158 args: Option<Vec<Value>>,
159 body: Vec<Statement>,
160 },
161 Emit {
162 event: String,
163 payload: Option<Value>,
164 },
165 If {
166 condition: Value,
167 body: Vec<Statement>,
168 else_body: Option<Vec<Statement>>, },
170 Comment,
171 Indent,
172 Dedent,
173 NewLine,
174 Unknown,
175 Error {
176 message: String,
177 },
178}
179
180impl Default for StatementKind {
181 fn default() -> Self {
182 StatementKind::Unknown
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
187pub struct Statement {
188 pub kind: StatementKind,
189 #[serde(default)]
190 pub value: Value,
191 pub indent: usize,
192 pub line: usize,
193 pub column: usize,
194}
195
196impl Statement {
197 pub fn new(
198 kind: StatementKind,
199 value: Value,
200 indent: usize,
201 line: usize,
202 column: usize,
203 ) -> Self {
204 Self {
205 kind,
206 value,
207 indent,
208 line,
209 column,
210 }
211 }
212
213 pub fn tempo(value: f32, line: usize, column: usize) -> Self {
214 Self::new(StatementKind::Tempo, Value::Number(value), 0, line, column)
215 }
216
217 pub fn print(message: impl Into<String>, line: usize, column: usize) -> Self {
218 Self::new(
219 StatementKind::Print,
220 Value::String(message.into()),
221 0,
222 line,
223 column,
224 )
225 }
226
227 pub fn trigger(
228 entity: impl Into<String>,
229 duration: DurationValue,
230 effects: Option<Value>,
231 line: usize,
232 column: usize,
233 ) -> Self {
234 Self::new(
235 StatementKind::Trigger {
236 entity: entity.into(),
237 duration,
238 effects,
239 },
240 Value::Null,
241 0,
242 line,
243 column,
244 )
245 }
246
247 pub fn unknown() -> Self {
248 Self::default()
249 }
250
251 pub fn unknown_with_pos(indent: usize, line: usize, column: usize) -> Self {
252 Self::new(StatementKind::Unknown, Value::Null, indent, line, column)
253 }
254
255 pub fn error_with_pos(indent: usize, line: usize, column: usize, message: String) -> Self {
256 Self::new(
257 StatementKind::Error { message },
258 Value::Null,
259 indent,
260 line,
261 column,
262 )
263 }
264}