pub mod expr_to_literal;
pub mod gen_generic_component;
pub mod gen_literal;
pub mod interval;
pub mod match_literals;
pub mod memory;
pub mod operations;
use crate::data::literal::ContentType;
pub use expr_to_literal::{expr_to_literal, resolve_fn_args};
use crate::data::error_info::ErrorInfo;
use crate::data::position::Position;
use crate::data::primitive::{
null::PrimitiveNull, object::PrimitiveObject, string::PrimitiveString, PrimitiveType,
};
use crate::data::{
ast::{Expr, Function, Identifier, Interval, PathLiteral, PathState},
tokens::{COMPONENT, EVENT, _METADATA},
ArgsType, Data, Literal, MemoryType, MessageData, MSG,
};
use crate::error_format::*;
use crate::interpreter::variable_handler::{
gen_literal::gen_literal_from_component,
gen_literal::gen_literal_from_event,
memory::{save_literal_in_mem, search_in_memory_type, search_var_memory},
};
use std::slice::Iter;
use std::{collections::HashMap, sync::mpsc};
pub fn get_literal(
literal: &mut Literal,
index: Option<Literal>,
) -> Result<&mut Literal, ErrorInfo> {
let interval = literal.interval.to_owned();
match (literal, index) {
(literal_lhs, Some(literal_rhs))
if literal_lhs.primitive.get_type() == PrimitiveType::PrimitiveArray
&& literal_rhs.primitive.get_type() == PrimitiveType::PrimitiveInt =>
{
let items = Literal::get_mut_value::<&mut Vec<Literal>>(
&mut literal_lhs.primitive,
literal_lhs.interval,
ERROR_ARRAY_TYPE.to_owned(),
)?;
let value = Literal::get_value::<i64>(
&literal_rhs.primitive,
literal_rhs.interval,
ERROR_ARRAY_INDEX_TYPE.to_owned(),
)?;
match items.get_mut(*value as usize) {
Some(lit) => Ok(lit),
None => Err(gen_error_info(
Position::new(interval),
format!("{} {}", value, ERROR_ARRAY_INDEX_EXIST.to_owned()),
)),
}
}
(literal, None) => Ok(literal),
(_, Some(_)) => Err(gen_error_info(
Position::new(interval),
ERROR_ARRAY_TYPE.to_owned(),
)),
}
}
fn get_var_from_step_var<'a>(
name: &Identifier,
data: &'a mut Data,
) -> Result<&'a mut Literal, ErrorInfo> {
match data.step_vars.get_mut(&name.ident) {
Some(var) => Ok(var),
None => Err(gen_error_info(
Position::new(name.interval),
format!("< {} > {}", name.ident, ERROR_STEP_MEMORY),
)),
}
}
pub fn get_at_index(lit: &mut Literal, index: usize) -> Option<&mut Literal> {
let vec = Literal::get_mut_value::<Vec<Literal>>(
&mut lit.primitive,
lit.interval,
ERROR_ARRAY_TYPE.to_owned(),
)
.ok()?;
vec.get_mut(index)
}
pub fn get_value_from_key<'a>(lit: &'a mut Literal, key: &str) -> Option<&'a mut Literal> {
let map = Literal::get_mut_value::<HashMap<String, Literal>>(
&mut lit.primitive,
lit.interval,
ERROR_OBJECT_TYPE.to_owned(),
)
.ok()?;
map.get_mut(key)
}
pub fn resolve_path(
path: &[(Interval, PathState)],
condition: bool,
data: &mut Data,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<Vec<(Interval, PathLiteral)>, ErrorInfo> {
let mut new_path = vec![];
for (interval, node) in path.iter() {
match node {
PathState::ExprIndex(expr) => {
let lit = expr_to_literal(&expr, condition, None, data, msg_data, sender)?;
if let Ok(val) = Literal::get_value::<i64>(
&lit.primitive,
lit.interval,
ERROR_UNREACHABLE.to_owned(),
) {
new_path.push((interval.to_owned(), PathLiteral::VecIndex(*val as usize)))
} else if let Ok(val) = Literal::get_value::<String>(
&lit.primitive,
lit.interval,
ERROR_UNREACHABLE.to_owned(),
) {
new_path.push((interval.to_owned(), PathLiteral::MapIndex(val.to_owned())))
} else {
return Err(gen_error_info(
Position::new(*interval),
ERROR_FIND_BY_INDEX.to_owned(),
));
}
}
PathState::Func(Function {
name,
interval,
args,
}) => new_path.push((
interval.to_owned(),
PathLiteral::Func {
name: name.to_owned(),
interval: interval.to_owned(),
args: resolve_fn_args(&args, data, msg_data, sender)?,
},
)),
PathState::StringIndex(key) => {
new_path.push((interval.to_owned(), PathLiteral::MapIndex(key.to_owned())))
}
}
}
Ok(new_path)
}
fn loop_path(
mut lit: &mut Literal,
condition: bool,
new: Option<Literal>,
path: &mut Iter<(Interval, PathLiteral)>,
content_type: &ContentType,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<(Literal, bool), ErrorInfo> {
let mut tmp_update_var = false;
while let Some((interval, action)) = path.next() {
match action {
PathLiteral::VecIndex(index) => match get_at_index(lit, *index) {
Some(new_lit) => lit = new_lit,
None => {
let err = gen_error_info(
Position::new(*interval),
format!("[{}] {}", index, ERROR_ARRAY_INDEX),
);
let null = match condition {
true => PrimitiveNull::get_literal(err.position.interval),
false => MSG::send_error_msg(&sender, msg_data, Err(err)),
};
return Ok((null, tmp_update_var));
}
},
PathLiteral::MapIndex(key) => {
if let (Some(ref new), 0) = (&new, path.len()) {
let mut args = HashMap::new();
args.insert(
"arg0".to_owned(),
PrimitiveString::get_literal(key, interval.to_owned()),
);
args.insert("arg1".to_owned(), new.to_owned());
lit.primitive.exec(
"insert",
&args,
interval.to_owned(),
content_type,
&mut false,
)?;
return Ok((lit.to_owned(), true));
} else {
match get_value_from_key(lit, key) {
Some(new_lit) => lit = new_lit,
None => {
let err = gen_error_info(
Position::new(*interval),
format!("[{}] {}", key, ERROR_OBJECT_GET),
);
let null = match condition {
true => PrimitiveNull::get_literal(err.position.interval),
false => MSG::send_error_msg(&sender, msg_data, Err(err)),
};
return Ok((null, tmp_update_var));
}
}
};
}
PathLiteral::Func {
name,
interval,
args,
} => {
let args = match args {
ArgsType::Normal(args) => args,
ArgsType::Named(_) => {
let err = gen_error_info(
Position::new(*interval),
format!("{}", ERROR_METHOD_NAMED_ARGS),
);
return Ok((
MSG::send_error_msg(&sender, msg_data, Err(err)),
tmp_update_var,
));
}
};
let mut return_lit = match lit.primitive.exec(
name,
args,
*interval,
content_type,
&mut tmp_update_var,
) {
Ok(lit) => lit,
Err(err) => MSG::send_error_msg(sender, msg_data, Err(err)),
};
let content_type = ContentType::get(&return_lit);
let (lit_new, ..) = loop_path(
&mut return_lit,
false,
None,
path,
&content_type,
msg_data,
sender,
)?;
return Ok((lit_new, tmp_update_var));
}
}
}
if let Some(new) = new {
*lit = new;
tmp_update_var = true;
}
Ok((lit.to_owned(), tmp_update_var))
}
pub fn exec_path_actions(
lit: &mut Literal,
condition: bool,
new: Option<Literal>,
path: &Option<Vec<(Interval, PathLiteral)>>,
content_type: &ContentType,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<(Literal, bool), ErrorInfo> {
if let Some(vec) = path {
let mut path = vec.iter();
let (return_lit, update) = loop_path(
lit,
condition,
new,
&mut path,
content_type,
msg_data,
sender,
)?;
Ok((return_lit, update))
} else {
let mut tmp_update_var = false;
if let Some(new) = new {
*lit = new;
tmp_update_var = true;
}
Ok((lit.to_owned(), tmp_update_var))
}
}
pub fn get_literal_form_metadata(
path: &[(Interval, PathLiteral)],
condition: bool,
data: &mut Data,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<Literal, ErrorInfo> {
let mut lit = match path.get(0) {
Some((interval, PathLiteral::MapIndex(name))) => match data.context.metadata.get(name) {
Some(lit) => lit.to_owned(),
None => PrimitiveNull::get_literal(interval.to_owned()),
},
Some((interval, _)) => {
return Err(gen_error_info(
Position::new(*interval),
ERROR_FIND_BY_INDEX.to_owned(),
));
}
None => unreachable!(),
};
let content_type = ContentType::get(&lit);
let (lit, _tmp_mem_update) = exec_path_actions(
&mut lit,
condition,
None,
&Some(path[1..].to_owned()),
&content_type,
msg_data,
sender,
)?;
Ok(lit)
}
pub fn get_var(
var: Identifier,
condition: bool,
path: Option<&[(Interval, PathState)]>,
data: &mut Data,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<Literal, ErrorInfo> {
let interval = &var.interval;
match var.ident {
name if name == COMPONENT => {
gen_literal_from_component(*interval, path, data, msg_data, sender)
}
name if name == EVENT => {
gen_literal_from_event(*interval, condition, path, data, msg_data, sender)
}
name if name == _METADATA => match path {
Some(path) => {
let path = resolve_path(path, condition, data, msg_data, sender)?;
get_literal_form_metadata(&path, condition, data, msg_data, sender)
}
None => Ok(PrimitiveObject::get_literal(
&data.context.metadata,
interval.to_owned(),
)),
},
_ => match get_var_from_mem(var.to_owned(), condition, path, data, msg_data, sender) {
Ok((lit, name, mem_type, path)) => {
let result = exec_path_actions(
lit,
condition,
None,
&path,
&ContentType::get(&lit),
msg_data,
sender,
);
let (new_literal, update_mem) = match result {
Ok((lit, update)) => (lit, update),
Err(err) => (MSG::send_error_msg(&sender, msg_data, Err(err)), false),
};
save_literal_in_mem(
lit.to_owned(),
name,
&mem_type,
update_mem,
data,
msg_data,
sender,
);
Ok(new_literal)
}
Err(err) => {
let mut null = match condition {
true => PrimitiveNull::get_literal(err.position.interval),
false => MSG::send_error_msg(&sender, msg_data, Err(err)),
};
let path = if let Some(p) = path {
Some(resolve_path(p, condition, data, msg_data, sender)?)
} else {
None
};
let content_type = ContentType::get(&null);
let (new_literal, ..) = exec_path_actions(
&mut null,
condition,
None,
&path,
&content_type,
msg_data,
sender,
)?;
Ok(new_literal)
}
},
}
}
pub fn get_var_from_mem<'a>(
name: Identifier,
condition: bool,
path: Option<&[(Interval, PathState)]>,
data: &'a mut Data,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<
(
&'a mut Literal,
String,
MemoryType,
Option<Vec<(Interval, PathLiteral)>>,
),
ErrorInfo,
> {
let path = if let Some(p) = path {
Some(resolve_path(p, condition, data, msg_data, sender)?)
} else {
None
};
match search_in_memory_type(&name, data)? {
var if var == "use" => {
let lit = get_var_from_step_var(&name, data)?;
Ok((lit, name.ident, MemoryType::Use, path))
}
_ => {
let lit = search_var_memory(name.clone(), data)?;
Ok((lit, name.ident, MemoryType::Remember, path))
}
}
}
pub fn get_string_from_complex_string(
exprs: &[Expr],
interval: Interval,
data: &mut Data,
msg_data: &mut MessageData,
sender: &Option<mpsc::Sender<MSG>>,
) -> Result<Literal, ErrorInfo> {
let mut new_string = String::new();
for elem in exprs.iter() {
match expr_to_literal(elem, false, None, data, msg_data, sender) {
Ok(var) => new_string.push_str(&var.primitive.to_string()),
Err(err) => {
return Err(err);
}
}
}
let mut result = PrimitiveString::get_literal(&new_string, interval);
result.set_content_type("text");
Ok(result)
}