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 if let Some(open_paren) = arg.find('(') {
89 if arg.ends_with(')') {
90 let name = arg[..open_paren].trim().to_string();
91 let args_str = &arg[open_paren + 1..arg.len() - 1];
92 let parsed_args = if args_str.trim().is_empty() {
93 Vec::new()
94 } else {
95 parse_function_args(args_str)?
96 };
97 return Ok(Value::Call {
98 name,
99 args: parsed_args,
100 });
101 }
102 }
103
104 match arg.to_lowercase().as_str() {
106 "true" => return Ok(Value::Boolean(true)),
107 "false" => return Ok(Value::Boolean(false)),
108 _ => {}
109 }
110
111 Ok(Value::Identifier(arg.to_string()))
113}
114
115pub fn parse_synth_definition(input: &str) -> Result<Value> {
124 let input = input.trim();
126 let input = if input == "synth" {
127 ""
128 } else {
129 input.strip_prefix("synth ").map(str::trim).unwrap_or(input)
130 };
131
132 let (waveform_or_plugin, params_str) = if let Some(brace_idx) = input.find('{') {
134 let before_brace = input[..brace_idx].trim();
135 let params = &input[brace_idx..];
136 (before_brace, params)
137 } else {
138 return Ok(Value::Map({
140 let mut map = HashMap::new();
141 map.insert("type".to_string(), Value::String("synth".to_string()));
142
143 if input.is_empty() {
144 } else if input.starts_with("plugin.") {
147 let parts: Vec<&str> = input.split('.').collect();
149 if parts.len() >= 3 {
150 map.insert(
151 "plugin_author".to_string(),
152 Value::String(parts[1].to_string()),
153 );
154 map.insert(
155 "plugin_name".to_string(),
156 Value::String(parts[2].to_string()),
157 );
158 if parts.len() >= 4 {
159 map.insert(
160 "plugin_export".to_string(),
161 Value::String(parts[3].to_string()),
162 );
163 }
164 }
165 } else if input.contains('.') {
166 map.insert("_plugin_ref".to_string(), Value::String(input.to_string()));
168 } else {
169 map.insert("_deprecated_shorthand".to_string(), Value::Boolean(true));
173 map.insert("waveform".to_string(), Value::String(input.to_string()));
174 }
175
176 map
177 }));
178 };
179
180 let params_str = params_str.trim_matches(|c| c == '{' || c == '}').trim();
182 let mut params_map = HashMap::new();
183
184 params_map.insert("type".to_string(), Value::String("synth".to_string()));
186
187 if !waveform_or_plugin.is_empty() {
189 if waveform_or_plugin.contains('.') {
191 params_map.insert(
193 "_plugin_ref".to_string(),
194 Value::String(waveform_or_plugin.to_string()),
195 );
196
197 if waveform_or_plugin.starts_with("plugin.") {
199 let parts: Vec<&str> = waveform_or_plugin.split('.').collect();
200 if parts.len() >= 3 {
201 params_map.insert(
202 "plugin_author".to_string(),
203 Value::String(parts[1].to_string()),
204 );
205 params_map.insert(
206 "plugin_name".to_string(),
207 Value::String(parts[2].to_string()),
208 );
209 if parts.len() >= 4 {
210 params_map.insert(
211 "plugin_export".to_string(),
212 Value::String(parts[3].to_string()),
213 );
214 }
215 }
216 }
217 } else {
218 params_map.insert(
220 "waveform".to_string(),
221 Value::String(waveform_or_plugin.to_string()),
222 );
223 }
224 }
225
226 if !params_str.is_empty() {
228 let mut cleaned_lines = Vec::new();
230 for line in params_str.lines() {
231 if let Some(comment_pos) = line.find("//") {
232 let clean_line = &line[..comment_pos];
233 if !clean_line.trim().is_empty() {
234 cleaned_lines.push(clean_line);
235 }
236 } else if !line.trim().is_empty() {
237 cleaned_lines.push(line);
238 }
239 }
240
241 let cleaned = cleaned_lines.join("\n");
243 let normalized = cleaned.replace('\n', ",").replace('\r', "");
244
245 for pair in normalized.split(',') {
246 let pair = pair.trim();
247 if pair.is_empty() {
248 continue;
249 }
250
251 let parts: Vec<&str> = pair.split(':').collect();
252 if parts.len() >= 2 {
253 let key = parts[0].trim().to_string();
254 let value_part = parts[1..].join(":");
256 let value_str = value_part.trim().trim_matches(',').trim_matches('"');
257
258 if value_str.starts_with('[') {
260 if let Ok(array_val) = parse_array_value(value_str) {
261 params_map.insert(key, array_val);
262 continue;
263 }
264 }
265
266 if let Ok(num) = value_str.parse::<f32>() {
268 params_map.insert(key, Value::Number(num));
269 } else {
270 params_map.insert(key, Value::String(value_str.to_string()));
272 }
273 }
274 }
275 }
276
277 Ok(Value::Map(params_map))
278}
279
280pub fn parse_array_value(input: &str) -> Result<Value> {
282 let input = input.trim().trim_matches(|c| c == '[' || c == ']').trim();
283 if input.is_empty() {
284 return Ok(Value::Array(Vec::new()));
285 }
286
287 if input.contains("..") {
289 let parts: Vec<&str> = input.split("..").collect();
290 if parts.len() == 2 {
291 let start_str = parts[0].trim();
292 let end_str = parts[1].trim();
293
294 if let (Ok(start), Ok(end)) = (start_str.parse::<f32>(), end_str.parse::<f32>()) {
296 return Ok(Value::Range {
297 start: Box::new(Value::Number(start)),
298 end: Box::new(Value::Number(end)),
299 });
300 }
301 }
302 }
303
304 let mut items = Vec::new();
305 let mut depth = 0;
306 let mut current = String::new();
307
308 for ch in input.chars() {
309 match ch {
310 '{' => {
311 depth += 1;
312 current.push(ch);
313 }
314 '}' => {
315 depth -= 1;
316 current.push(ch);
317
318 if depth == 0 && !current.trim().is_empty() {
319 if let Ok(obj) = parse_map_value(¤t) {
321 items.push(obj);
322 }
323 current.clear();
324 }
325 }
326 ',' if depth == 0 => {
327 let token = current.trim();
329 if !token.is_empty() {
330 if let Ok(val) = parse_single_arg(token) {
332 if let Value::Map(_) = val {
336 items.push(val);
337 } else {
338 let mut map = HashMap::new();
339 let idx = items.len();
340 map.insert("index".to_string(), Value::Number(idx as f32));
341 map.insert("value".to_string(), val);
342 items.push(Value::Map(map));
343 }
344 }
345 }
346 current.clear();
347 continue;
348 }
349 _ => {
350 current.push(ch);
351 }
352 }
353 }
354
355 if !current.trim().is_empty() {
357 let token = current.trim();
358 if !token.is_empty() {
360 if let Ok(val) = parse_single_arg(token) {
361 items.push(val);
362 }
363 }
364 }
365
366 Ok(Value::Array(items))
367}
368
369pub fn parse_map_value(input: &str) -> Result<Value> {
371 let input = input.trim().trim_matches(|c| c == '{' || c == '}').trim();
372 let mut map = HashMap::new();
373
374 for pair in input.split(',') {
375 let pair = pair.trim();
376 if pair.is_empty() {
377 continue;
378 }
379
380 let parts: Vec<&str> = pair.split(':').collect();
381 if parts.len() >= 2 {
382 let key = parts[0].trim().to_string();
383 let value_part = parts[1..].join(":");
385
386 let value_clean = if let Some(comment_pos) = value_part.find("//") {
388 &value_part[..comment_pos]
389 } else {
390 &value_part
391 };
392
393 let value_str = value_clean.trim().trim_matches('"').trim_matches('\'');
394
395 if let Ok(num) = value_str.parse::<f32>() {
397 map.insert(key, Value::Number(num));
398 } else {
399 map.insert(key, Value::String(value_str.to_string()));
400 }
401 }
402 }
403
404 Ok(Value::Map(map))
405}
406
407fn find_word_boundary(text: &str, keyword: &str) -> Option<usize> {
410 text.rfind(keyword).and_then(|idx| {
412 let before_ok =
414 idx == 0 || !text[..idx].ends_with(|c: char| c.is_alphanumeric() || c == '_');
415 let after_idx = idx + keyword.len();
416 let after_ok = after_idx >= text.len()
417 || !text[after_idx..].starts_with(|c: char| c.is_alphanumeric() || c == '_');
418
419 if before_ok && after_ok {
420 Some(idx)
421 } else {
422 None
423 }
424 })
425}
426
427pub fn parse_condition(condition_str: &str) -> Result<Value> {
431 let condition_str = condition_str.trim();
432
433 if let Some(idx) = condition_str.rfind("||") {
435 let left = parse_condition(&condition_str[..idx].trim())?;
436 let right = parse_condition(&condition_str[idx + 2..].trim())?;
437
438 let mut map = HashMap::new();
439 map.insert("operator".to_string(), Value::String("||".to_string()));
440 map.insert("left".to_string(), left);
441 map.insert("right".to_string(), right);
442 return Ok(Value::Map(map));
443 }
444
445 if let Some(idx) = find_word_boundary(condition_str, " or ") {
447 let left = parse_condition(&condition_str[..idx].trim())?;
448 let right = parse_condition(&condition_str[idx + 4..].trim())?;
449
450 let mut map = HashMap::new();
451 map.insert("operator".to_string(), Value::String("||".to_string()));
452 map.insert("left".to_string(), left);
453 map.insert("right".to_string(), right);
454 return Ok(Value::Map(map));
455 }
456
457 if let Some(idx) = condition_str.rfind("&&") {
459 let left = parse_condition(&condition_str[..idx].trim())?;
460 let right = parse_condition(&condition_str[idx + 2..].trim())?;
461
462 let mut map = HashMap::new();
463 map.insert("operator".to_string(), Value::String("&&".to_string()));
464 map.insert("left".to_string(), left);
465 map.insert("right".to_string(), right);
466 return Ok(Value::Map(map));
467 }
468
469 if let Some(idx) = find_word_boundary(condition_str, " and ") {
471 let left = parse_condition(&condition_str[..idx].trim())?;
472 let right = parse_condition(&condition_str[idx + 5..].trim())?;
473
474 let mut map = HashMap::new();
475 map.insert("operator".to_string(), Value::String("&&".to_string()));
476 map.insert("left".to_string(), left);
477 map.insert("right".to_string(), right);
478 return Ok(Value::Map(map));
479 }
480
481 if condition_str.starts_with('!') {
483 let inner = parse_condition(&condition_str[1..].trim())?;
484
485 let mut map = HashMap::new();
486 map.insert("operator".to_string(), Value::String("!".to_string()));
487 map.insert("operand".to_string(), inner);
488 return Ok(Value::Map(map));
489 }
490
491 if condition_str.starts_with("not ") {
493 let inner = parse_condition(&condition_str[4..].trim())?;
494
495 let mut map = HashMap::new();
496 map.insert("operator".to_string(), Value::String("!".to_string()));
497 map.insert("operand".to_string(), inner);
498 return Ok(Value::Map(map));
499 }
500
501 let operators = vec![">=", "<=", "==", "!=", ">", "<"];
503 for op in operators {
504 if let Some(idx) = condition_str.find(op) {
505 let left = condition_str[..idx].trim();
506 let right = condition_str[idx + op.len()..].trim();
507
508 let mut map = HashMap::new();
510 map.insert("operator".to_string(), Value::String(op.to_string()));
511 map.insert(
512 "left".to_string(),
513 if let Ok(num) = left.parse::<f32>() {
514 Value::Number(num)
515 } else {
516 Value::Identifier(left.to_string())
517 },
518 );
519 map.insert(
520 "right".to_string(),
521 if let Ok(num) = right.parse::<f32>() {
522 Value::Number(num)
523 } else {
524 Value::Identifier(right.to_string())
525 },
526 );
527
528 return Ok(Value::Map(map));
529 }
530 }
531
532 Ok(Value::Identifier(condition_str.to_string()))
534}