use std::array::IntoIter;
use std::iter::FromIterator;
use std::collections::HashMap;
use crate::{AuthType, RadError};
use crate::utils::Utils;
use crate::arg_parser::ArgParser;
use crate::Processor;
type KeywordMacType = fn(&str, usize,&mut Processor) -> Result<Option<String>, RadError>;
#[derive(Clone)]
pub struct KeywordMacro {
macros : HashMap<String, KeywordMacType>,
}
impl KeywordMacro {
pub fn new() -> Self {
let map = HashMap::from_iter(IntoIter::new([
("pause".to_owned(), KeywordMacro::pause as KeywordMacType),
("foreach".to_owned(), KeywordMacro::foreach as KeywordMacType),
("forloop".to_owned(), KeywordMacro::forloop as KeywordMacType),
("if".to_owned(), KeywordMacro::if_cond as KeywordMacType),
("ifelse".to_owned(), KeywordMacro::ifelse as KeywordMacType),
("ifdef".to_owned(), KeywordMacro::ifdef as KeywordMacType),
("ifenv".to_owned(), KeywordMacro::ifenv as KeywordMacType),
]));
Self {
macros: map,
}
}
pub fn get(&self, name: &str) -> Option<&KeywordMacType> {
if let Some(mac) = self.macros.get(name) {
Some(mac)
} else {
None
}
}
pub fn contains(&self, name: &str) -> bool {
self.macros.contains_key(name)
}
fn pause(args: &str, level: usize,processor : &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 1, true) {
let arg = &processor.parse_chunk_args(level, "", &args[0])?;
if let Ok(value) =Utils::is_arg_true(arg) {
if value {
processor.paused = true;
} else {
processor.paused = false;
}
Ok(None)
}
else {
Err(RadError::InvalidArgument(format!("Pause requires either true/false or zero/nonzero integer, but given \"{}\"", arg)))
}
} else {
Err(RadError::InvalidArgument("Pause requires an argument".to_owned()))
}
}
fn foreach(args: &str, level: usize,processor: &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 2, true) {
let mut sums = String::new();
let loopable = &processor.parse_chunk_args(level, "", &args[0])?;
for value in loopable.split(',') {
let result = processor.parse_chunk_args(level, "", &args[1].replace("$:", value))?;
sums.push_str(&result);
}
Ok(Some(sums))
} else {
Err(RadError::InvalidArgument("Foreach requires two argument".to_owned()))
}
}
fn forloop(args: &str, level: usize, processor: &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 3, true) {
let mut sums = String::new();
let min_src = processor.parse_chunk_args(level, "",&Utils::trim(&args[0]))?;
let max_src = processor.parse_chunk_args(level, "",&Utils::trim(&args[1]))?;
let min: usize;
let max: usize;
if let Ok(num) = min_src.parse::<usize>() {
min = num;
} else {
return Err(RadError::InvalidArgument(format!("Forloop's min value should be non zero positive integer but given {}", &args[0])));
}
if let Ok(num) = max_src.parse::<usize>() {
max = num
} else {
return Err(RadError::InvalidArgument(format!("Forloop's min value should be non zero positive integer gut given \"{}\"", &args[1])));
}
for value in min..=max {
let result = processor.parse_chunk_args(level, "", &args[2].replace("$:", &value.to_string()))?;
sums.push_str(&result);
}
Ok(Some(sums))
} else {
Err(RadError::InvalidArgument("Forloop requires two argument".to_owned()))
}
}
fn if_cond(args: &str,level:usize,processor: &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 2, true) {
let boolean = &processor.parse_chunk_args(level,"",&args[0])?;
let cond = Utils::is_arg_true(&Utils::trim(boolean));
if let Ok(cond) = cond {
if cond {
let if_expr = processor.parse_chunk_args(level,"",&args[1])?;
return Ok(Some(if_expr));
}
} else {
return Err(RadError::InvalidArgument(format!("If requires either true/false or zero/nonzero integer but given \"{}\"", boolean)))
}
Ok(None)
} else {
Err(RadError::InvalidArgument("if requires two arguments".to_owned()))
}
}
fn ifelse(args: &str, level: usize,processor: &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 3, true) {
let boolean = &processor.parse_chunk_args(level,"",&args[0])?;
let cond = Utils::is_arg_true(&Utils::trim(boolean));
if let Ok(cond) = cond {
if cond {
let if_expr = processor.parse_chunk_args(level,"",&args[1])?;
return Ok(Some(if_expr));
}
} else {
return Err(RadError::InvalidArgument(format!("Ifelse requires either true/false or zero/nonzero integer but given \"{}\"", boolean)))
}
let else_expr = processor.parse_chunk_args(level, "", &args[2])?;
return Ok(Some(else_expr));
} else {
Err(RadError::InvalidArgument("ifelse requires three argument".to_owned()))
}
}
fn ifdef(args: &str, level: usize,processor: &mut Processor) -> Result<Option<String>, RadError> {
if let Some(args) = ArgParser::new().args_with_len(args, 2, true) {
let name = processor.parse_chunk_args(level, "",&Utils::trim(&args[0]))?;
let map = processor.get_map();
let boolean = map.contains(&name);
if boolean {
let if_expr = processor.parse_chunk_args(level,"",&args[1])?;
return Ok(Some(if_expr));
}
Ok(None)
} else {
Err(RadError::InvalidArgument("ifdef requires two arguments".to_owned()))
}
}
fn ifenv(args: &str, level: usize,processor: &mut Processor) -> Result<Option<String>, RadError> {
if !Utils::is_granted("ifenv", AuthType::ENV,processor)? {
return Ok(None);
}
if let Some(args) = ArgParser::new().args_with_len(args, 2, true) {
let name = processor.parse_chunk_args(level, "",&Utils::trim(&args[0]))?;
let boolean = if let Ok(_) = std::env::var(name) {
true
} else {
false
};
if boolean {
let if_expr = processor.parse_chunk_args(level,"",&args[1])?;
return Ok(Some(if_expr));
}
Ok(None)
} else {
Err(RadError::InvalidArgument("ifenv requires two arguments".to_owned()))
}
}
}