1use 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_pattern_shorthand(line: &str, line_number: usize) -> Result<Option<Statement>> {
109 let Some(colon_idx) = line.find(':') else {
110 return Ok(None);
111 };
112 let Some(eq_idx) = line.find('=') else {
113 return Ok(None);
114 };
115 if colon_idx > eq_idx {
116 return Ok(None);
117 }
118
119 let name = line[..colon_idx].trim();
120 if name.is_empty()
121 || name.contains(char::is_whitespace)
122 || !name.chars().all(|c| c.is_alphanumeric() || c == '_')
123 {
124 return Ok(None);
125 }
126
127 let target_expr = line[colon_idx + 1..eq_idx].trim();
128 let pattern_part = line[eq_idx + 1..].trim();
129 if target_expr.is_empty()
130 || !(pattern_part.starts_with('"')
131 && pattern_part.ends_with('"')
132 && pattern_part.len() >= 2)
133 {
134 return Ok(None);
135 }
136
137 let mut target = target_expr.to_string();
138 let mut options: HashMap<String, Value> = HashMap::new();
139
140 fn insert_option(options: &mut HashMap<String, Value>, method: &str, args: &[Value]) {
141 if let Some(first) = args.first() {
142 match first {
143 Value::Number(_) => {
144 options.insert(method.to_string(), first.clone());
145 }
146 Value::Map(map) => {
147 for (key, value) in map.iter() {
148 if matches!(value, Value::Number(_)) {
149 options.insert(key.clone(), value.clone());
150 }
151 }
152 }
153 _ => {}
154 }
155 }
156 }
157
158 if target_expr.contains("->") {
159 let stmt =
160 crate::language::syntax::parser::driver::parse_arrow_call(target_expr, line_number)?;
161 if let Value::Map(chain_container) = stmt.value {
162 if let Some(Value::String(parsed_target)) = chain_container.get("target") {
163 target = parsed_target.clone();
164 }
165
166 if let Some(Value::String(method)) = chain_container.get("method") {
167 if let Some(Value::Array(args)) = chain_container.get("args") {
168 insert_option(&mut options, method, args);
169 }
170 }
171
172 if let Some(Value::Array(chain)) = chain_container.get("chain") {
173 for item in chain {
174 if let Value::Map(call_map) = item {
175 if let (Some(Value::String(method)), Some(Value::Array(args))) =
176 (call_map.get("method"), call_map.get("args"))
177 {
178 insert_option(&mut options, method, args);
179 }
180 }
181 }
182 }
183 }
184 }
185
186 let pattern = pattern_part.trim_matches('"').to_string();
187 let value = if options.is_empty() {
188 Value::String(pattern)
189 } else {
190 options.insert("pattern".to_string(), Value::String(pattern));
191 Value::Map(options)
192 };
193
194 Ok(Some(Statement::new(
195 StatementKind::Pattern {
196 name: name.to_string(),
197 target: Some(target),
198 },
199 value,
200 0,
201 line_number,
202 1,
203 )))
204}
205
206pub fn parse_group(
209 mut parts: impl Iterator<Item = impl AsRef<str>>,
210 line_number: usize,
211) -> Result<Statement> {
212 let name = parts
213 .next()
214 .ok_or_else(|| anyhow!("group requires a name"))?
215 .as_ref()
216 .trim_end_matches(':')
217 .to_string();
218
219 let next = parts.next();
221 let duration = if next.as_ref().map(|w| w.as_ref()) == Some("during") {
222 let duration_str = parts
224 .map(|p| p.as_ref().to_string())
225 .collect::<Vec<_>>()
226 .join(" ")
227 .trim_end_matches(':')
228 .to_string();
229
230 Some(super::super::duration::parse_duration_token(&duration_str)?)
231 } else {
232 None
233 };
234
235 Ok(Statement::new(
236 StatementKind::Group {
237 name: name.clone(),
238 body: Vec::new(),
239 duration,
240 },
241 Value::Identifier(name),
242 0,
243 line_number,
244 1,
245 ))
246}
247
248pub fn parse_automate(
250 mut parts: impl Iterator<Item = impl AsRef<str>>,
251 line_number: usize,
252) -> Result<Statement> {
253 let target = parts
255 .next()
256 .ok_or_else(|| anyhow!("automate requires a target"))?
257 .as_ref()
258 .trim_end_matches(':')
259 .to_string();
260
261 let mut mode: Option<String> = None;
263 if let Some(word) = parts.next() {
264 if word.as_ref() == "mode" {
265 if let Some(m) = parts.next() {
266 mode = Some(m.as_ref().trim_end_matches(':').to_string());
267 }
268 }
269 }
270
271 let mut map = HashMap::new();
272 if let Some(m) = mode {
273 map.insert("mode".to_string(), Value::String(m));
274 }
275
276 Ok(Statement::new(
277 StatementKind::Automate { target },
278 Value::Map(map),
279 0,
280 line_number,
281 1,
282 ))
283}
284
285pub fn parse_loop(
287 parts: impl Iterator<Item = impl AsRef<str>>,
288 line_number: usize,
289) -> Result<Statement> {
290 let all_parts: Vec<String> = parts.map(|p| p.as_ref().to_string()).collect();
296
297 let count = if all_parts.is_empty() {
298 Value::Null
300 } else {
301 let count_str = all_parts.join(" ").trim_end_matches(':').to_string();
303
304 if let Ok(num) = count_str.parse::<f32>() {
312 Value::Number(num)
313 } else if count_str.contains('(') && count_str.ends_with(')') {
314 if let Some(open_idx) = count_str.find('(') {
316 let name = count_str[..open_idx].to_string();
317 let inside = &count_str[open_idx + 1..count_str.len() - 1];
318
319 if name == "pass" && !inside.trim().is_empty() {
321 if let Ok(duration) =
323 crate::language::syntax::parser::driver::parse_duration_token(inside.trim())
324 {
325 Value::Duration(duration)
326 } else {
327 let args = if inside.trim().is_empty() {
329 Vec::new()
330 } else {
331 crate::language::syntax::parser::driver::parse_function_args(inside)?
332 };
333 Value::Call { name, args }
334 }
335 } else {
336 let args = if inside.trim().is_empty() {
338 Vec::new()
339 } else {
340 crate::language::syntax::parser::driver::parse_function_args(inside)?
341 };
342 Value::Call { name, args }
343 }
344 } else {
345 Value::Identifier(count_str.to_string())
346 }
347 } else {
348 Value::Identifier(count_str)
349 }
350 };
351
352 Ok(Statement::new(
353 StatementKind::Loop {
354 count,
355 body: Vec::new(), },
357 Value::Null,
358 0,
359 line_number,
360 1,
361 ))
362}
363
364pub fn parse_for(
366 parts: impl Iterator<Item = impl AsRef<str>>,
367 line_number: usize,
368) -> Result<Statement> {
369 let parts_vec: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
371
372 if parts_vec.is_empty() {
373 return Err(anyhow!("for loop requires a variable name"));
374 }
375
376 let variable = parts_vec[0].clone();
377
378 if parts_vec.len() < 2 || parts_vec[1] != "in" {
380 return Err(anyhow!("Expected 'in' after variable in for loop"));
381 }
382
383 let iterable_str = parts_vec[2..].join(" ");
385 let iterable_str = iterable_str.trim_end_matches(':').trim();
386
387 let iterable = if iterable_str.starts_with('[') && iterable_str.ends_with(']') {
388 parse_array_value(iterable_str)?
390 } else {
391 if let Ok(num) = iterable_str.parse::<f32>() {
393 Value::Number(num)
394 } else {
395 Value::Identifier(iterable_str.to_string())
396 }
397 };
398
399 Ok(Statement::new(
400 StatementKind::For {
401 variable,
402 iterable,
403 body: Vec::new(), },
405 Value::Null,
406 0,
407 line_number,
408 1,
409 ))
410}
411
412pub fn parse_function(line: &str, line_number: usize) -> Result<Statement> {
414 let after_kw = line
416 .trim()
417 .strip_prefix("function")
418 .ok_or_else(|| anyhow!("function parsing error"))?
419 .trim();
420
421 if let Some(paren_idx) = after_kw.find('(') {
423 let name = after_kw[..paren_idx].trim().to_string();
424 if let Some(close_idx) = after_kw.rfind(')') {
425 let args_str = &after_kw[paren_idx + 1..close_idx];
426 let params: Vec<String> = if args_str.trim().is_empty() {
428 Vec::new()
429 } else {
430 args_str
431 .split(',')
432 .map(|s| s.trim().trim_end_matches(':').to_string())
433 .filter(|s| !s.is_empty())
434 .collect()
435 };
436
437 return Ok(Statement::new(
438 StatementKind::Function {
439 name: name.clone(),
440 parameters: params,
441 body: Vec::new(),
442 },
443 Value::Identifier(name),
444 0,
445 line_number,
446 1,
447 ));
448 }
449 }
450
451 Err(anyhow!("Invalid function declaration"))
452}
453
454pub fn parse_if(
456 parts: impl Iterator<Item = impl AsRef<str>>,
457 line_number: usize,
458) -> Result<Statement> {
459 let condition_str = parts
461 .map(|s| s.as_ref().to_string())
462 .collect::<Vec<_>>()
463 .join(" ");
464 let condition_str = condition_str.trim_end_matches(':').trim();
465
466 let condition = parse_condition(condition_str)?;
468
469 Ok(Statement::new(
470 StatementKind::If {
471 condition,
472 body: Vec::new(), else_body: None,
474 },
475 Value::Null,
476 0,
477 line_number,
478 1,
479 ))
480}
481
482pub fn parse_while(
485 parts: impl Iterator<Item = impl AsRef<str>>,
486 line_number: usize,
487) -> Result<Statement> {
488 let condition_str = parts
490 .map(|s| s.as_ref().to_string())
491 .collect::<Vec<_>>()
492 .join(" ");
493 let condition_str = condition_str.trim_end_matches(':').trim();
494
495 let condition = parse_condition(condition_str)?;
497
498 Ok(Statement::new(
499 StatementKind::While {
500 condition,
501 body: Vec::new(), },
503 Value::Null,
504 0,
505 line_number,
506 1,
507 ))
508}
509
510pub fn parse_else(line: &str, line_number: usize) -> Result<Statement> {
512 if line.trim().starts_with("else if") {
514 let Some(condition_str) = line.trim().strip_prefix("else if") else {
516 return Err(anyhow::anyhow!(
517 "Invalid else-if statement at line {}",
518 line_number
519 ));
520 };
521 let condition_str = condition_str.trim();
522 let condition_str = condition_str.trim_end_matches(':').trim();
523 let condition = parse_condition(condition_str)?;
524
525 Ok(Statement::new(
528 StatementKind::If {
529 condition,
530 body: Vec::new(), else_body: None,
532 },
533 Value::String("else-if".to_string()),
534 0,
535 line_number,
536 1,
537 ))
538 } else {
539 Ok(Statement::new(
544 StatementKind::Comment, Value::String("else".to_string()),
546 0,
547 line_number,
548 1,
549 ))
550 }
551}
552
553pub fn parse_call(
558 line: &str,
559 mut parts: impl Iterator<Item = impl AsRef<str>>,
560 line_number: usize,
561) -> Result<Statement> {
562 let first_token = parts
566 .next()
567 .ok_or_else(|| anyhow!("call requires a target"))?
568 .as_ref()
569 .to_string();
570 let mut call_name = first_token.clone();
571 if line.find('(').is_some() {
572 if let Some(after_call) = line.trim().strip_prefix("call") {
574 let snippet = after_call.trim();
575 if let Some(pidx) = snippet.find('(') {
576 call_name = snippet[..pidx].trim().to_string();
577 }
578 }
579 }
580
581 if line.contains('=') {
583 let eq_parts: Vec<&str> = line.splitn(2, '=').collect();
585 if eq_parts.len() == 2 {
586 let target = eq_parts[0]
588 .trim()
589 .strip_prefix("call")
590 .unwrap_or(eq_parts[0])
591 .trim()
592 .to_string();
593 let pattern = eq_parts[1].trim().trim_matches('"').to_string();
594
595 let mut map = HashMap::new();
598 map.insert("inline_pattern".to_string(), Value::Boolean(true));
599 map.insert("target".to_string(), Value::String(target.clone()));
600 map.insert("pattern".to_string(), Value::String(pattern));
601
602 return Ok(Statement::new(
603 StatementKind::Call {
604 name: target,
605 args: Vec::new(),
606 },
607 Value::Map(map),
608 0,
609 line_number,
610 1,
611 ));
612 }
613 }
614
615 if let Some(paren_idx) = line.find('(') {
618 if let Some(close_idx) = line.rfind(')') {
619 let args_str = &line[paren_idx + 1..close_idx];
620 let args = if args_str.trim().is_empty() {
621 Vec::new()
622 } else {
623 crate::language::syntax::parser::driver::parse_function_args(args_str)?
625 };
626
627 return Ok(Statement::new(
628 StatementKind::Call {
629 name: call_name,
630 args,
631 },
632 Value::Null,
633 0,
634 line_number,
635 1,
636 ));
637 }
638 }
639
640 Ok(Statement::new(
641 StatementKind::Call {
642 name: call_name,
643 args: Vec::new(),
644 },
645 Value::Null,
646 0,
647 line_number,
648 1,
649 ))
650}
651
652pub fn parse_break(
654 _parts: impl Iterator<Item = impl AsRef<str>>,
655 line_number: usize,
656) -> Result<Statement> {
657 Ok(Statement::new(
658 StatementKind::Break,
659 Value::Null,
660 0,
661 line_number,
662 1,
663 ))
664}
665
666pub fn parse_spawn(
668 mut parts: impl Iterator<Item = impl AsRef<str>>,
669 line_number: usize,
670) -> Result<Statement> {
671 let name = parts
672 .next()
673 .ok_or_else(|| anyhow!("spawn requires a target"))?
674 .as_ref()
675 .to_string();
676
677 Ok(Statement::new(
678 StatementKind::Spawn {
679 name,
680 args: Vec::new(),
681 },
682 Value::Null,
683 0,
684 line_number,
685 1,
686 ))
687}
688
689pub fn parse_on(
691 mut parts: impl Iterator<Item = impl AsRef<str>>,
692 line_number: usize,
693) -> Result<Statement> {
694 let raw = parts
697 .next()
698 .ok_or_else(|| anyhow!("on statement requires an event name"))?
699 .as_ref()
700 .to_string();
701
702 let mut event_name = raw.clone();
704 let mut args_vec: Vec<Value> = Vec::new();
705 if let Some(open_idx) = raw.find('(') {
706 if raw.ends_with(')') {
707 let base = raw[..open_idx].to_string();
708 let inside = &raw[open_idx + 1..raw.len() - 1];
709 if let Ok(n) = inside.trim().parse::<f32>() {
710 args_vec.push(Value::Number(n));
711 }
712 event_name = base;
713 }
714 }
715
716 let next_word = parts.next();
718 let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
719 if once {
720 args_vec.push(Value::String("once".to_string()));
721 }
722
723 let args = if !args_vec.is_empty() {
724 Some(args_vec)
725 } else {
726 None
727 };
728
729 Ok(Statement::new(
730 StatementKind::On {
731 event: event_name,
732 args,
733 body: Vec::new(), },
735 Value::Null,
736 0,
737 line_number,
738 1,
739 ))
740}
741
742pub fn parse_emit(
744 line: &str,
745 mut parts: impl Iterator<Item = impl AsRef<str>>,
746 line_number: usize,
747) -> Result<Statement> {
748 let event_name = parts
750 .next()
751 .ok_or_else(|| anyhow!("emit statement requires an event name"))?
752 .as_ref()
753 .to_string();
754
755 let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
757
758 let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
759 let inner = &remainder[1..remainder.len() - 1];
761 let mut map = HashMap::new();
762
763 for pair in inner.split(',') {
765 let parts: Vec<&str> = pair.split(':').collect();
766 if parts.len() == 2 {
767 let key = parts[0].trim().to_string();
768 let value_str = parts[1].trim();
769
770 let value = if value_str.starts_with('"') && value_str.ends_with('"') {
772 Value::String(value_str.trim_matches('"').to_string())
773 } else if let Ok(num) = value_str.parse::<f32>() {
774 Value::Number(num)
775 } else {
776 Value::Identifier(value_str.to_string())
777 };
778
779 map.insert(key, value);
780 }
781 }
782
783 Some(Value::Map(map))
784 } else {
785 None
786 };
787
788 Ok(Statement::new(
789 StatementKind::Emit {
790 event: event_name,
791 payload,
792 },
793 Value::Null,
794 0,
795 line_number,
796 1,
797 ))
798}