1#![allow(missing_docs)]
7
8use super::ast::{BinaryOp, Expr, Program, Statement, Type, UnaryOp};
9use crate::error::{AlgorithmError, Result};
10use pest::Parser;
11use pest_derive::Parser;
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, string::String, vec::Vec};
15
16#[derive(Parser)]
17#[grammar = "dsl/grammar.pest"]
18struct RasterParser;
19
20pub fn parse_program(input: &str) -> Result<Program> {
22 let pairs = RasterParser::parse(Rule::program, input).map_err(|e| {
23 AlgorithmError::InvalidParameter {
24 parameter: "dsl",
25 message: format!("Parse error: {e}"),
26 }
27 })?;
28
29 let mut statements = Vec::new();
30
31 for pair in pairs {
32 match pair.as_rule() {
33 Rule::program => {
34 for inner in pair.into_inner() {
35 if inner.as_rule() == Rule::statement {
36 statements.push(parse_statement(inner)?);
37 }
38 }
39 }
40 Rule::EOI => {}
41 _ => {
42 return Err(AlgorithmError::InvalidParameter {
43 parameter: "dsl",
44 message: format!("Unexpected rule: {:?}", pair.as_rule()),
45 });
46 }
47 }
48 }
49
50 Ok(Program { statements })
51}
52
53pub fn parse_expression(input: &str) -> Result<Expr> {
55 let mut full_input = String::from(input);
56 if !full_input.ends_with(';') {
57 full_input.push(';');
58 }
59
60 let pairs = RasterParser::parse(Rule::program, &full_input).map_err(|e| {
61 AlgorithmError::InvalidParameter {
62 parameter: "dsl",
63 message: format!("Parse error: {e}"),
64 }
65 })?;
66
67 for pair in pairs {
68 if pair.as_rule() == Rule::program {
69 for inner in pair.into_inner() {
70 if inner.as_rule() == Rule::statement {
71 let stmt_inner = inner.into_inner().next().ok_or_else(|| {
73 AlgorithmError::InvalidParameter {
74 parameter: "dsl",
75 message: "Empty statement".to_string(),
76 }
77 })?;
78
79 if stmt_inner.as_rule() == Rule::expr_stmt {
81 return parse_expr_stmt(stmt_inner);
82 }
83 }
84 }
85 }
86 }
87
88 Err(AlgorithmError::InvalidParameter {
89 parameter: "dsl",
90 message: "No expression found".to_string(),
91 })
92}
93
94fn parse_statement(pair: pest::iterators::Pair<Rule>) -> Result<Statement> {
95 let inner = pair
96 .into_inner()
97 .next()
98 .ok_or_else(|| AlgorithmError::InvalidParameter {
99 parameter: "dsl",
100 message: "Empty statement".to_string(),
101 })?;
102
103 match inner.as_rule() {
104 Rule::variable_decl => {
105 let mut parts = inner.into_inner();
106 let name = parts
107 .next()
108 .ok_or_else(|| AlgorithmError::InvalidParameter {
109 parameter: "dsl",
110 message: "Missing variable name".to_string(),
111 })?
112 .as_str()
113 .to_string();
114
115 let value = parts
116 .next()
117 .ok_or_else(|| AlgorithmError::InvalidParameter {
118 parameter: "dsl",
119 message: "Missing variable value".to_string(),
120 })?;
121
122 Ok(Statement::VariableDecl {
123 name,
124 value: Box::new(parse_expr(value)?),
125 })
126 }
127 Rule::function_decl => {
128 let mut parts = inner.into_inner();
129 let name = parts
130 .next()
131 .ok_or_else(|| AlgorithmError::InvalidParameter {
132 parameter: "dsl",
133 message: "Missing function name".to_string(),
134 })?
135 .as_str()
136 .to_string();
137
138 let mut params = Vec::new();
139 let mut body_pair = None;
140
141 for part in parts {
142 match part.as_rule() {
143 Rule::param_list => {
144 for param in part.into_inner() {
145 params.push(param.as_str().to_string());
146 }
147 }
148 Rule::expression => {
149 body_pair = Some(part);
150 }
151 _ => {}
152 }
153 }
154
155 let body = body_pair.ok_or_else(|| AlgorithmError::InvalidParameter {
156 parameter: "dsl",
157 message: "Missing function body".to_string(),
158 })?;
159
160 Ok(Statement::FunctionDecl {
161 name,
162 params,
163 body: Box::new(parse_expr(body)?),
164 })
165 }
166 Rule::return_stmt => {
167 let expr =
168 inner
169 .into_inner()
170 .next()
171 .ok_or_else(|| AlgorithmError::InvalidParameter {
172 parameter: "dsl",
173 message: "Missing return expression".to_string(),
174 })?;
175
176 Ok(Statement::Return(Box::new(parse_expr(expr)?)))
177 }
178 Rule::expr_stmt => parse_expr_stmt(inner).map(|e| Statement::Expr(Box::new(e))),
179 _ => Err(AlgorithmError::InvalidParameter {
180 parameter: "dsl",
181 message: format!("Unexpected statement: {:?}", inner.as_rule()),
182 }),
183 }
184}
185
186fn parse_expr_stmt(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
187 let expr = pair
188 .into_inner()
189 .next()
190 .ok_or_else(|| AlgorithmError::InvalidParameter {
191 parameter: "dsl",
192 message: "Empty expression statement".to_string(),
193 })?;
194
195 parse_expr(expr)
196}
197
198fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
199 match pair.as_rule() {
200 Rule::expression => parse_expr(pair.into_inner().next().ok_or_else(|| {
201 AlgorithmError::InvalidParameter {
202 parameter: "dsl",
203 message: "Empty expression".to_string(),
204 }
205 })?),
206 Rule::logical_or => parse_binary_op(pair, BinaryOp::Or),
207 Rule::logical_and => parse_binary_op(pair, BinaryOp::And),
208 Rule::logical_not => {
209 let mut inner = pair.into_inner();
210 let mut not_count = 0;
211
212 while let Some(next) = inner.peek() {
214 if matches!(next.as_rule(), Rule::not_op) {
215 not_count += 1;
216 inner.next();
217 } else {
218 break;
219 }
220 }
221
222 let mut expr =
223 parse_expr(
224 inner
225 .next()
226 .ok_or_else(|| AlgorithmError::InvalidParameter {
227 parameter: "dsl",
228 message: "Missing expression after not".to_string(),
229 })?,
230 )?;
231
232 for _ in 0..not_count {
234 expr = Expr::Unary {
235 op: UnaryOp::Not,
236 expr: Box::new(expr),
237 ty: Type::Unknown,
238 };
239 }
240
241 Ok(expr)
242 }
243 Rule::comparison => parse_comparison(pair),
244 Rule::additive => parse_additive(pair),
245 Rule::multiplicative => parse_multiplicative(pair),
246 Rule::power => parse_power(pair),
247 Rule::unary => parse_unary(pair),
248 Rule::primary => parse_primary(pair),
249 _ => Err(AlgorithmError::InvalidParameter {
250 parameter: "dsl",
251 message: format!("Unexpected expression rule: {:?}", pair.as_rule()),
252 }),
253 }
254}
255
256fn parse_binary_op(pair: pest::iterators::Pair<Rule>, default_op: BinaryOp) -> Result<Expr> {
257 let mut inner = pair.into_inner();
258 let mut left = parse_expr(
259 inner
260 .next()
261 .ok_or_else(|| AlgorithmError::InvalidParameter {
262 parameter: "dsl",
263 message: "Missing left operand".to_string(),
264 })?,
265 )?;
266
267 while let Some(next) = inner.next() {
268 let op = match next.as_rule() {
269 Rule::or_op => BinaryOp::Or,
270 Rule::and_op => BinaryOp::And,
271 _ => {
272 let right = parse_expr(next)?;
273 left = Expr::Binary {
274 left: Box::new(left),
275 op: default_op,
276 right: Box::new(right),
277 ty: Type::Unknown,
278 };
279 continue;
280 }
281 };
282
283 let right = parse_expr(
284 inner
285 .next()
286 .ok_or_else(|| AlgorithmError::InvalidParameter {
287 parameter: "dsl",
288 message: "Missing right operand".to_string(),
289 })?,
290 )?;
291
292 left = Expr::Binary {
293 left: Box::new(left),
294 op,
295 right: Box::new(right),
296 ty: Type::Unknown,
297 };
298 }
299
300 Ok(left)
301}
302
303fn parse_comparison(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
304 let mut inner = pair.into_inner();
305 let left = parse_expr(
306 inner
307 .next()
308 .ok_or_else(|| AlgorithmError::InvalidParameter {
309 parameter: "dsl",
310 message: "Missing left operand".to_string(),
311 })?,
312 )?;
313
314 if let Some(op_pair) = inner.next() {
315 let op = match op_pair.as_rule() {
316 Rule::eq_op => BinaryOp::Equal,
317 Rule::ne_op => BinaryOp::NotEqual,
318 Rule::lt_op => BinaryOp::Less,
319 Rule::le_op => BinaryOp::LessEqual,
320 Rule::gt_op => BinaryOp::Greater,
321 Rule::ge_op => BinaryOp::GreaterEqual,
322 _ => {
323 return Err(AlgorithmError::InvalidParameter {
324 parameter: "dsl",
325 message: format!("Unknown comparison operator: {:?}", op_pair.as_rule()),
326 });
327 }
328 };
329
330 let right = parse_expr(
331 inner
332 .next()
333 .ok_or_else(|| AlgorithmError::InvalidParameter {
334 parameter: "dsl",
335 message: "Missing right operand".to_string(),
336 })?,
337 )?;
338
339 Ok(Expr::Binary {
340 left: Box::new(left),
341 op,
342 right: Box::new(right),
343 ty: Type::Unknown,
344 })
345 } else {
346 Ok(left)
347 }
348}
349
350fn parse_additive(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
351 let mut inner = pair.into_inner();
352 let mut left = parse_expr(
353 inner
354 .next()
355 .ok_or_else(|| AlgorithmError::InvalidParameter {
356 parameter: "dsl",
357 message: "Missing left operand".to_string(),
358 })?,
359 )?;
360
361 while let Some(op_pair) = inner.next() {
362 let op = match op_pair.as_rule() {
363 Rule::add_op => BinaryOp::Add,
364 Rule::sub_op => BinaryOp::Subtract,
365 _ => {
366 let right = parse_expr(op_pair)?;
367 left = Expr::Binary {
368 left: Box::new(left),
369 op: BinaryOp::Add,
370 right: Box::new(right),
371 ty: Type::Unknown,
372 };
373 continue;
374 }
375 };
376
377 let right = parse_expr(
378 inner
379 .next()
380 .ok_or_else(|| AlgorithmError::InvalidParameter {
381 parameter: "dsl",
382 message: "Missing right operand".to_string(),
383 })?,
384 )?;
385
386 left = Expr::Binary {
387 left: Box::new(left),
388 op,
389 right: Box::new(right),
390 ty: Type::Unknown,
391 };
392 }
393
394 Ok(left)
395}
396
397fn parse_multiplicative(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
398 let mut inner = pair.into_inner();
399 let mut left = parse_expr(
400 inner
401 .next()
402 .ok_or_else(|| AlgorithmError::InvalidParameter {
403 parameter: "dsl",
404 message: "Missing left operand".to_string(),
405 })?,
406 )?;
407
408 while let Some(op_pair) = inner.next() {
409 let op = match op_pair.as_rule() {
410 Rule::mul_op => BinaryOp::Multiply,
411 Rule::div_op => BinaryOp::Divide,
412 Rule::mod_op => BinaryOp::Modulo,
413 _ => {
414 let right = parse_expr(op_pair)?;
415 left = Expr::Binary {
416 left: Box::new(left),
417 op: BinaryOp::Multiply,
418 right: Box::new(right),
419 ty: Type::Unknown,
420 };
421 continue;
422 }
423 };
424
425 let right = parse_expr(
426 inner
427 .next()
428 .ok_or_else(|| AlgorithmError::InvalidParameter {
429 parameter: "dsl",
430 message: "Missing right operand".to_string(),
431 })?,
432 )?;
433
434 left = Expr::Binary {
435 left: Box::new(left),
436 op,
437 right: Box::new(right),
438 ty: Type::Unknown,
439 };
440 }
441
442 Ok(left)
443}
444
445fn parse_power(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
446 let mut inner = pair.into_inner();
447 let mut left = parse_expr(
448 inner
449 .next()
450 .ok_or_else(|| AlgorithmError::InvalidParameter {
451 parameter: "dsl",
452 message: "Missing left operand".to_string(),
453 })?,
454 )?;
455
456 while let Some(op_pair) = inner.next() {
457 if matches!(op_pair.as_rule(), Rule::pow_op) {
458 let right =
459 parse_expr(
460 inner
461 .next()
462 .ok_or_else(|| AlgorithmError::InvalidParameter {
463 parameter: "dsl",
464 message: "Missing right operand".to_string(),
465 })?,
466 )?;
467
468 left = Expr::Binary {
469 left: Box::new(left),
470 op: BinaryOp::Power,
471 right: Box::new(right),
472 ty: Type::Unknown,
473 };
474 } else {
475 let right = parse_expr(op_pair)?;
476 left = Expr::Binary {
477 left: Box::new(left),
478 op: BinaryOp::Power,
479 right: Box::new(right),
480 ty: Type::Unknown,
481 };
482 }
483 }
484
485 Ok(left)
486}
487
488fn parse_unary(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
489 let mut inner = pair.into_inner();
490 let first = inner
491 .next()
492 .ok_or_else(|| AlgorithmError::InvalidParameter {
493 parameter: "dsl",
494 message: "Empty unary expression".to_string(),
495 })?;
496
497 match first.as_rule() {
498 Rule::sub_op => {
499 let expr = inner
501 .next()
502 .ok_or_else(|| AlgorithmError::InvalidParameter {
503 parameter: "dsl",
504 message: "Missing expression after -".to_string(),
505 })?;
506
507 Ok(Expr::Unary {
508 op: UnaryOp::Negate,
509 expr: Box::new(parse_expr(expr)?),
510 ty: Type::Unknown,
511 })
512 }
513 Rule::add_op => {
514 let expr = inner
516 .next()
517 .ok_or_else(|| AlgorithmError::InvalidParameter {
518 parameter: "dsl",
519 message: "Missing expression after +".to_string(),
520 })?;
521
522 Ok(Expr::Unary {
523 op: UnaryOp::Plus,
524 expr: Box::new(parse_expr(expr)?),
525 ty: Type::Unknown,
526 })
527 }
528 _ => parse_expr(first),
529 }
530}
531
532fn parse_primary(pair: pest::iterators::Pair<Rule>) -> Result<Expr> {
533 let inner = pair
534 .into_inner()
535 .next()
536 .ok_or_else(|| AlgorithmError::InvalidParameter {
537 parameter: "dsl",
538 message: "Empty primary expression".to_string(),
539 })?;
540
541 match inner.as_rule() {
542 Rule::number => {
543 let num =
544 inner
545 .as_str()
546 .parse::<f64>()
547 .map_err(|_| AlgorithmError::InvalidParameter {
548 parameter: "dsl",
549 message: format!("Invalid number: {}", inner.as_str()),
550 })?;
551 Ok(Expr::Number(num))
552 }
553 Rule::band_ref => {
554 let band_str = inner.as_str();
555 let band_num =
556 band_str[1..]
557 .parse::<usize>()
558 .map_err(|_| AlgorithmError::InvalidParameter {
559 parameter: "dsl",
560 message: format!("Invalid band reference: {band_str}"),
561 })?;
562 Ok(Expr::Band(band_num))
563 }
564 Rule::function_call => {
565 let mut parts = inner.into_inner();
566 let name = parts
567 .next()
568 .ok_or_else(|| AlgorithmError::InvalidParameter {
569 parameter: "dsl",
570 message: "Missing function name".to_string(),
571 })?
572 .as_str()
573 .to_string();
574
575 let mut args = Vec::new();
576 if let Some(arg_list) = parts.next() {
577 for arg in arg_list.into_inner() {
578 args.push(parse_expr(arg)?);
579 }
580 }
581
582 Ok(Expr::Call {
583 name,
584 args,
585 ty: Type::Unknown,
586 })
587 }
588 Rule::variable_ref => Ok(Expr::Variable(inner.as_str().to_string())),
589 Rule::conditional => {
590 let mut parts = inner.into_inner();
591 let condition =
592 parse_expr(
593 parts
594 .next()
595 .ok_or_else(|| AlgorithmError::InvalidParameter {
596 parameter: "dsl",
597 message: "Missing condition".to_string(),
598 })?,
599 )?;
600
601 let then_expr =
602 parse_expr(
603 parts
604 .next()
605 .ok_or_else(|| AlgorithmError::InvalidParameter {
606 parameter: "dsl",
607 message: "Missing then expression".to_string(),
608 })?,
609 )?;
610
611 let else_expr =
612 parse_expr(
613 parts
614 .next()
615 .ok_or_else(|| AlgorithmError::InvalidParameter {
616 parameter: "dsl",
617 message: "Missing else expression".to_string(),
618 })?,
619 )?;
620
621 Ok(Expr::Conditional {
622 condition: Box::new(condition),
623 then_expr: Box::new(then_expr),
624 else_expr: Box::new(else_expr),
625 ty: Type::Unknown,
626 })
627 }
628 Rule::block => {
629 let mut statements = Vec::new();
630 let mut result = None;
631
632 for part in inner.into_inner() {
633 match part.as_rule() {
634 Rule::statement => statements.push(parse_statement(part)?),
635 Rule::expression => result = Some(Box::new(parse_expr(part)?)),
636 _ => {}
637 }
638 }
639
640 Ok(Expr::Block {
641 statements,
642 result,
643 ty: Type::Unknown,
644 })
645 }
646 Rule::expression => parse_expr(inner),
647 _ => Err(AlgorithmError::InvalidParameter {
648 parameter: "dsl",
649 message: format!("Unexpected primary: {:?}", inner.as_rule()),
650 }),
651 }
652}
653
654#[cfg(test)]
655mod tests {
656 use super::*;
657
658 #[test]
659 fn test_parse_number() {
660 let expr = parse_expression("42.5").expect("Should parse");
661 assert!(matches!(expr, Expr::Number(n) if (n - 42.5).abs() < 1e-10));
662 }
663
664 #[test]
665 fn test_parse_band() {
666 let expr = parse_expression("B1").expect("Should parse");
667 assert!(matches!(expr, Expr::Band(1)));
668 }
669
670 #[test]
671 fn test_parse_arithmetic() {
672 let result = parse_expression("1 + 2 * 3");
673 assert!(result.is_ok());
674 }
675
676 #[test]
677 fn test_parse_ndvi() {
678 let result = parse_expression("(B1 - B2) / (B1 + B2)");
679 assert!(result.is_ok());
680 }
681
682 #[test]
683 fn test_parse_conditional() {
684 let result = parse_expression("if B1 > 0.5 then 1 else 0");
685 if let Err(e) = &result {
686 eprintln!("Parse error: {:?}", e);
687 }
688 assert!(result.is_ok(), "Parse failed: {:?}", result);
689 }
690
691 #[test]
692 fn test_parse_function_call() {
693 let result = parse_expression("sqrt(B1 * B1 + B2 * B2)");
694 assert!(result.is_ok());
695 }
696
697 #[test]
698 fn test_parse_program() {
699 let program = r#"
700 let ndvi = (B8 - B4) / (B8 + B4);
701 let result = if ndvi > 0.5 then 1 else 0;
702 "#;
703 let result = parse_program(program);
704 assert!(result.is_ok());
705 }
706}