#![doc = include_str!("../../doc/bif-each.md")]
use crate::{
bif::constants::*, bif::Bif, bif::BifError, json, utils::extract_blocks,
utils::resolve_pointer, Value,
};
impl<'a> Bif<'a> {
pub(crate) fn parse_bif_each(&mut self) -> Result<(), BifError> {
if self.mod_filter || self.mod_negate {
return Err(self.bif_error(BIF_ERROR_MODIFIER_NOT_ALLOWED));
}
self.extract_params_code(true);
if !self.flags.is_empty() {
return Err(self.bif_error(BIF_ERROR_FLAGS_NOT_ALLOWED));
}
let mut parts = self.params.split_whitespace();
let array_name = match parts.next() {
Some(value) => value.to_string(),
None => {
return Err(self.bif_error(BIF_ERROR_ARGUMENTS_NOT_FOUND));
}
};
let key_name = match parts.next() {
Some(value) => value.to_string(),
None => {
return Err(self.bif_error(BIF_ERROR_ARGS_KEY_NOT_FOUND));
}
};
let val_name = match parts.next() {
Some(value) => value.to_string(),
None => {
return Err(self.bif_error(BIF_ERROR_ARGS_VALUE_NOT_FOUND));
}
};
if key_name.starts_with("local::") || val_name.starts_with("local::") {
return Err(self.bif_error(BIF_ERROR_INSECURE_VARNAME));
}
let restore_key = self.shared.schema["data"][&key_name].clone();
let restore_val = self.shared.schema["data"][&val_name].clone();
let data_storage = if array_name.starts_with("local::") {
&self.shared.get_indir(&self.inherit.indir)["data"]
} else {
&self.shared.schema["data"]
};
let array_clean = array_name.strip_prefix("local::").unwrap_or(&array_name);
let collection = if let Some(data_value) = resolve_pointer(data_storage, array_clean) {
data_value.clone()
} else {
Value::Null
};
let blocks = match extract_blocks(&self.code) {
Ok(b) => b,
Err(p) => return Err(self.bif_error(&format!("Unmatched block at position {}", p))),
};
match collection {
Value::Object(obj) => {
for (key, val) in obj.iter() {
self.parse_bif_each_iter(&key_name, &val_name, key, val, &blocks);
}
}
Value::Array(arr) => {
for (idx, val) in arr.iter().enumerate() {
self.parse_bif_each_iter(&key_name, &val_name, &idx.to_string(), val, &blocks);
}
}
_ => {}
}
self.shared.schema["data"][&key_name] = restore_key;
self.shared.schema["data"][&val_name] = restore_val;
Ok(())
}
fn parse_bif_each_iter(
&mut self,
key_name: &str,
val_name: &str,
key: &String,
val: &Value,
blocks: &Vec<(usize, usize)>,
) {
self.shared.schema["data"][key_name] = json!(key);
self.shared.schema["data"][val_name] = json!(val);
let mut child_inherit = self.inherit.clone();
child_inherit.alias = self.alias.clone();
if !self.file_path.is_empty() {
child_inherit.current_file = self.file_path.clone();
}
if !self.dir.is_empty() {
child_inherit.current_dir = self.dir.clone();
}
if self.mod_scope {
self.inherit.create_block_schema(self.shared);
}
let mut block_parser = crate::block_parser::BlockParser::new(self.shared, child_inherit);
let code = block_parser.parse_with_blocks(&self.code, blocks, self.only);
if self.mod_scope {
block_parser.update_indir(&self.inherit.indir);
}
self.out += &code;
}
}
#[cfg(test)]
#[path = "parse_bif_each_tests.rs"]
mod tests;