devalang_wasm/language/syntax/parser/driver/
helpers.rs1use crate::language::syntax::ast::Value;
2use anyhow::Result;
4use std::collections::HashMap;
5
6pub fn parse_function_args(args_str: &str) -> Result<Vec<Value>> {
9 let mut args = Vec::new();
10 let mut current_arg = String::new();
11 let mut depth = 0; let mut in_string = false;
13
14 for ch in args_str.chars() {
15 match ch {
16 '"' => {
17 in_string = !in_string;
18 current_arg.push(ch);
19 }
20 '[' | '{' if !in_string => {
21 depth += 1;
22 current_arg.push(ch);
23 }
24 ']' | '}' if !in_string => {
25 depth -= 1;
26 current_arg.push(ch);
27 }
28 ',' if depth == 0 && !in_string => {
29 if !current_arg.trim().is_empty() {
31 args.push(parse_single_arg(current_arg.trim())?);
32 current_arg.clear();
33 }
34 }
35 _ => {
36 current_arg.push(ch);
37 }
38 }
39 }
40
41 if !current_arg.trim().is_empty() {
43 args.push(parse_single_arg(current_arg.trim())?);
44 }
45
46 Ok(args)
47}
48
49pub fn parse_single_arg(arg: &str) -> Result<Value> {
51 let arg = arg.trim();
52
53 if arg.starts_with('"') && arg.ends_with('"') {
55 return Ok(Value::String(arg[1..arg.len() - 1].to_string()));
56 }
57
58 if arg.starts_with('[') && arg.ends_with(']') {
60 let inner = &arg[1..arg.len() - 1];
61 let items = parse_function_args(inner)?;
62 return Ok(Value::Array(items));
63 }
64
65 if arg.starts_with('{') && arg.ends_with('}') {
67 let inner = &arg[1..arg.len() - 1];
68 let mut map = HashMap::new();
69
70 for pair in inner.split(',') {
72 if let Some(colon_idx) = pair.find(':') {
73 let key = pair[..colon_idx].trim().trim_matches('"');
74 let value = parse_single_arg(pair[colon_idx + 1..].trim())?;
75 map.insert(key.to_string(), value);
76 }
77 }
78
79 return Ok(Value::Map(map));
80 }
81
82 if let Ok(num) = arg.parse::<f32>() {
84 return Ok(Value::Number(num));
85 }
86
87 match arg.to_lowercase().as_str() {
89 "true" => return Ok(Value::Boolean(true)),
90 "false" => return Ok(Value::Boolean(false)),
91 _ => {}
92 }
93
94 Ok(Value::Identifier(arg.to_string()))
96}
97
98pub fn parse_synth_definition(input: &str) -> Result<Value> {
106 let input = input.trim_start_matches("synth ").trim();
108
109 let (waveform_or_plugin, params_str) = if let Some(brace_idx) = input.find('{') {
111 let before_brace = input[..brace_idx].trim();
112 let params = &input[brace_idx..];
113 (before_brace, params)
114 } else {
115 return Ok(Value::Map({
117 let mut map = HashMap::new();
118 map.insert("type".to_string(), Value::String("synth".to_string()));
119
120 if input.starts_with("plugin.") {
122 let parts: Vec<&str> = input.split('.').collect();
123 if parts.len() >= 3 {
124 map.insert(
125 "plugin_author".to_string(),
126 Value::String(parts[1].to_string()),
127 );
128 map.insert(
129 "plugin_name".to_string(),
130 Value::String(parts[2].to_string()),
131 );
132 if parts.len() >= 4 {
133 map.insert(
134 "plugin_export".to_string(),
135 Value::String(parts[3].to_string()),
136 );
137 }
138 }
139 } else {
140 map.insert("waveform".to_string(), Value::String(input.to_string()));
141 }
142
143 map
144 }));
145 };
146
147 let params_str = params_str.trim_matches(|c| c == '{' || c == '}').trim();
149 let mut params_map = HashMap::new();
150
151 params_map.insert("type".to_string(), Value::String("synth".to_string()));
153
154 if !waveform_or_plugin.is_empty() {
156 if waveform_or_plugin.contains('.') {
158 params_map.insert(
160 "_plugin_ref".to_string(),
161 Value::String(waveform_or_plugin.to_string()),
162 );
163
164 if waveform_or_plugin.starts_with("plugin.") {
166 let parts: Vec<&str> = waveform_or_plugin.split('.').collect();
167 if parts.len() >= 3 {
168 params_map.insert(
169 "plugin_author".to_string(),
170 Value::String(parts[1].to_string()),
171 );
172 params_map.insert(
173 "plugin_name".to_string(),
174 Value::String(parts[2].to_string()),
175 );
176 if parts.len() >= 4 {
177 params_map.insert(
178 "plugin_export".to_string(),
179 Value::String(parts[3].to_string()),
180 );
181 }
182 }
183 }
184 } else {
185 params_map.insert(
187 "waveform".to_string(),
188 Value::String(waveform_or_plugin.to_string()),
189 );
190 }
191 }
192
193 if !params_str.is_empty() {
195 let mut cleaned_lines = Vec::new();
197 for line in params_str.lines() {
198 if let Some(comment_pos) = line.find("//") {
199 let clean_line = &line[..comment_pos];
200 if !clean_line.trim().is_empty() {
201 cleaned_lines.push(clean_line);
202 }
203 } else if !line.trim().is_empty() {
204 cleaned_lines.push(line);
205 }
206 }
207
208 let cleaned = cleaned_lines.join("\n");
210 let normalized = cleaned.replace('\n', ",").replace('\r', "");
211
212 for pair in normalized.split(',') {
213 let pair = pair.trim();
214 if pair.is_empty() {
215 continue;
216 }
217
218 let parts: Vec<&str> = pair.split(':').collect();
219 if parts.len() >= 2 {
220 let key = parts[0].trim().to_string();
221 let value_part = parts[1..].join(":");
223 let value_str = value_part.trim().trim_matches(',').trim_matches('"');
224
225 if value_str.starts_with('[') {
227 if let Ok(array_val) = parse_array_value(value_str) {
228 params_map.insert(key, array_val);
229 continue;
230 }
231 }
232
233 if let Ok(num) = value_str.parse::<f32>() {
235 params_map.insert(key, Value::Number(num));
236 } else {
237 params_map.insert(key, Value::String(value_str.to_string()));
239 }
240 }
241 }
242 }
243
244 Ok(Value::Map(params_map))
245}
246
247pub fn parse_array_value(input: &str) -> Result<Value> {
249 let input = input.trim().trim_matches(|c| c == '[' || c == ']').trim();
250 if input.is_empty() {
251 return Ok(Value::Array(Vec::new()));
252 }
253
254 if input.contains("..") {
256 let parts: Vec<&str> = input.split("..").collect();
257 if parts.len() == 2 {
258 let start_str = parts[0].trim();
259 let end_str = parts[1].trim();
260
261 if let (Ok(start), Ok(end)) = (start_str.parse::<f32>(), end_str.parse::<f32>()) {
263 return Ok(Value::Range {
264 start: Box::new(Value::Number(start)),
265 end: Box::new(Value::Number(end)),
266 });
267 }
268 }
269 }
270
271 let mut items = Vec::new();
272 let mut depth = 0;
273 let mut current = String::new();
274
275 for ch in input.chars() {
276 match ch {
277 '{' => {
278 depth += 1;
279 current.push(ch);
280 }
281 '}' => {
282 depth -= 1;
283 current.push(ch);
284
285 if depth == 0 && !current.trim().is_empty() {
286 if let Ok(obj) = parse_map_value(¤t) {
288 items.push(obj);
289 }
290 current.clear();
291 }
292 }
293 ',' if depth == 0 => {
294 continue;
296 }
297 _ => {
298 current.push(ch);
299 }
300 }
301 }
302
303 Ok(Value::Array(items))
304}
305
306pub fn parse_map_value(input: &str) -> Result<Value> {
308 let input = input.trim().trim_matches(|c| c == '{' || c == '}').trim();
309 let mut map = HashMap::new();
310
311 for pair in input.split(',') {
312 let pair = pair.trim();
313 if pair.is_empty() {
314 continue;
315 }
316
317 let parts: Vec<&str> = pair.split(':').collect();
318 if parts.len() >= 2 {
319 let key = parts[0].trim().to_string();
320 let value_part = parts[1..].join(":");
322
323 let value_clean = if let Some(comment_pos) = value_part.find("//") {
325 &value_part[..comment_pos]
326 } else {
327 &value_part
328 };
329
330 let value_str = value_clean.trim().trim_matches('"').trim_matches('\'');
331
332 if let Ok(num) = value_str.parse::<f32>() {
334 map.insert(key, Value::Number(num));
335 } else {
336 map.insert(key, Value::String(value_str.to_string()));
337 }
338 }
339 }
340
341 Ok(Value::Map(map))
342}
343
344pub fn parse_condition(condition_str: &str) -> Result<Value> {
347 let operators = vec![">=", "<=", "==", "!=", ">", "<"];
349 for op in operators {
350 if let Some(idx) = condition_str.find(op) {
351 let left = condition_str[..idx].trim();
352 let right = condition_str[idx + op.len()..].trim();
353
354 let mut map = HashMap::new();
356 map.insert("operator".to_string(), Value::String(op.to_string()));
357 map.insert(
358 "left".to_string(),
359 if let Ok(num) = left.parse::<f32>() {
360 Value::Number(num)
361 } else {
362 Value::Identifier(left.to_string())
363 },
364 );
365 map.insert(
366 "right".to_string(),
367 if let Ok(num) = right.parse::<f32>() {
368 Value::Number(num)
369 } else {
370 Value::Identifier(right.to_string())
371 },
372 );
373
374 return Ok(Value::Map(map));
375 }
376 }
377
378 Ok(Value::Identifier(condition_str.to_string()))
380}