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].trim().strip_prefix("call").unwrap_or(eq_parts[0]).trim().to_string();
288 let pattern = eq_parts[1].trim().trim_matches('"').to_string();
289
290 let mut map = HashMap::new();
293 map.insert("inline_pattern".to_string(), Value::Boolean(true));
294 map.insert("target".to_string(), Value::String(target.clone()));
295 map.insert("pattern".to_string(), Value::String(pattern));
296
297 return Ok(Statement::new(
298 StatementKind::Call {
299 name: target,
300 args: Vec::new(),
301 },
302 Value::Map(map),
303 0,
304 line_number,
305 1,
306 ));
307 }
308 }
309
310 Ok(Statement::new(
312 StatementKind::Call {
313 name: first,
314 args: Vec::new(),
315 },
316 Value::Null,
317 0,
318 line_number,
319 1,
320 ))
321}
322
323pub fn parse_spawn(
325 mut parts: impl Iterator<Item = impl AsRef<str>>,
326 line_number: usize,
327) -> Result<Statement> {
328 let name = parts
329 .next()
330 .ok_or_else(|| anyhow!("spawn requires a target"))?
331 .as_ref()
332 .to_string();
333
334 Ok(Statement::new(
335 StatementKind::Spawn {
336 name,
337 args: Vec::new(),
338 },
339 Value::Null,
340 0,
341 line_number,
342 1,
343 ))
344}
345
346pub fn parse_on(
348 mut parts: impl Iterator<Item = impl AsRef<str>>,
349 line_number: usize,
350) -> Result<Statement> {
351 let event_name = parts
353 .next()
354 .ok_or_else(|| anyhow!("on statement requires an event name"))?
355 .as_ref()
356 .to_string();
357
358 let next_word = parts.next();
360 let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
361
362 let args = if once {
364 Some(vec![Value::String("once".to_string())])
365 } else {
366 None
367 };
368
369 Ok(Statement::new(
370 StatementKind::On {
371 event: event_name,
372 args,
373 body: Vec::new(), },
375 Value::Null,
376 0,
377 line_number,
378 1,
379 ))
380}
381
382pub fn parse_emit(
384 line: &str,
385 mut parts: impl Iterator<Item = impl AsRef<str>>,
386 line_number: usize,
387) -> Result<Statement> {
388 let event_name = parts
390 .next()
391 .ok_or_else(|| anyhow!("emit statement requires an event name"))?
392 .as_ref()
393 .to_string();
394
395 let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
397
398 let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
399 let inner = &remainder[1..remainder.len() - 1];
401 let mut map = HashMap::new();
402
403 for pair in inner.split(',') {
405 let parts: Vec<&str> = pair.split(':').collect();
406 if parts.len() == 2 {
407 let key = parts[0].trim().to_string();
408 let value_str = parts[1].trim();
409
410 let value = if value_str.starts_with('"') && value_str.ends_with('"') {
412 Value::String(value_str.trim_matches('"').to_string())
413 } else if let Ok(num) = value_str.parse::<f32>() {
414 Value::Number(num)
415 } else {
416 Value::Identifier(value_str.to_string())
417 };
418
419 map.insert(key, value);
420 }
421 }
422
423 Some(Value::Map(map))
424 } else {
425 None
426 };
427
428 Ok(Statement::new(
429 StatementKind::Emit {
430 event: event_name,
431 payload,
432 },
433 Value::Null,
434 0,
435 line_number,
436 1,
437 ))
438}