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 {
157 map.insert("waveform".to_string(), Value::String(input.to_string()));
158 }
159
160 map
161 }));
162 };
163
164 let params_str = params_str.trim_matches(|c| c == '{' || c == '}').trim();
166 let mut params_map = HashMap::new();
167
168 params_map.insert("type".to_string(), Value::String("synth".to_string()));
170
171 if !waveform_or_plugin.is_empty() {
173 if waveform_or_plugin.contains('.') {
175 params_map.insert(
177 "_plugin_ref".to_string(),
178 Value::String(waveform_or_plugin.to_string()),
179 );
180
181 if waveform_or_plugin.starts_with("plugin.") {
183 let parts: Vec<&str> = waveform_or_plugin.split('.').collect();
184 if parts.len() >= 3 {
185 params_map.insert(
186 "plugin_author".to_string(),
187 Value::String(parts[1].to_string()),
188 );
189 params_map.insert(
190 "plugin_name".to_string(),
191 Value::String(parts[2].to_string()),
192 );
193 if parts.len() >= 4 {
194 params_map.insert(
195 "plugin_export".to_string(),
196 Value::String(parts[3].to_string()),
197 );
198 }
199 }
200 }
201 } else {
202 params_map.insert(
204 "waveform".to_string(),
205 Value::String(waveform_or_plugin.to_string()),
206 );
207 }
208 }
209
210 if !params_str.is_empty() {
212 let mut cleaned_lines = Vec::new();
214 for line in params_str.lines() {
215 if let Some(comment_pos) = line.find("//") {
216 let clean_line = &line[..comment_pos];
217 if !clean_line.trim().is_empty() {
218 cleaned_lines.push(clean_line);
219 }
220 } else if !line.trim().is_empty() {
221 cleaned_lines.push(line);
222 }
223 }
224
225 let cleaned = cleaned_lines.join("\n");
227 let normalized = cleaned.replace('\n', ",").replace('\r', "");
228
229 for pair in normalized.split(',') {
230 let pair = pair.trim();
231 if pair.is_empty() {
232 continue;
233 }
234
235 let parts: Vec<&str> = pair.split(':').collect();
236 if parts.len() >= 2 {
237 let key = parts[0].trim().to_string();
238 let value_part = parts[1..].join(":");
240 let value_str = value_part.trim().trim_matches(',').trim_matches('"');
241
242 if value_str.starts_with('[') {
244 if let Ok(array_val) = parse_array_value(value_str) {
245 params_map.insert(key, array_val);
246 continue;
247 }
248 }
249
250 if let Ok(num) = value_str.parse::<f32>() {
252 params_map.insert(key, Value::Number(num));
253 } else {
254 params_map.insert(key, Value::String(value_str.to_string()));
256 }
257 }
258 }
259 }
260
261 Ok(Value::Map(params_map))
262}
263
264pub fn parse_array_value(input: &str) -> Result<Value> {
266 let input = input.trim().trim_matches(|c| c == '[' || c == ']').trim();
267 if input.is_empty() {
268 return Ok(Value::Array(Vec::new()));
269 }
270
271 if input.contains("..") {
273 let parts: Vec<&str> = input.split("..").collect();
274 if parts.len() == 2 {
275 let start_str = parts[0].trim();
276 let end_str = parts[1].trim();
277
278 if let (Ok(start), Ok(end)) = (start_str.parse::<f32>(), end_str.parse::<f32>()) {
280 return Ok(Value::Range {
281 start: Box::new(Value::Number(start)),
282 end: Box::new(Value::Number(end)),
283 });
284 }
285 }
286 }
287
288 let mut items = Vec::new();
289 let mut depth = 0;
290 let mut current = String::new();
291
292 for ch in input.chars() {
293 match ch {
294 '{' => {
295 depth += 1;
296 current.push(ch);
297 }
298 '}' => {
299 depth -= 1;
300 current.push(ch);
301
302 if depth == 0 && !current.trim().is_empty() {
303 if let Ok(obj) = parse_map_value(¤t) {
305 items.push(obj);
306 }
307 current.clear();
308 }
309 }
310 ',' if depth == 0 => {
311 let token = current.trim();
313 if !token.is_empty() {
314 if let Ok(val) = parse_single_arg(token) {
316 if let Value::Map(_) = val {
320 items.push(val);
321 } else {
322 let mut map = HashMap::new();
323 let idx = items.len();
324 map.insert("index".to_string(), Value::Number(idx as f32));
325 map.insert("value".to_string(), val);
326 items.push(Value::Map(map));
327 }
328 }
329 }
330 current.clear();
331 continue;
332 }
333 _ => {
334 current.push(ch);
335 }
336 }
337 }
338
339 if !current.trim().is_empty() {
341 let token = current.trim();
342 if !token.is_empty() {
344 if let Ok(val) = parse_single_arg(token) {
345 items.push(val);
346 }
347 }
348 }
349
350 Ok(Value::Array(items))
351}
352
353pub fn parse_map_value(input: &str) -> Result<Value> {
355 let input = input.trim().trim_matches(|c| c == '{' || c == '}').trim();
356 let mut map = HashMap::new();
357
358 for pair in input.split(',') {
359 let pair = pair.trim();
360 if pair.is_empty() {
361 continue;
362 }
363
364 let parts: Vec<&str> = pair.split(':').collect();
365 if parts.len() >= 2 {
366 let key = parts[0].trim().to_string();
367 let value_part = parts[1..].join(":");
369
370 let value_clean = if let Some(comment_pos) = value_part.find("//") {
372 &value_part[..comment_pos]
373 } else {
374 &value_part
375 };
376
377 let value_str = value_clean.trim().trim_matches('"').trim_matches('\'');
378
379 if let Ok(num) = value_str.parse::<f32>() {
381 map.insert(key, Value::Number(num));
382 } else {
383 map.insert(key, Value::String(value_str.to_string()));
384 }
385 }
386 }
387
388 Ok(Value::Map(map))
389}
390
391pub fn parse_condition(condition_str: &str) -> Result<Value> {
394 let operators = vec![">=", "<=", "==", "!=", ">", "<"];
396 for op in operators {
397 if let Some(idx) = condition_str.find(op) {
398 let left = condition_str[..idx].trim();
399 let right = condition_str[idx + op.len()..].trim();
400
401 let mut map = HashMap::new();
403 map.insert("operator".to_string(), Value::String(op.to_string()));
404 map.insert(
405 "left".to_string(),
406 if let Ok(num) = left.parse::<f32>() {
407 Value::Number(num)
408 } else {
409 Value::Identifier(left.to_string())
410 },
411 );
412 map.insert(
413 "right".to_string(),
414 if let Ok(num) = right.parse::<f32>() {
415 Value::Number(num)
416 } else {
417 Value::Identifier(right.to_string())
418 },
419 );
420
421 return Ok(Value::Map(map));
422 }
423 }
424
425 Ok(Value::Identifier(condition_str.to_string()))
427}