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> {
123 let input = input.trim_start_matches("synth ").trim();
125
126 let (waveform_or_plugin, params_str) = if let Some(brace_idx) = input.find('{') {
128 let before_brace = input[..brace_idx].trim();
129 let params = &input[brace_idx..];
130 (before_brace, params)
131 } else {
132 return Ok(Value::Map({
134 let mut map = HashMap::new();
135 map.insert("type".to_string(), Value::String("synth".to_string()));
136
137 if input.starts_with("plugin.") {
139 let parts: Vec<&str> = input.split('.').collect();
140 if parts.len() >= 3 {
141 map.insert(
142 "plugin_author".to_string(),
143 Value::String(parts[1].to_string()),
144 );
145 map.insert(
146 "plugin_name".to_string(),
147 Value::String(parts[2].to_string()),
148 );
149 if parts.len() >= 4 {
150 map.insert(
151 "plugin_export".to_string(),
152 Value::String(parts[3].to_string()),
153 );
154 }
155 }
156 } else if input.contains('.') {
157 map.insert("_plugin_ref".to_string(), Value::String(input.to_string()));
159 } else {
160 map.insert("waveform".to_string(), Value::String(input.to_string()));
162 }
163
164 map
165 }));
166 };
167
168 let params_str = params_str.trim_matches(|c| c == '{' || c == '}').trim();
170 let mut params_map = HashMap::new();
171
172 params_map.insert("type".to_string(), Value::String("synth".to_string()));
174
175 if !waveform_or_plugin.is_empty() {
177 if waveform_or_plugin.contains('.') {
179 params_map.insert(
181 "_plugin_ref".to_string(),
182 Value::String(waveform_or_plugin.to_string()),
183 );
184
185 if waveform_or_plugin.starts_with("plugin.") {
187 let parts: Vec<&str> = waveform_or_plugin.split('.').collect();
188 if parts.len() >= 3 {
189 params_map.insert(
190 "plugin_author".to_string(),
191 Value::String(parts[1].to_string()),
192 );
193 params_map.insert(
194 "plugin_name".to_string(),
195 Value::String(parts[2].to_string()),
196 );
197 if parts.len() >= 4 {
198 params_map.insert(
199 "plugin_export".to_string(),
200 Value::String(parts[3].to_string()),
201 );
202 }
203 }
204 }
205 } else {
206 params_map.insert(
208 "waveform".to_string(),
209 Value::String(waveform_or_plugin.to_string()),
210 );
211 }
212 }
213
214 if !params_str.is_empty() {
216 let mut cleaned_lines = Vec::new();
218 for line in params_str.lines() {
219 if let Some(comment_pos) = line.find("//") {
220 let clean_line = &line[..comment_pos];
221 if !clean_line.trim().is_empty() {
222 cleaned_lines.push(clean_line);
223 }
224 } else if !line.trim().is_empty() {
225 cleaned_lines.push(line);
226 }
227 }
228
229 let cleaned = cleaned_lines.join("\n");
231 let normalized = cleaned.replace('\n', ",").replace('\r', "");
232
233 for pair in normalized.split(',') {
234 let pair = pair.trim();
235 if pair.is_empty() {
236 continue;
237 }
238
239 let parts: Vec<&str> = pair.split(':').collect();
240 if parts.len() >= 2 {
241 let key = parts[0].trim().to_string();
242 let value_part = parts[1..].join(":");
244 let value_str = value_part.trim().trim_matches(',').trim_matches('"');
245
246 if value_str.starts_with('[') {
248 if let Ok(array_val) = parse_array_value(value_str) {
249 params_map.insert(key, array_val);
250 continue;
251 }
252 }
253
254 if let Ok(num) = value_str.parse::<f32>() {
256 params_map.insert(key, Value::Number(num));
257 } else {
258 params_map.insert(key, Value::String(value_str.to_string()));
260 }
261 }
262 }
263 }
264
265 Ok(Value::Map(params_map))
266}
267
268pub fn parse_array_value(input: &str) -> Result<Value> {
270 let input = input.trim().trim_matches(|c| c == '[' || c == ']').trim();
271 if input.is_empty() {
272 return Ok(Value::Array(Vec::new()));
273 }
274
275 if input.contains("..") {
277 let parts: Vec<&str> = input.split("..").collect();
278 if parts.len() == 2 {
279 let start_str = parts[0].trim();
280 let end_str = parts[1].trim();
281
282 if let (Ok(start), Ok(end)) = (start_str.parse::<f32>(), end_str.parse::<f32>()) {
284 return Ok(Value::Range {
285 start: Box::new(Value::Number(start)),
286 end: Box::new(Value::Number(end)),
287 });
288 }
289 }
290 }
291
292 let mut items = Vec::new();
293 let mut depth = 0;
294 let mut current = String::new();
295
296 for ch in input.chars() {
297 match ch {
298 '{' => {
299 depth += 1;
300 current.push(ch);
301 }
302 '}' => {
303 depth -= 1;
304 current.push(ch);
305
306 if depth == 0 && !current.trim().is_empty() {
307 if let Ok(obj) = parse_map_value(¤t) {
309 items.push(obj);
310 }
311 current.clear();
312 }
313 }
314 ',' if depth == 0 => {
315 let token = current.trim();
317 if !token.is_empty() {
318 if let Ok(val) = parse_single_arg(token) {
320 if let Value::Map(_) = val {
324 items.push(val);
325 } else {
326 let mut map = HashMap::new();
327 let idx = items.len();
328 map.insert("index".to_string(), Value::Number(idx as f32));
329 map.insert("value".to_string(), val);
330 items.push(Value::Map(map));
331 }
332 }
333 }
334 current.clear();
335 continue;
336 }
337 _ => {
338 current.push(ch);
339 }
340 }
341 }
342
343 if !current.trim().is_empty() {
345 let token = current.trim();
346 if !token.is_empty() {
348 if let Ok(val) = parse_single_arg(token) {
349 items.push(val);
350 }
351 }
352 }
353
354 Ok(Value::Array(items))
355}
356
357pub fn parse_map_value(input: &str) -> Result<Value> {
359 let input = input.trim().trim_matches(|c| c == '{' || c == '}').trim();
360 let mut map = HashMap::new();
361
362 for pair in input.split(',') {
363 let pair = pair.trim();
364 if pair.is_empty() {
365 continue;
366 }
367
368 let parts: Vec<&str> = pair.split(':').collect();
369 if parts.len() >= 2 {
370 let key = parts[0].trim().to_string();
371 let value_part = parts[1..].join(":");
373
374 let value_clean = if let Some(comment_pos) = value_part.find("//") {
376 &value_part[..comment_pos]
377 } else {
378 &value_part
379 };
380
381 let value_str = value_clean.trim().trim_matches('"').trim_matches('\'');
382
383 if let Ok(num) = value_str.parse::<f32>() {
385 map.insert(key, Value::Number(num));
386 } else {
387 map.insert(key, Value::String(value_str.to_string()));
388 }
389 }
390 }
391
392 Ok(Value::Map(map))
393}
394
395fn find_word_boundary(text: &str, keyword: &str) -> Option<usize> {
398 text.rfind(keyword).and_then(|idx| {
400 let before_ok =
402 idx == 0 || !text[..idx].ends_with(|c: char| c.is_alphanumeric() || c == '_');
403 let after_idx = idx + keyword.len();
404 let after_ok = after_idx >= text.len()
405 || !text[after_idx..].starts_with(|c: char| c.is_alphanumeric() || c == '_');
406
407 if before_ok && after_ok {
408 Some(idx)
409 } else {
410 None
411 }
412 })
413}
414
415pub fn parse_condition(condition_str: &str) -> Result<Value> {
419 let condition_str = condition_str.trim();
420
421 if let Some(idx) = condition_str.rfind("||") {
423 let left = parse_condition(&condition_str[..idx].trim())?;
424 let right = parse_condition(&condition_str[idx + 2..].trim())?;
425
426 let mut map = HashMap::new();
427 map.insert("operator".to_string(), Value::String("||".to_string()));
428 map.insert("left".to_string(), left);
429 map.insert("right".to_string(), right);
430 return Ok(Value::Map(map));
431 }
432
433 if let Some(idx) = find_word_boundary(condition_str, " or ") {
435 let left = parse_condition(&condition_str[..idx].trim())?;
436 let right = parse_condition(&condition_str[idx + 4..].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) = condition_str.rfind("&&") {
447 let left = parse_condition(&condition_str[..idx].trim())?;
448 let right = parse_condition(&condition_str[idx + 2..].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) = find_word_boundary(condition_str, " and ") {
459 let left = parse_condition(&condition_str[..idx].trim())?;
460 let right = parse_condition(&condition_str[idx + 5..].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 condition_str.starts_with('!') {
471 let inner = parse_condition(&condition_str[1..].trim())?;
472
473 let mut map = HashMap::new();
474 map.insert("operator".to_string(), Value::String("!".to_string()));
475 map.insert("operand".to_string(), inner);
476 return Ok(Value::Map(map));
477 }
478
479 if condition_str.starts_with("not ") {
481 let inner = parse_condition(&condition_str[4..].trim())?;
482
483 let mut map = HashMap::new();
484 map.insert("operator".to_string(), Value::String("!".to_string()));
485 map.insert("operand".to_string(), inner);
486 return Ok(Value::Map(map));
487 }
488
489 let operators = vec![">=", "<=", "==", "!=", ">", "<"];
491 for op in operators {
492 if let Some(idx) = condition_str.find(op) {
493 let left = condition_str[..idx].trim();
494 let right = condition_str[idx + op.len()..].trim();
495
496 let mut map = HashMap::new();
498 map.insert("operator".to_string(), Value::String(op.to_string()));
499 map.insert(
500 "left".to_string(),
501 if let Ok(num) = left.parse::<f32>() {
502 Value::Number(num)
503 } else {
504 Value::Identifier(left.to_string())
505 },
506 );
507 map.insert(
508 "right".to_string(),
509 if let Ok(num) = right.parse::<f32>() {
510 Value::Number(num)
511 } else {
512 Value::Identifier(right.to_string())
513 },
514 );
515
516 return Ok(Value::Map(map));
517 }
518 }
519
520 Ok(Value::Identifier(condition_str.to_string()))
522}