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(
10 mut parts: impl Iterator<Item = impl AsRef<str>>,
11 line_number: usize,
12) -> Result<Statement> {
13 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 if let Some(word) = parts.next() {
25 if word.as_ref() == "with" {
26 target = parts.next().map(|v| v.as_ref().to_string());
28
29 if let Some(eq) = parts.next() {
31 if eq.as_ref() == "=" {
32 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
50pub 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
74pub fn parse_loop(
76 mut parts: impl Iterator<Item = impl AsRef<str>>,
77 line_number: usize,
78) -> Result<Statement> {
79 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(), },
96 Value::Null,
97 0,
98 line_number,
99 1,
100 ))
101}
102
103pub fn parse_for(
105 parts: impl Iterator<Item = impl AsRef<str>>,
106 line_number: usize,
107) -> Result<Statement> {
108 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 if parts_vec.len() < 2 || parts_vec[1] != "in" {
119 return Err(anyhow!("Expected 'in' after variable in for loop"));
120 }
121
122 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_array_value(iterable_str)?
129 } else {
130 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(), },
144 Value::Null,
145 0,
146 line_number,
147 1,
148 ))
149}
150
151pub fn parse_if(
153 parts: impl Iterator<Item = impl AsRef<str>>,
154 line_number: usize,
155) -> Result<Statement> {
156 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 let condition = parse_condition(condition_str)?;
165
166 Ok(Statement::new(
167 StatementKind::If {
168 condition,
169 body: Vec::new(), else_body: None,
171 },
172 Value::Null,
173 0,
174 line_number,
175 1,
176 ))
177}
178
179pub fn parse_else(line: &str, line_number: usize) -> Result<Statement> {
181 if line.trim().starts_with("else if") {
183 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(), else_body: None,
193 },
194 Value::Null,
195 0,
196 line_number,
197 1,
198 ))
199 } else {
200 Ok(Statement::new(
202 StatementKind::Comment, Value::String("else".to_string()),
204 0,
205 line_number,
206 1,
207 ))
208 }
209}
210
211pub 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
234pub 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
257pub fn parse_on(
259 mut parts: impl Iterator<Item = impl AsRef<str>>,
260 line_number: usize,
261) -> Result<Statement> {
262 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 let next_word = parts.next();
271 let once = next_word.map(|w| w.as_ref() == "once").unwrap_or(false);
272
273 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(), },
286 Value::Null,
287 0,
288 line_number,
289 1,
290 ))
291}
292
293pub fn parse_emit(
295 line: &str,
296 mut parts: impl Iterator<Item = impl AsRef<str>>,
297 line_number: usize,
298) -> Result<Statement> {
299 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 let remainder = line.splitn(2, &event_name).nth(1).unwrap_or("").trim();
308
309 let payload = if remainder.starts_with('{') && remainder.ends_with('}') {
310 let inner = &remainder[1..remainder.len() - 1];
312 let mut map = HashMap::new();
313
314 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 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}