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

1use super::super::helpers::{parse_array_value, parse_condition};
2use crate::language::syntax::ast::{Statement, StatementKind, Value};
3/// Structure statement parsing: group, pattern, loop, for, if, on, emit, call, spawn
4use anyhow::{Result, anyhow};
5use std::collections::HashMap;
6use std::iter::Iterator;
7
8/// Parse pattern statement
9pub fn parse_pattern(
10    mut parts: impl Iterator<Item = impl AsRef<str>>,
11    line_number: usize,
12) -> Result<Statement> {
13    // Parse: pattern <name> with <target> = "<pattern_string>"
14    let name = parts
15        .next()
16        .ok_or_else(|| anyhow!("pattern requires a name"))?
17        .as_ref()
18        .to_string();
19
20    let mut target = None;
21    let mut pattern_str = None;
22
23    // Check for "with" keyword
24    if let Some(word) = parts.next() {
25        if word.as_ref() == "with" {
26            // Next is the target
27            target = parts.next().map(|v| v.as_ref().to_string());
28
29            // Check for "=" sign
30            if let Some(eq) = parts.next() {
31                if eq.as_ref() == "=" {
32                    // Rest is the pattern string (might be quoted)
33                    let rest: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
34                    let joined = rest.join(" ");
35                    pattern_str = Some(joined.trim_matches('"').to_string());
36                }
37            }
38        }
39    }
40
41    Ok(Statement::new(
42        StatementKind::Pattern { name, target },
43        pattern_str.map(Value::String).unwrap_or(Value::Null),
44        0,
45        line_number,
46        1,
47    ))
48}
49
50/// Parse group statement
51pub fn parse_group(
52    mut parts: impl Iterator<Item = impl AsRef<str>>,
53    line_number: usize,
54) -> Result<Statement> {
55    let name = parts
56        .next()
57        .ok_or_else(|| anyhow!("group requires a name"))?
58        .as_ref()
59        .trim_end_matches(':')
60        .to_string();
61
62    Ok(Statement::new(
63        StatementKind::Group {
64            name: name.clone(),
65            body: Vec::new(),
66        },
67        Value::Identifier(name),
68        0,
69        line_number,
70        1,
71    ))
72}
73
74/// Parse loop statement
75pub fn parse_loop(
76    mut parts: impl Iterator<Item = impl AsRef<str>>,
77    line_number: usize,
78) -> Result<Statement> {
79    // Parse: loop <count>:
80    let count_str_ref = parts
81        .next()
82        .ok_or_else(|| anyhow!("loop requires a count"))?;
83    let count_str = count_str_ref.as_ref().trim_end_matches(':');
84
85    let count = if let Ok(num) = count_str.parse::<f32>() {
86        Value::Number(num)
87    } else {
88        Value::Identifier(count_str.to_string())
89    };
90
91    Ok(Statement::new(
92        StatementKind::Loop {
93            count,
94            body: Vec::new(), // Will be filled during indentation parsing
95        },
96        Value::Null,
97        0,
98        line_number,
99        1,
100    ))
101}
102
103/// Parse for statement
104pub fn parse_for(
105    parts: impl Iterator<Item = impl AsRef<str>>,
106    line_number: usize,
107) -> Result<Statement> {
108    // Parse: for <var> in <iterable>:
109    let parts_vec: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
110
111    if parts_vec.is_empty() {
112        return Err(anyhow!("for loop requires a variable name"));
113    }
114
115    let variable = parts_vec[0].clone();
116
117    // Expect "in"
118    if parts_vec.len() < 2 || parts_vec[1] != "in" {
119        return Err(anyhow!("Expected 'in' after variable in for loop"));
120    }
121
122    // Parse iterable (array or identifier)
123    let iterable_str = parts_vec[2..].join(" ");
124    let iterable_str = iterable_str.trim_end_matches(':').trim();
125
126    let iterable = if iterable_str.starts_with('[') && iterable_str.ends_with(']') {
127        // Parse as array: [1, 2, 3] or range: [1..10]
128        parse_array_value(iterable_str)?
129    } else {
130        // Parse as identifier or number
131        if let Ok(num) = iterable_str.parse::<f32>() {
132            Value::Number(num)
133        } else {
134            Value::Identifier(iterable_str.to_string())
135        }
136    };
137
138    Ok(Statement::new(
139        StatementKind::For {
140            variable,
141            iterable,
142            body: Vec::new(), // Will be filled during indentation parsing
143        },
144        Value::Null,
145        0,
146        line_number,
147        1,
148    ))
149}
150
151/// Parse if statement
152pub fn parse_if(
153    parts: impl Iterator<Item = impl AsRef<str>>,
154    line_number: usize,
155) -> Result<Statement> {
156    // Parse: if <condition>:
157    let condition_str = parts
158        .map(|s| s.as_ref().to_string())
159        .collect::<Vec<_>>()
160        .join(" ");
161    let condition_str = condition_str.trim_end_matches(':').trim();
162
163    // Parse condition (for now, simple comparison)
164    let condition = parse_condition(condition_str)?;
165
166    Ok(Statement::new(
167        StatementKind::If {
168            condition,
169            body: Vec::new(), // Will be filled during indentation parsing
170            else_body: None,
171        },
172        Value::Null,
173        0,
174        line_number,
175        1,
176    ))
177}
178
179/// Parse else statement (can be "else if" or just "else")
180pub fn parse_else(line: &str, line_number: usize) -> Result<Statement> {
181    // Check if this is "else if" or just "else"
182    if line.trim().starts_with("else if") {
183        // Parse as "else if <condition>:"
184        let condition_str = line.trim().strip_prefix("else if").unwrap().trim();
185        let condition_str = condition_str.trim_end_matches(':').trim();
186        let condition = parse_condition(condition_str)?;
187
188        Ok(Statement::new(
189            StatementKind::If {
190                condition,
191                body: Vec::new(), // Will be filled during indentation parsing
192                else_body: None,
193            },
194            Value::Null,
195            0,
196            line_number,
197            1,
198        ))
199    } else {
200        // Just "else:"
201        Ok(Statement::new(
202            StatementKind::Comment, // We'll handle this specially during body parsing
203            Value::String("else".to_string()),
204            0,
205            line_number,
206            1,
207        ))
208    }
209}
210
211/// Parse call statement
212pub fn parse_call(
213    mut parts: impl Iterator<Item = impl AsRef<str>>,
214    line_number: usize,
215) -> Result<Statement> {
216    let name = parts
217        .next()
218        .ok_or_else(|| anyhow!("call requires a target"))?
219        .as_ref()
220        .to_string();
221
222    Ok(Statement::new(
223        StatementKind::Call {
224            name,
225            args: Vec::new(),
226        },
227        Value::Null,
228        0,
229        line_number,
230        1,
231    ))
232}
233
234/// Parse spawn statement
235pub fn parse_spawn(
236    mut parts: impl Iterator<Item = impl AsRef<str>>,
237    line_number: usize,
238) -> Result<Statement> {
239    let name = parts
240        .next()
241        .ok_or_else(|| anyhow!("spawn requires a target"))?
242        .as_ref()
243        .to_string();
244
245    Ok(Statement::new(
246        StatementKind::Spawn {
247            name,
248            args: Vec::new(),
249        },
250        Value::Null,
251        0,
252        line_number,
253        1,
254    ))
255}
256
257/// Parse on statement (event handler)
258pub fn parse_on(
259    mut parts: impl Iterator<Item = impl AsRef<str>>,
260    line_number: usize,
261) -> Result<Statement> {
262    // Parse: on eventName: or on eventName once:
263    let event_name = parts
264        .next()
265        .ok_or_else(|| anyhow!("on statement requires an event name"))?
266        .as_ref()
267        .to_string();
268
269    // Check for "once" keyword
270    let next_word = parts.next();
271    let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
272
273    // Store once flag in args (temporary workaround until we have proper AST)
274    let args = if once {
275        Some(vec![Value::String("once".to_string())])
276    } else {
277        None
278    };
279
280    Ok(Statement::new(
281        StatementKind::On {
282            event: event_name,
283            args,
284            body: Vec::new(), // Will be filled during indentation parsing
285        },
286        Value::Null,
287        0,
288        line_number,
289        1,
290    ))
291}
292
293/// Parse emit statement (event emission)
294pub fn parse_emit(
295    line: &str,
296    mut parts: impl Iterator<Item = impl AsRef<str>>,
297    line_number: usize,
298) -> Result<Statement> {
299    // Parse: emit eventName { key: value, key: value }
300    let event_name = parts
301        .next()
302        .ok_or_else(|| anyhow!("emit statement requires an event name"))?
303        .as_ref()
304        .to_string();
305
306    // Parse payload if present
307    let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
308
309    let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
310        // Parse as map: { key: value, key: value }
311        let inner = &remainder[1..remainder.len() - 1];
312        let mut map = HashMap::new();
313
314        // Split by comma and parse key-value pairs
315        for pair in inner.split(',') {
316            let parts: Vec<&str> = pair.split(':').collect();
317            if parts.len() == 2 {
318                let key = parts[0].trim().to_string();
319                let value_str = parts[1].trim();
320
321                // Parse value
322                let value = if value_str.starts_with('"') && value_str.ends_with('"') {
323                    Value::String(value_str.trim_matches('"').to_string())
324                } else if let Ok(num) = value_str.parse::<f32>() {
325                    Value::Number(num)
326                } else {
327                    Value::Identifier(value_str.to_string())
328                };
329
330                map.insert(key, value);
331            }
332        }
333
334        Some(Value::Map(map))
335    } else {
336        None
337    };
338
339    Ok(Statement::new(
340        StatementKind::Emit {
341            event: event_name,
342            payload,
343        },
344        Value::Null,
345        0,
346        line_number,
347        1,
348    ))
349}