neutralts/bif/
parse_bif_each.rs

1#![doc = include_str!("../../doc/bif-each.md")]
2
3use crate::{
4    bif::constants::*, bif::Bif, bif::BifError, json, utils::extract_blocks,
5    utils::resolve_pointer, Value,
6};
7
8impl<'a> Bif<'a> {
9    /*
10        {:each; array-name name-for-key name-for-value  >>
11            {:;name-for-key:}={:;name-for-value:}
12        :}
13    */
14    pub(crate) fn parse_bif_each(&mut self) -> Result<(), BifError> {
15        if self.mod_filter || self.mod_negate {
16            return Err(self.bif_error(BIF_ERROR_MODIFIER_NOT_ALLOWED));
17        }
18
19        self.extract_params_code(true);
20
21        if !self.flags.is_empty() {
22            return Err(self.bif_error(BIF_ERROR_FLAGS_NOT_ALLOWED));
23        }
24
25        let mut parts = self.params.split_whitespace();
26
27        let array_name = match parts.next() {
28            Some(value) => value.to_string(),
29            None => {
30                return Err(self.bif_error(BIF_ERROR_ARGUMENTS_NOT_FOUND));
31            }
32        };
33
34        let key_name = match parts.next() {
35            Some(value) => value.to_string(),
36            None => {
37                return Err(self.bif_error(BIF_ERROR_ARGS_KEY_NOT_FOUND));
38            }
39        };
40
41        let val_name = match parts.next() {
42            Some(value) => value.to_string(),
43            None => {
44                return Err(self.bif_error(BIF_ERROR_ARGS_VALUE_NOT_FOUND));
45            }
46        };
47
48        let restore_key = self.get_data(&key_name);
49        let restore_val = self.get_data(&val_name);
50
51        let data_storage = if array_name.starts_with("local::") {
52            &self.shared.schema["__indir"][&self.inherit.indir]["data"]
53        } else {
54            &self.shared.schema["data"]
55        };
56
57        let array_clean = array_name.strip_prefix("local::").unwrap_or(&array_name);
58
59        let collection = if let Some(data_value) = resolve_pointer(data_storage, array_clean) {
60            data_value.clone()
61        } else {
62            Value::Null
63        };
64
65        let blocks = match extract_blocks(&self.code) {
66            Ok(b) => b,
67            Err(p) => return Err(self.bif_error(&format!("Unmatched block at position {}", p))),
68        };
69
70        match collection {
71            Value::Object(obj) => {
72                for (key, val) in obj.iter() {
73                    self.parse_bif_each_iter(&key_name, &val_name, key, val, &blocks);
74                }
75            }
76            Value::Array(arr) => {
77                for (idx, val) in arr.iter().enumerate() {
78                    self.parse_bif_each_iter(&key_name, &val_name, &idx.to_string(), val, &blocks);
79                }
80            }
81            _ => {}
82        }
83
84        self.set_data(&key_name, &restore_key);
85        self.set_data(&val_name, &restore_val);
86
87        Ok(())
88    }
89
90    fn parse_bif_each_iter(
91        &mut self,
92        key_name: &str,
93        val_name: &str,
94        key: &String,
95        val: &Value,
96        blocks: &Vec<(usize, usize)>,
97    ) {
98        self.shared.schema["data"][key_name] = json!(key);
99        self.shared.schema["data"][val_name] = json!(val);
100
101        let mut child_inherit = self.inherit.clone();
102        child_inherit.alias = self.alias.clone();
103        if !self.file_path.is_empty() {
104            child_inherit.current_file = self.file_path.clone();
105        }
106        if !self.dir.is_empty() {
107            child_inherit.current_dir = self.dir.clone();
108        }
109
110        if self.mod_scope {
111            self.inherit.create_block_schema(self.shared);
112        }
113
114        let mut block_parser = crate::block_parser::BlockParser::new(self.shared, child_inherit);
115        let code = block_parser.parse_with_blocks(&self.code, blocks, self.only);
116
117        if self.mod_scope {
118            block_parser.update_indir(&self.inherit.indir);
119        }
120
121        self.out += &code;
122    }
123}
124
125#[cfg(test)]
126#[path = "parse_bif_each_tests.rs"]
127mod tests;