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_loop(
131 mut parts: impl Iterator<Item = impl AsRef<str>>,
132 line_number: usize,
133) -> Result<Statement> {
134 let count_str_ref = parts
136 .next()
137 .ok_or_else(|| anyhow!("loop requires a count"))?;
138 let count_str = count_str_ref.as_ref().trim_end_matches(':');
139
140 let count = if let Ok(num) = count_str.parse::<f32>() {
141 Value::Number(num)
142 } else {
143 Value::Identifier(count_str.to_string())
144 };
145
146 Ok(Statement::new(
147 StatementKind::Loop {
148 count,
149 body: Vec::new(), },
151 Value::Null,
152 0,
153 line_number,
154 1,
155 ))
156}
157
158pub fn parse_for(
160 parts: impl Iterator<Item = impl AsRef<str>>,
161 line_number: usize,
162) -> Result<Statement> {
163 let parts_vec: Vec<String> = parts.map(|s| s.as_ref().to_string()).collect();
165
166 if parts_vec.is_empty() {
167 return Err(anyhow!("for loop requires a variable name"));
168 }
169
170 let variable = parts_vec[0].clone();
171
172 if parts_vec.len() < 2 || parts_vec[1] != "in" {
174 return Err(anyhow!("Expected 'in' after variable in for loop"));
175 }
176
177 let iterable_str = parts_vec[2..].join(" ");
179 let iterable_str = iterable_str.trim_end_matches(':').trim();
180
181 let iterable = if iterable_str.starts_with('[') && iterable_str.ends_with(']') {
182 parse_array_value(iterable_str)?
184 } else {
185 if let Ok(num) = iterable_str.parse::<f32>() {
187 Value::Number(num)
188 } else {
189 Value::Identifier(iterable_str.to_string())
190 }
191 };
192
193 Ok(Statement::new(
194 StatementKind::For {
195 variable,
196 iterable,
197 body: Vec::new(), },
199 Value::Null,
200 0,
201 line_number,
202 1,
203 ))
204}
205
206pub fn parse_if(
208 parts: impl Iterator<Item = impl AsRef<str>>,
209 line_number: usize,
210) -> Result<Statement> {
211 let condition_str = parts
213 .map(|s| s.as_ref().to_string())
214 .collect::<Vec<_>>()
215 .join(" ");
216 let condition_str = condition_str.trim_end_matches(':').trim();
217
218 let condition = parse_condition(condition_str)?;
220
221 Ok(Statement::new(
222 StatementKind::If {
223 condition,
224 body: Vec::new(), else_body: None,
226 },
227 Value::Null,
228 0,
229 line_number,
230 1,
231 ))
232}
233
234pub fn parse_else(line: &str, line_number: usize) -> Result<Statement> {
236 if line.trim().starts_with("else if") {
238 let condition_str = line.trim().strip_prefix("else if").unwrap().trim();
240 let condition_str = condition_str.trim_end_matches(':').trim();
241 let condition = parse_condition(condition_str)?;
242
243 Ok(Statement::new(
244 StatementKind::If {
245 condition,
246 body: Vec::new(), else_body: None,
248 },
249 Value::Null,
250 0,
251 line_number,
252 1,
253 ))
254 } else {
255 Ok(Statement::new(
257 StatementKind::Comment, Value::String("else".to_string()),
259 0,
260 line_number,
261 1,
262 ))
263 }
264}
265
266pub fn parse_call(
271 line: &str,
272 mut parts: impl Iterator<Item = impl AsRef<str>>,
273 line_number: usize,
274) -> Result<Statement> {
275 let first = parts
276 .next()
277 .ok_or_else(|| anyhow!("call requires a target"))?
278 .as_ref()
279 .to_string();
280
281 if line.contains('=') {
283 let eq_parts: Vec<&str> = line.splitn(2, '=').collect();
285 if eq_parts.len() == 2 {
286 let target = eq_parts[0]
288 .trim()
289 .strip_prefix("call")
290 .unwrap_or(eq_parts[0])
291 .trim()
292 .to_string();
293 let pattern = eq_parts[1].trim().trim_matches('"').to_string();
294
295 let mut map = HashMap::new();
298 map.insert("inline_pattern".to_string(), Value::Boolean(true));
299 map.insert("target".to_string(), Value::String(target.clone()));
300 map.insert("pattern".to_string(), Value::String(pattern));
301
302 return Ok(Statement::new(
303 StatementKind::Call {
304 name: target,
305 args: Vec::new(),
306 },
307 Value::Map(map),
308 0,
309 line_number,
310 1,
311 ));
312 }
313 }
314
315 Ok(Statement::new(
317 StatementKind::Call {
318 name: first,
319 args: Vec::new(),
320 },
321 Value::Null,
322 0,
323 line_number,
324 1,
325 ))
326}
327
328pub fn parse_spawn(
330 mut parts: impl Iterator<Item = impl AsRef<str>>,
331 line_number: usize,
332) -> Result<Statement> {
333 let name = parts
334 .next()
335 .ok_or_else(|| anyhow!("spawn requires a target"))?
336 .as_ref()
337 .to_string();
338
339 Ok(Statement::new(
340 StatementKind::Spawn {
341 name,
342 args: Vec::new(),
343 },
344 Value::Null,
345 0,
346 line_number,
347 1,
348 ))
349}
350
351pub fn parse_on(
353 mut parts: impl Iterator<Item = impl AsRef<str>>,
354 line_number: usize,
355) -> Result<Statement> {
356 let event_name = parts
358 .next()
359 .ok_or_else(|| anyhow!("on statement requires an event name"))?
360 .as_ref()
361 .to_string();
362
363 let next_word = parts.next();
365 let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
366
367 let args = if once {
369 Some(vec![Value::String("once".to_string())])
370 } else {
371 None
372 };
373
374 Ok(Statement::new(
375 StatementKind::On {
376 event: event_name,
377 args,
378 body: Vec::new(), },
380 Value::Null,
381 0,
382 line_number,
383 1,
384 ))
385}
386
387pub fn parse_emit(
389 line: &str,
390 mut parts: impl Iterator<Item = impl AsRef<str>>,
391 line_number: usize,
392) -> Result<Statement> {
393 let event_name = parts
395 .next()
396 .ok_or_else(|| anyhow!("emit statement requires an event name"))?
397 .as_ref()
398 .to_string();
399
400 let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
402
403 let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
404 let inner = &remainder[1..remainder.len() - 1];
406 let mut map = HashMap::new();
407
408 for pair in inner.split(',') {
410 let parts: Vec<&str> = pair.split(':').collect();
411 if parts.len() == 2 {
412 let key = parts[0].trim().to_string();
413 let value_str = parts[1].trim();
414
415 let value = if value_str.starts_with('"') && value_str.ends_with('"') {
417 Value::String(value_str.trim_matches('"').to_string())
418 } else if let Ok(num) = value_str.parse::<f32>() {
419 Value::Number(num)
420 } else {
421 Value::Identifier(value_str.to_string())
422 };
423
424 map.insert(key, value);
425 }
426 }
427
428 Some(Value::Map(map))
429 } else {
430 None
431 };
432
433 Ok(Statement::new(
434 StatementKind::Emit {
435 event: event_name,
436 payload,
437 },
438 Value::Null,
439 0,
440 line_number,
441 1,
442 ))
443}