use crate::components::context::Context;
use crate::components::error_message::help_data::HelpData;
use crate::components::r#type::Type;
use crate::processes::transpiling::escape_r_string;
pub fn wrap_checked(context: &Context, r_expr: String, typ: &Type, loc: &HelpData, what: &str) -> String {
if !context.get_checked_mode() {
return r_expr;
}
match checked_descriptor(context, typ) {
Some(descriptor) => format!(
"typr_assert_type({}, {}, {}, {})",
r_expr,
descriptor,
escape_r_string(&format_loc(loc)),
escape_r_string(what)
),
None => r_expr,
}
}
pub fn param_assertion(context: &Context, param_name: &str, typ: &Type, loc: &HelpData) -> Option<String> {
if !context.get_checked_mode() {
return None;
}
let what = format!("param {}", param_name);
let wrapped = wrap_checked(context, param_name.to_string(), typ, loc, &what);
if wrapped == param_name {
None
} else {
Some(format!("{}\n", wrapped))
}
}
fn checked_descriptor(context: &Context, typ: &Type) -> Option<String> {
match typ {
Type::Integer(_, _) => Some("\"integer\"".to_string()),
Type::Number(_, _) => Some("\"double\"".to_string()),
Type::Char(_, _) => Some("\"character\"".to_string()),
Type::Boolean(_, _) => Some("\"logical\"".to_string()),
Type::Function(_, _, _) => Some("\"function\"".to_string()),
Type::Any(_)
| Type::Generic(_, _)
| Type::IndexGen(_, _)
| Type::LabelGen(_, _)
| Type::KindedGen(_, _, _)
| Type::Variable(_, _)
| Type::Interface(_, _)
| Type::UnknownFunction(_)
| Type::Failed(_, _)
| Type::Empty(_) => None,
Type::Alias(name, _, _, _) if context.resolves_to_foreign_alias(name) => None,
_ => {
if let Some(elem) = context.atomic_array_elem(typ) {
let descriptor = match elem {
Type::Integer(_, _) => "\"integer\"",
Type::Char(_, _) => "\"character\"",
Type::Boolean(_, _) => "\"logical\"",
_ => "\"double\"",
};
return Some(descriptor.to_string());
}
let head = context.get_class(typ);
if head == "'default'" || head == "'Any'" {
return None;
}
let rest = context.get_classes(typ).unwrap_or_else(|| "'None'".to_string());
Some(format!("c({}, {})", head, rest))
}
}
}
fn format_loc(loc: &HelpData) -> String {
let file = loc.get_file_name();
if file.is_empty() {
return "<unknown>".to_string();
}
let line = loc.get_file_data().and_then(|(_, content)| {
let offset = loc.get_offset().min(content.len());
content.get(..offset).map(|prefix| prefix.matches('\n').count() + 1)
});
match line {
Some(line) => format!("{}:{}", file, line),
None => format!("{}:offset {}", file, loc.get_offset()),
}
}