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("plugin_author".to_string(), Value::String(parts[1].to_string()));
125 map.insert("plugin_name".to_string(), Value::String(parts[2].to_string()));
126 if parts.len() >= 4 {
127 map.insert("plugin_export".to_string(), Value::String(parts[3].to_string()));
128 }
129 }
130 } else {
131 map.insert("waveform".to_string(), Value::String(input.to_string()));
132 }
133
134 map
135 }));
136 };
137
138 let params_str = params_str.trim_matches(|c| c == '{' || c == '}').trim();
140 let mut params_map = HashMap::new();
141
142 params_map.insert("type".to_string(), Value::String("synth".to_string()));
144
145 if !waveform_or_plugin.is_empty() {
147 if waveform_or_plugin.contains('.') {
149 params_map.insert("_plugin_ref".to_string(), Value::String(waveform_or_plugin.to_string()));
151
152 if waveform_or_plugin.starts_with("plugin.") {
154 let parts: Vec<&str> = waveform_or_plugin.split('.').collect();
155 if parts.len() >= 3 {
156 params_map.insert("plugin_author".to_string(), Value::String(parts[1].to_string()));
157 params_map.insert("plugin_name".to_string(), Value::String(parts[2].to_string()));
158 if parts.len() >= 4 {
159 params_map.insert("plugin_export".to_string(), Value::String(parts[3].to_string()));
160 }
161 }
162 }
163 } else {
164 params_map.insert("waveform".to_string(), Value::String(waveform_or_plugin.to_string()));
166 }
167 }
168
169 if !params_str.is_empty() {
171 let mut cleaned_lines = Vec::new();
173 for line in params_str.lines() {
174 if let Some(comment_pos) = line.find("//") {
175 let clean_line = &line[..comment_pos];
176 if !clean_line.trim().is_empty() {
177 cleaned_lines.push(clean_line);
178 }
179 } else if !line.trim().is_empty() {
180 cleaned_lines.push(line);
181 }
182 }
183
184 let cleaned = cleaned_lines.join("\n");
186 let normalized = cleaned.replace('\n', ",").replace('\r', "");
187
188 for pair in normalized.split(',') {
189 let pair = pair.trim();
190 if pair.is_empty() {
191 continue;
192 }
193
194 let parts: Vec<&str> = pair.split(':').collect();
195 if parts.len() >= 2 {
196 let key = parts[0].trim().to_string();
197 let value_part = parts[1..].join(":");
199 let value_str = value_part.trim().trim_matches(',').trim_matches('"');
200
201 if value_str.starts_with('[') {
203 if let Ok(array_val) = parse_array_value(value_str) {
204 params_map.insert(key, array_val);
205 continue;
206 }
207 }
208
209 if let Ok(num) = value_str.parse::<f32>() {
211 params_map.insert(key, Value::Number(num));
212 } else {
213 params_map.insert(key, Value::String(value_str.to_string()));
215 }
216 }
217 }
218 }
219
220 Ok(Value::Map(params_map))
221}
222
223pub fn parse_array_value(input: &str) -> Result<Value> {
225 let input = input.trim().trim_matches(|c| c == '[' || c == ']').trim();
226 if input.is_empty() {
227 return Ok(Value::Array(Vec::new()));
228 }
229
230 if input.contains("..") {
232 let parts: Vec<&str> = input.split("..").collect();
233 if parts.len() == 2 {
234 let start_str = parts[0].trim();
235 let end_str = parts[1].trim();
236
237 if let (Ok(start), Ok(end)) = (start_str.parse::<f32>(), end_str.parse::<f32>()) {
239 return Ok(Value::Range {
240 start: Box::new(Value::Number(start)),
241 end: Box::new(Value::Number(end)),
242 });
243 }
244 }
245 }
246
247 let mut items = Vec::new();
248 let mut depth = 0;
249 let mut current = String::new();
250
251 for ch in input.chars() {
252 match ch {
253 '{' => {
254 depth += 1;
255 current.push(ch);
256 }
257 '}' => {
258 depth -= 1;
259 current.push(ch);
260
261 if depth == 0 && !current.trim().is_empty() {
262 if let Ok(obj) = parse_map_value(¤t) {
264 items.push(obj);
265 }
266 current.clear();
267 }
268 }
269 ',' if depth == 0 => {
270 continue;
272 }
273 _ => {
274 current.push(ch);
275 }
276 }
277 }
278
279 Ok(Value::Array(items))
280}
281
282pub fn parse_map_value(input: &str) -> Result<Value> {
284 let input = input.trim().trim_matches(|c| c == '{' || c == '}').trim();
285 let mut map = HashMap::new();
286
287 for pair in input.split(',') {
288 let pair = pair.trim();
289 if pair.is_empty() {
290 continue;
291 }
292
293 let parts: Vec<&str> = pair.split(':').collect();
294 if parts.len() >= 2 {
295 let key = parts[0].trim().to_string();
296 let value_part = parts[1..].join(":");
298
299 let value_clean = if let Some(comment_pos) = value_part.find("//") {
301 &value_part[..comment_pos]
302 } else {
303 &value_part
304 };
305
306 let value_str = value_clean.trim().trim_matches('"').trim_matches('\'');
307
308 if let Ok(num) = value_str.parse::<f32>() {
310 map.insert(key, Value::Number(num));
311 } else {
312 map.insert(key, Value::String(value_str.to_string()));
313 }
314 }
315 }
316
317 Ok(Value::Map(map))
318}
319
320pub fn parse_condition(condition_str: &str) -> Result<Value> {
323 let operators = vec![">=", "<=", "==", "!=", ">", "<"];
325 for op in operators {
326 if let Some(idx) = condition_str.find(op) {
327 let left = condition_str[..idx].trim();
328 let right = condition_str[idx + op.len()..].trim();
329
330 let mut map = HashMap::new();
332 map.insert("operator".to_string(), Value::String(op.to_string()));
333 map.insert(
334 "left".to_string(),
335 if let Ok(num) = left.parse::<f32>() {
336 Value::Number(num)
337 } else {
338 Value::Identifier(left.to_string())
339 },
340 );
341 map.insert(
342 "right".to_string(),
343 if let Ok(num) = right.parse::<f32>() {
344 Value::Number(num)
345 } else {
346 Value::Identifier(right.to_string())
347 },
348 );
349
350 return Ok(Value::Map(map));
351 }
352 }
353
354 Ok(Value::Identifier(condition_str.to_string()))
356}