devalang_wasm/language/syntax/parser/driver/statements/
structure.rs1use super::super::helpers::{parse_array_value, parse_condition};
2use crate::language::syntax::ast::{Statement, StatementKind, Value};
3use anyhow::{Result, anyhow};
5use std::collections::HashMap;
6use std::iter::Iterator;
7
8pub fn parse_pattern(
13 mut parts: impl Iterator<Item = impl AsRef<str>>,
14 line_number: usize,
15) -> Result<Statement> {
16 let name = parts
17 .next()
18 .ok_or_else(|| anyhow!("pattern requires a name"))?
19 .as_ref()
20 .to_string();
21
22 let mut target = None;
23 let mut pattern_str = None;
24 let mut options: HashMap<String, Value> = HashMap::new();
25
26 if let Some(word) = parts.next() {
28 if word.as_ref() == "with" {
29 target = parts.next().map(|v| v.as_ref().to_string());
31
32 let rest: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
34 let joined = rest.join(" ");
35
36 if let Some(brace_start) = joined.find('{') {
38 if let Some(brace_end) = joined.rfind('}') {
39 let options_str = &joined[brace_start + 1..brace_end];
41
42 for pair in options_str.split(',') {
44 let parts: Vec<&str> = pair.split(':').collect();
45 if parts.len() == 2 {
46 let key = parts[0].trim().to_string();
47 let value_str = parts[1].trim();
48
49 let value = if let Ok(num) = value_str.parse::<f32>() {
51 Value::Number(num)
52 } else if value_str == "true" {
53 Value::Boolean(true)
54 } else if value_str == "false" {
55 Value::Boolean(false)
56 } else if value_str.starts_with('"') && value_str.ends_with('"') {
57 Value::String(value_str.trim_matches('"').to_string())
58 } else {
59 Value::Identifier(value_str.to_string())
60 };
61
62 options.insert(key, value);
63 }
64 }
65
66 let after_brace = joined[brace_end + 1..].trim();
68 if let Some(eq_pos) = after_brace.find('=') {
69 let pattern_part = after_brace[eq_pos + 1..].trim();
70 pattern_str = Some(pattern_part.trim_matches('"').to_string());
71 }
72 } else {
73 return Err(anyhow!("Unclosed brace in pattern options"));
74 }
75 } else {
76 if let Some(eq_pos) = joined.find('=') {
78 let pattern_part = joined[eq_pos + 1..].trim();
79 pattern_str = Some(pattern_part.trim_matches('"').to_string());
80 }
81 }
82 }
83 }
84
85 let value = if !options.is_empty() {
87 let mut map = options;
88 if let Some(pat) = pattern_str {
89 map.insert("pattern".to_string(), Value::String(pat));
90 }
91 Value::Map(map)
92 } else {
93 pattern_str.map(Value::String).unwrap_or(Value::Null)
94 };
95
96 Ok(Statement::new(
97 StatementKind::Pattern { name, target },
98 value,
99 0,
100 line_number,
101 1,
102 ))
103}
104
105pub fn parse_group(
107 mut parts: impl Iterator<Item = impl AsRef<str>>,
108 line_number: usize,
109) -> Result<Statement> {
110 let name = parts
111 .next()
112 .ok_or_else(|| anyhow!("group requires a name"))?
113 .as_ref()
114 .trim_end_matches(':')
115 .to_string();
116
117 Ok(Statement::new(
118 StatementKind::Group {
119 name: name.clone(),
120 body: Vec::new(),
121 },
122 Value::Identifier(name),
123 0,
124 line_number,
125 1,
126 ))
127}
128
129pub fn parse_automate(
131 mut parts: impl Iterator<Item = impl AsRef<str>>,
132 line_number: usize,
133) -> Result<Statement> {
134 let target = parts
136 .next()
137 .ok_or_else(|| anyhow!("automate requires a target"))?
138 .as_ref()
139 .trim_end_matches(':')
140 .to_string();
141
142 let mut mode: Option<String> = None;
144 if let Some(word) = parts.next() {
145 if word.as_ref() == "mode" {
146 if let Some(m) = parts.next() {
147 mode = Some(m.as_ref().trim_end_matches(':').to_string());
148 }
149 }
150 }
151
152 let mut map = HashMap::new();
153 if let Some(m) = mode {
154 map.insert("mode".to_string(), Value::String(m));
155 }
156
157 Ok(Statement::new(
158 StatementKind::Automate { target },
159 Value::Map(map),
160 0,
161 line_number,
162 1,
163 ))
164}
165
166pub fn parse_loop(
168 mut parts: impl Iterator<Item = impl AsRef<str>>,
169 line_number: usize,
170) -> Result<Statement> {
171 let count_opt = parts.next();
174
175 let count = if let Some(count_str_ref) = count_opt {
176 let count_str = count_str_ref.as_ref().trim_end_matches(':');
177 if let Ok(num) = count_str.parse::<f32>() {
183 Value::Number(num)
184 } else if count_str.contains('(') && count_str.ends_with(')') {
185 if let Some(open_idx) = count_str.find('(') {
187 let name = count_str[..open_idx].to_string();
188 let inside = &count_str[open_idx + 1..count_str.len() - 1];
189 let args = if inside.trim().is_empty() {
190 Vec::new()
191 } else {
192 crate::language::syntax::parser::driver::parse_function_args(inside)?
193 };
194 Value::Call { name, args }
195 } else {
196 Value::Identifier(count_str.to_string())
197 }
198 } else {
199 Value::Identifier(count_str.to_string())
200 }
201 } else {
202 Value::Null
204 };
205
206 Ok(Statement::new(
207 StatementKind::Loop {
208 count,
209 body: Vec::new(), },
211 Value::Null,
212 0,
213 line_number,
214 1,
215 ))
216}
217
218pub fn parse_for(
220 parts: impl Iterator<Item = impl AsRef<str>>,
221 line_number: usize,
222) -> Result<Statement> {
223 let parts_vec: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
225
226 if parts_vec.is_empty() {
227 return Err(anyhow!("for loop requires a variable name"));
228 }
229
230 let variable = parts_vec[0].clone();
231
232 if parts_vec.len() < 2 || parts_vec[1] != "in" {
234 return Err(anyhow!("Expected 'in' after variable in for loop"));
235 }
236
237 let iterable_str = parts_vec[2..].join(" ");
239 let iterable_str = iterable_str.trim_end_matches(':').trim();
240
241 let iterable = if iterable_str.starts_with('[') && iterable_str.ends_with(']') {
242 parse_array_value(iterable_str)?
244 } else {
245 if let Ok(num) = iterable_str.parse::<f32>() {
247 Value::Number(num)
248 } else {
249 Value::Identifier(iterable_str.to_string())
250 }
251 };
252
253 Ok(Statement::new(
254 StatementKind::For {
255 variable,
256 iterable,
257 body: Vec::new(), },
259 Value::Null,
260 0,
261 line_number,
262 1,
263 ))
264}
265
266pub fn parse_function(line: &str, line_number: usize) -> Result<Statement> {
268 let after_kw = line
270 .trim()
271 .strip_prefix("function")
272 .ok_or_else(|| anyhow!("function parsing error"))?
273 .trim();
274
275 if let Some(paren_idx) = after_kw.find('(') {
277 let name = after_kw[..paren_idx].trim().to_string();
278 if let Some(close_idx) = after_kw.rfind(')') {
279 let args_str = &after_kw[paren_idx + 1..close_idx];
280 let params: Vec<String> = if args_str.trim().is_empty() {
282 Vec::new()
283 } else {
284 args_str
285 .split(',')
286 .map(|s| s.trim().trim_end_matches(':').to_string())
287 .filter(|s| !s.is_empty())
288 .collect()
289 };
290
291 return Ok(Statement::new(
292 StatementKind::Function {
293 name: name.clone(),
294 parameters: params,
295 body: Vec::new(),
296 },
297 Value::Identifier(name),
298 0,
299 line_number,
300 1,
301 ));
302 }
303 }
304
305 Err(anyhow!("Invalid function declaration"))
306}
307
308pub fn parse_if(
310 parts: impl Iterator<Item = impl AsRef<str>>,
311 line_number: usize,
312) -> Result<Statement> {
313 let condition_str = parts
315 .map(|s| s.as_ref().to_string())
316 .collect::<Vec<_>>()
317 .join(" ");
318 let condition_str = condition_str.trim_end_matches(':').trim();
319
320 let condition = parse_condition(condition_str)?;
322
323 Ok(Statement::new(
324 StatementKind::If {
325 condition,
326 body: Vec::new(), else_body: None,
328 },
329 Value::Null,
330 0,
331 line_number,
332 1,
333 ))
334}
335
336pub fn parse_else(line: &str, line_number: usize) -> Result<Statement> {
338 if line.trim().starts_with("else if") {
340 let condition_str = line.trim().strip_prefix("else if").unwrap().trim();
342 let condition_str = condition_str.trim_end_matches(':').trim();
343 let condition = parse_condition(condition_str)?;
344
345 Ok(Statement::new(
348 StatementKind::If {
349 condition,
350 body: Vec::new(), else_body: None,
352 },
353 Value::String("else-if".to_string()),
354 0,
355 line_number,
356 1,
357 ))
358 } else {
359 Ok(Statement::new(
364 StatementKind::Comment, Value::String("else".to_string()),
366 0,
367 line_number,
368 1,
369 ))
370 }
371}
372
373pub fn parse_call(
378 line: &str,
379 mut parts: impl Iterator<Item = impl AsRef<str>>,
380 line_number: usize,
381) -> Result<Statement> {
382 let first_token = parts
386 .next()
387 .ok_or_else(|| anyhow!("call requires a target"))?
388 .as_ref()
389 .to_string();
390 let mut call_name = first_token.clone();
391 if line.find('(').is_some() {
392 if let Some(after_call) = line.trim().strip_prefix("call") {
394 let snippet = after_call.trim();
395 if let Some(pidx) = snippet.find('(') {
396 call_name = snippet[..pidx].trim().to_string();
397 }
398 }
399 }
400
401 if line.contains('=') {
403 let eq_parts: Vec<&str> = line.splitn(2, '=').collect();
405 if eq_parts.len() == 2 {
406 let target = eq_parts[0]
408 .trim()
409 .strip_prefix("call")
410 .unwrap_or(eq_parts[0])
411 .trim()
412 .to_string();
413 let pattern = eq_parts[1].trim().trim_matches('"').to_string();
414
415 let mut map = HashMap::new();
418 map.insert("inline_pattern".to_string(), Value::Boolean(true));
419 map.insert("target".to_string(), Value::String(target.clone()));
420 map.insert("pattern".to_string(), Value::String(pattern));
421
422 return Ok(Statement::new(
423 StatementKind::Call {
424 name: target,
425 args: Vec::new(),
426 },
427 Value::Map(map),
428 0,
429 line_number,
430 1,
431 ));
432 }
433 }
434
435 if let Some(paren_idx) = line.find('(') {
438 if let Some(close_idx) = line.rfind(')') {
439 let args_str = &line[paren_idx + 1..close_idx];
440 let args = if args_str.trim().is_empty() {
441 Vec::new()
442 } else {
443 crate::language::syntax::parser::driver::parse_function_args(args_str)?
445 };
446
447 return Ok(Statement::new(
448 StatementKind::Call {
449 name: call_name,
450 args,
451 },
452 Value::Null,
453 0,
454 line_number,
455 1,
456 ));
457 }
458 }
459
460 Ok(Statement::new(
461 StatementKind::Call {
462 name: call_name,
463 args: Vec::new(),
464 },
465 Value::Null,
466 0,
467 line_number,
468 1,
469 ))
470}
471
472pub fn parse_break(
474 _parts: impl Iterator<Item = impl AsRef<str>>,
475 line_number: usize,
476) -> Result<Statement> {
477 Ok(Statement::new(
478 StatementKind::Break,
479 Value::Null,
480 0,
481 line_number,
482 1,
483 ))
484}
485
486pub fn parse_spawn(
488 mut parts: impl Iterator<Item = impl AsRef<str>>,
489 line_number: usize,
490) -> Result<Statement> {
491 let name = parts
492 .next()
493 .ok_or_else(|| anyhow!("spawn requires a target"))?
494 .as_ref()
495 .to_string();
496
497 Ok(Statement::new(
498 StatementKind::Spawn {
499 name,
500 args: Vec::new(),
501 },
502 Value::Null,
503 0,
504 line_number,
505 1,
506 ))
507}
508
509pub fn parse_on(
511 mut parts: impl Iterator<Item = impl AsRef<str>>,
512 line_number: usize,
513) -> Result<Statement> {
514 let raw = parts
517 .next()
518 .ok_or_else(|| anyhow!("on statement requires an event name"))?
519 .as_ref()
520 .to_string();
521
522 let mut event_name = raw.clone();
524 let mut args_vec: Vec<Value> = Vec::new();
525 if let Some(open_idx) = raw.find('(') {
526 if raw.ends_with(')') {
527 let base = raw[..open_idx].to_string();
528 let inside = &raw[open_idx + 1..raw.len() - 1];
529 if let Ok(n) = inside.trim().parse::<f32>() {
530 args_vec.push(Value::Number(n));
531 }
532 event_name = base;
533 }
534 }
535
536 let next_word = parts.next();
538 let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
539 if once {
540 args_vec.push(Value::String("once".to_string()));
541 }
542
543 let args = if !args_vec.is_empty() {
544 Some(args_vec)
545 } else {
546 None
547 };
548
549 Ok(Statement::new(
550 StatementKind::On {
551 event: event_name,
552 args,
553 body: Vec::new(), },
555 Value::Null,
556 0,
557 line_number,
558 1,
559 ))
560}
561
562pub fn parse_emit(
564 line: &str,
565 mut parts: impl Iterator<Item = impl AsRef<str>>,
566 line_number: usize,
567) -> Result<Statement> {
568 let event_name = parts
570 .next()
571 .ok_or_else(|| anyhow!("emit statement requires an event name"))?
572 .as_ref()
573 .to_string();
574
575 let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
577
578 let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
579 let inner = &remainder[1..remainder.len() - 1];
581 let mut map = HashMap::new();
582
583 for pair in inner.split(',') {
585 let parts: Vec<&str> = pair.split(':').collect();
586 if parts.len() == 2 {
587 let key = parts[0].trim().to_string();
588 let value_str = parts[1].trim();
589
590 let value = if value_str.starts_with('"') && value_str.ends_with('"') {
592 Value::String(value_str.trim_matches('"').to_string())
593 } else if let Ok(num) = value_str.parse::<f32>() {
594 Value::Number(num)
595 } else {
596 Value::Identifier(value_str.to_string())
597 };
598
599 map.insert(key, value);
600 }
601 }
602
603 Some(Value::Map(map))
604 } else {
605 None
606 };
607
608 Ok(Statement::new(
609 StatementKind::Emit {
610 event: event_name,
611 payload,
612 },
613 Value::Null,
614 0,
615 line_number,
616 1,
617 ))
618}