neutralts/bif/
parse_bif_for.rs

1#![doc = include_str!("../../doc/bif-for.md")]
2
3use crate::{bif::constants::*, bif::Bif, bif::BifError, utils::extract_blocks};
4
5impl<'a> Bif<'a> {
6    /*
7       {:for; varname 1 10 >>
8           var is:{:;varname:}
9       :}
10    */
11    pub(crate) fn parse_bif_for(&mut self) -> Result<(), BifError> {
12        if self.mod_filter || self.mod_negate {
13            return Err(self.bif_error(BIF_ERROR_MODIFIER_NOT_ALLOWED));
14        }
15
16        self.extract_params_code(true);
17
18        if !self.flags.is_empty() {
19            return Err(self.bif_error(BIF_ERROR_FLAGS_NOT_ALLOWED));
20        }
21
22        self.params = self.params.replace("..", " ");
23        let mut parts = self.params.split_whitespace();
24
25        let var_name = match parts.next() {
26            Some(value) => value.to_string(),
27            None => {
28                return Err(self.bif_error(BIF_ERROR_ARGUMENTS_NOT_FOUND));
29            }
30        };
31
32        let from = match parts.next() {
33            Some(value) => match value.parse::<i32>() {
34                Ok(num) => num,
35                Err(_) => {
36                    return Err(self.bif_error(BIF_ERROR_ARGUMENT_NOT_NUMBER));
37                }
38            },
39            None => {
40                return Err(self.bif_error(BIF_ERROR_ARGS_FROM_TO_NOT_FOUND));
41            }
42        };
43
44        let to = match parts.next() {
45            Some(value) => match value.parse::<i32>() {
46                Ok(num) => num,
47                Err(_) => {
48                    return Err(self.bif_error(BIF_ERROR_ARGUMENT_NOT_NUMBER));
49                }
50            },
51            None => {
52                return Err(self.bif_error(BIF_ERROR_ARGS_TO_NOT_FOUND));
53            }
54        };
55
56        let blocks = match extract_blocks(&self.code) {
57            Ok(b) => b,
58            Err(p) => return Err(self.bif_error(&format!("Unmatched block at position {}", p))),
59        };
60
61        let restore_var = self.get_data(&var_name);
62        if from > to {
63            for i in (to..=from).rev() {
64                self.parse_bif_for_iter(&var_name, &i.to_string(), &blocks);
65            }
66        } else {
67            for i in from..=to {
68                self.parse_bif_for_iter(&var_name, &i.to_string(), &blocks);
69            }
70        };
71        self.set_data(&var_name, &restore_var);
72
73        Ok(())
74    }
75
76    fn parse_bif_for_iter(&mut self, var_name: &str, val: &str, blocks: &Vec<(usize, usize)>) {
77        self.set_data(var_name, val);
78
79        let mut child_inherit = self.inherit.clone();
80        child_inherit.alias = self.alias.clone();
81        if !self.file_path.is_empty() {
82            child_inherit.current_file = self.file_path.clone();
83        }
84        if !self.dir.is_empty() {
85            child_inherit.current_dir = self.dir.clone();
86        }
87
88        if self.mod_scope {
89            self.inherit.create_block_schema(self.shared);
90        }
91
92        let mut block_parser = crate::block_parser::BlockParser::new(self.shared, child_inherit);
93        let code = block_parser.parse_with_blocks(&self.code, blocks, self.only);
94
95        if self.mod_scope {
96            block_parser.update_indir(&self.inherit.indir);
97        }
98
99        self.out += &code;
100    }
101}
102
103#[cfg(test)]
104#[path = "parse_bif_for_tests.rs"]
105mod tests;