neutralts/bif/
parse_bif_each.rs1#![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 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;