devalang_wasm/language/syntax/parser/driver/statements/
advanced.rs

1use super::super::helpers::{parse_function_args, parse_map_value};
2use crate::language::syntax::ast::{Statement, StatementKind, Value};
3/// Advanced statement parsing: ArrowCall, Assign, Automate, Bind
4use anyhow::{Result, anyhow};
5use std::collections::HashMap;
6
7/// Parse an arrow call: target -> method(args) -> method2(args2)
8/// Supports chaining multiple calls
9pub fn parse_arrow_call(line: &str, line_number: usize) -> Result<Statement> {
10    // Split by "->" to get chain of calls
11    let parts: Vec<&str> = line.split("->").map(|s| s.trim()).collect();
12
13    if parts.len() < 2 {
14        return Err(anyhow!("Arrow call requires at least one '->' operator"));
15    }
16
17    // First part is the target
18    let target = parts[0].to_string();
19
20    // Parse method calls
21    let mut calls = Vec::new();
22
23    for method_call in &parts[1..] {
24        // Parse method(args) or just method
25        if let Some(paren_idx) = method_call.find('(') {
26            let method_name = method_call[..paren_idx].trim();
27            let args_str = &method_call[paren_idx + 1..];
28
29            // Find matching closing paren
30            let close_paren = args_str
31                .rfind(')')
32                .ok_or_else(|| anyhow!("Missing closing parenthesis in arrow call"))?;
33
34            let args_str = &args_str[..close_paren];
35
36            // Parse arguments
37            let args = if args_str.trim().is_empty() {
38                Vec::new()
39            } else {
40                parse_function_args(args_str)?
41            };
42
43            calls.push((method_name.to_string(), args));
44        } else {
45            // Method without args
46            calls.push((method_call.trim().to_string(), Vec::new()));
47        }
48    }
49
50    // For now, we'll store all calls as separate ArrowCall statements
51    // or we can store them in a chain structure
52    // Let's store the first call and chain the rest
53
54    if calls.is_empty() {
55        return Err(anyhow!("No method calls found in arrow call"));
56    }
57
58    let (method, args) = calls[0].clone();
59
60    // Store chain in value for later processing
61    let mut chain_value = HashMap::new();
62    chain_value.insert("target".to_string(), Value::String(target.clone()));
63    chain_value.insert("method".to_string(), Value::String(method.clone()));
64    chain_value.insert("args".to_string(), Value::Array(args.clone()));
65
66    // Add remaining calls to chain
67    if calls.len() > 1 {
68        let chain_calls: Vec<Value> = calls[1..]
69            .iter()
70            .map(|(m, a)| {
71                let mut call_map = HashMap::new();
72                call_map.insert("method".to_string(), Value::String(m.clone()));
73                call_map.insert("args".to_string(), Value::Array(a.clone()));
74                Value::Map(call_map)
75            })
76            .collect();
77
78        chain_value.insert("chain".to_string(), Value::Array(chain_calls));
79    }
80
81    Ok(Statement::new(
82        StatementKind::ArrowCall {
83            target,
84            method,
85            args,
86        },
87        Value::Map(chain_value),
88        0,
89        line_number,
90        1,
91    ))
92}
93
94/// Parse property assignment: target.property = value
95pub fn parse_assign(line: &str, line_number: usize) -> Result<Statement> {
96    let assign_parts: Vec<&str> = line.splitn(2, '=').collect();
97    if assign_parts.len() != 2 {
98        return Err(anyhow!("Invalid assignment syntax"));
99    }
100
101    let left = assign_parts[0].trim();
102    let right = assign_parts[1].trim();
103
104    // Split left into target.property
105    let prop_parts: Vec<&str> = left.splitn(2, '.').collect();
106    if prop_parts.len() != 2 {
107        return Err(anyhow!("Assignment requires target.property syntax"));
108    }
109
110    let target = prop_parts[0].trim().to_string();
111    let property = prop_parts[1].trim().to_string();
112
113    // Parse value
114    let value = if let Ok(num) = right.parse::<f32>() {
115        Value::Number(num)
116    } else if right.starts_with('"') && right.ends_with('"') {
117        Value::String(right.trim_matches('"').to_string())
118    } else {
119        Value::Identifier(right.to_string())
120    };
121
122    Ok(Statement::new(
123        StatementKind::Assign { target, property },
124        value,
125        0,
126        line_number,
127        1,
128    ))
129}
130
131/// Parse bind statement: bind source -> target { options }
132pub fn parse_bind(line: &str, line_number: usize) -> Result<Statement> {
133    // Parse: bind source -> target { options }
134    let arrow_parts: Vec<&str> = line.splitn(2, "->").collect();
135    if arrow_parts.len() != 2 {
136        return Err(anyhow!("bind requires source -> target syntax"));
137    }
138
139    let source = arrow_parts[0]
140        .trim()
141        .strip_prefix("bind")
142        .ok_or_else(|| anyhow!("bind parsing error"))?
143        .trim()
144        .to_string();
145
146    let target_part = arrow_parts[1].trim();
147
148    // Check if there are options { ... }
149    let (target, options) = if let Some(brace_pos) = target_part.find('{') {
150        let target = target_part[..brace_pos].trim().to_string();
151
152        // Find closing brace
153        if let Some(close_brace) = target_part.rfind('}') {
154            let options_str = &target_part[brace_pos..close_brace + 1];
155            let options = parse_map_value(options_str)?;
156            (target, Some(options))
157        } else {
158            return Err(anyhow!("unclosed brace in bind options"));
159        }
160    } else {
161        (target_part.to_string(), None)
162    };
163
164    Ok(Statement::new(
165        StatementKind::Bind { source, target },
166        options.unwrap_or(Value::Null),
167        0,
168        line_number,
169        1,
170    ))
171}