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 if key_name.starts_with("local::") || val_name.starts_with("local::") {
49 return Err(self.bif_error(BIF_ERROR_INSECURE_VARNAME));
50 }
51
52 let restore_key = self.shared.schema["data"][&key_name].clone();
53 let restore_val = self.shared.schema["data"][&val_name].clone();
54
55 let data_storage = if array_name.starts_with("local::") {
56 &self.shared.get_indir(&self.inherit.indir)["data"]
57 } else {
58 &self.shared.schema["data"]
59 };
60
61 let array_clean = array_name.strip_prefix("local::").unwrap_or(&array_name);
62
63 let collection = if let Some(data_value) = resolve_pointer(data_storage, array_clean) {
64 data_value.clone()
65 } else {
66 Value::Null
67 };
68
69 let blocks = match extract_blocks(&self.code) {
70 Ok(b) => b,
71 Err(p) => return Err(self.bif_error(&format!("Unmatched block at position {}", p))),
72 };
73
74 match collection {
75 Value::Object(obj) => {
76 for (key, val) in obj.iter() {
77 self.parse_bif_each_iter(&key_name, &val_name, key, val, &blocks);
78 }
79 }
80 Value::Array(arr) => {
81 for (idx, val) in arr.iter().enumerate() {
82 self.parse_bif_each_iter(&key_name, &val_name, &idx.to_string(), val, &blocks);
83 }
84 }
85 _ => {}
86 }
87
88 self.shared.schema["data"][&key_name] = restore_key;
89 self.shared.schema["data"][&val_name] = restore_val;
90
91 Ok(())
92 }
93
94 fn parse_bif_each_iter(
95 &mut self,
96 key_name: &str,
97 val_name: &str,
98 key: &String,
99 val: &Value,
100 blocks: &Vec<(usize, usize)>,
101 ) {
102 self.shared.schema["data"][key_name] = json!(key);
103 self.shared.schema["data"][val_name] = json!(val);
104
105 let mut child_inherit = self.inherit.clone();
106 child_inherit.alias = self.alias.clone();
107 if !self.file_path.is_empty() {
108 child_inherit.current_file = self.file_path.clone();
109 }
110 if !self.dir.is_empty() {
111 child_inherit.current_dir = self.dir.clone();
112 }
113
114 if self.mod_scope {
115 self.inherit.create_block_schema(self.shared);
116 }
117
118 let mut block_parser = crate::block_parser::BlockParser::new(self.shared, child_inherit);
119 let code = block_parser.parse_with_blocks(&self.code, blocks, self.only);
120
121 if self.mod_scope {
122 block_parser.update_indir(&self.inherit.indir);
123 }
124
125 self.out += &code;
126 }
127}
128
129#[cfg(test)]
130#[path = "parse_bif_each_tests.rs"]
131mod tests;