use crate::evaluator::RuntimeError;
use crate::value::Value;
use std::collections::HashMap;
pub mod array;
pub mod dict;
pub mod filesystem;
pub mod help;
pub mod io;
pub mod json;
pub mod math;
pub mod network;
pub mod payroll;
pub mod precise;
pub mod report;
pub mod string;
pub mod trace;
pub mod types;
pub type BuiltInFn = fn(&[Value]) -> Result<Value, RuntimeError>;
#[derive(Debug, Clone)]
pub struct FunctionDoc {
pub name: String,
pub description: String,
pub params: Vec<(String, String)>,
pub returns: String,
pub example: Option<String>,
}
#[derive(Debug, Clone, Default)]
pub struct IOPermissions {
pub filesystem_enabled: bool,
pub network_enabled: bool,
}
impl IOPermissions {
pub fn allow_all() -> Self {
Self {
filesystem_enabled: true,
network_enabled: true,
}
}
pub fn deny_all() -> Self {
Self::default()
}
}
pub struct BuiltInRegistry {
functions: HashMap<String, (BuiltInFn, usize)>, docs: HashMap<String, FunctionDoc>, #[allow(dead_code)]
permissions: IOPermissions,
}
impl BuiltInRegistry {
pub fn new() -> Self {
Self::with_permissions(IOPermissions::default())
}
pub fn with_permissions(permissions: IOPermissions) -> Self {
let mut registry = Self {
functions: HashMap::new(),
docs: HashMap::new(),
permissions: permissions.clone(),
};
registry.register("HELP", help::help, 0);
registry.register("PRINT", io::print, 1);
registry.register("PRINTLN", io::println, 1);
registry.register("INPUT", io::input, 1);
registry.register("TRACE", trace::trace, 1);
registry.register("TRACE_DEBUG", trace::trace_debug, 2); registry.register("TRACE_INFO", trace::trace_info, 2); registry.register("TRACE_WARN", trace::trace_warn, 2); registry.register("TRACE_ERROR", trace::trace_error, 2);
registry.register("RANGE", array::range, 1); registry.register("LEN", types::len, 1);
registry.register("PUSH", array::push, 2);
registry.register("POP", array::pop, 1);
registry.register("MAP", array::map, 2);
registry.register("FILTER", array::filter, 2);
registry.register("REDUCE", array::reduce, 3);
registry.register("JOIN", array::join, 2);
registry.register("REVERSE", array::reverse, 1);
registry.register("SORT", array::sort, 1);
registry.register("SUM", array::sum, 1);
registry.register("MAX", array::max, 1);
registry.register("MIN", array::min, 1);
registry.register("KEYS", dict::keys, 1);
registry.register("VALUES", dict::values, 1);
registry.register("HAS", dict::has, 2);
registry.register("MERGE", dict::merge, 2);
registry.register("SPLIT", string::split, 2);
registry.register("UPPER", string::upper, 1);
registry.register("LOWER", string::lower, 1);
registry.register("TRIM", string::trim, 1);
registry.register("CONTAINS", string::contains, 2);
registry.register("STARTS_WITH", string::starts_with, 2);
registry.register("ENDS_WITH", string::ends_with, 2);
registry.register("REPLACE", string::replace, 3);
registry.register("REPEAT", string::repeat, 2);
registry.register("STRSLICE", string::substr, 3);
registry.register("STRLEN", string::strlen, 1);
registry.register("INDEXOF", string::index_of, 2);
registry.register("CHARAT", string::char_at, 2);
registry.register("ABS", math::abs, 1);
registry.register("FLOOR", math::floor, 1);
registry.register("CEIL", math::ceil, 1);
registry.register("ROUND", math::round, 1);
registry.register("SQRT", math::sqrt, 1);
registry.register("POW", math::pow, 2);
registry.register("SIN", math::sin, 1);
registry.register("COS", math::cos, 1);
registry.register("TAN", math::tan, 1);
registry.register("ASIN", math::asin, 1);
registry.register("ACOS", math::acos, 1);
registry.register("ATAN", math::atan, 1);
registry.register("ATAN2", math::atan2, 2);
registry.register("SINH", math::sinh, 1);
registry.register("COSH", math::cosh, 1);
registry.register("TANH", math::tanh, 1);
registry.register("LOG", math::log, 1);
registry.register("LN", math::ln, 1);
registry.register("LOG2", math::log2, 1);
registry.register("EXP", math::exp, 1);
registry.register("EXP2", math::exp2, 1);
registry.register("EXPM1", math::expm1, 1);
registry.register("LOG1P", math::log1p, 1);
registry.register("FACTORIAL", math::factorial, 1);
registry.register("GAMMA", math::gamma, 1);
registry.register("ERF", math::erf, 1);
registry.register("HYPOT", math::hypot, 2);
registry.register("SIGN", math::sign, 1);
registry.register("CLAMP", math::clamp, 3);
registry.register("MEAN", math::mean, 1);
registry.register("MEDIAN", math::median, 1);
registry.register("VARIANCE", math::variance, 1);
registry.register("STD", math::std, 1);
registry.register("QUANTILE", math::quantile, 2);
registry.register("DOT", math::dot, 2);
registry.register("NORM", math::norm, 1);
registry.register("CROSS", math::cross, 2);
registry.register("DISTANCE", math::distance, 2);
registry.register("NORMALIZE", math::normalize, 1);
registry.register("MATMUL", math::matmul, 2);
registry.register("TRANSPOSE", math::transpose, 1);
registry.register("DETERMINANT", math::determinant, 1);
registry.register("INVERSE", math::matrix_inverse, 1);
registry.register("LINEAR_REGRESSION", math::linear_regression, 2);
registry.register("NORMAL_PDF", math::normal_pdf, 1); registry.register("NORMAL_CDF", math::normal_cdf, 1); registry.register("POISSON_PMF", math::poisson_pmf, 2);
registry.register("PI", math::pi, 0);
registry.register("E", math::e, 0);
registry.register("TAU", math::tau, 0);
registry.register("PHI", math::phi, 0);
registry.register("ROUND_TO", math::round_to, 2);
registry.register("ADD_WITH_PRECISION", math::add_with_precision, 3);
registry.register("SUB_WITH_PRECISION", math::sub_with_precision, 3);
registry.register("MUL_WITH_PRECISION", math::mul_with_precision, 3);
registry.register("DIV_WITH_PRECISION", math::div_with_precision, 3);
registry.register("SET_PRECISION", math::set_precision, 2);
registry.register("TO_FRACTION", precise::to_fraction, 1);
registry.register("TO_FLOAT", precise::to_float, 1);
registry.register("SIMPLIFY", precise::simplify, 1);
registry.register("FRAC_ADD", precise::frac_add, 2);
registry.register("FRAC_SUB", precise::frac_sub, 2);
registry.register("FRAC_MUL", precise::frac_mul, 2);
registry.register("FRAC_DIV", precise::frac_div, 2);
registry.register("NUMERATOR", precise::numerator, 1);
registry.register("DENOMINATOR", precise::denominator, 1);
registry.register("GCD", precise::gcd, 2);
registry.register("LCM", precise::lcm, 2);
registry.register("TYPE", types::type_of, 1);
registry.register("TO_STRING", types::to_string, 1);
registry.register("TO_NUMBER", types::to_number, 1);
registry.register("CLONE", types::clone, 1);
registry.register("JSON_PARSE", json::json_parse, 1);
registry.register("JSON_STRINGIFY", json::json_stringify, 1);
registry.register("CALC_HOURLY_PAY", payroll::basic::calc_hourly_pay, 2);
registry.register("CALC_DAILY_PAY", payroll::basic::calc_daily_pay, 2);
registry.register(
"CALC_MONTHLY_FROM_HOURLY",
payroll::basic::calc_monthly_from_hourly,
1,
);
registry.register("CALC_ANNUAL_SALARY", payroll::basic::calc_annual_salary, 1);
registry.register("CALC_BASE_SALARY", payroll::basic::calc_base_salary, 1);
registry.register("CALC_GROSS_SALARY", payroll::basic::calc_gross_salary, 2);
registry.register("CALC_NET_SALARY", payroll::basic::calc_net_salary, 2);
registry.register("CALC_OVERTIME_PAY", payroll::overtime::calc_overtime_pay, 2);
registry.register(
"CALC_WEEKDAY_OVERTIME",
payroll::overtime::calc_weekday_overtime,
2,
);
registry.register(
"CALC_WEEKEND_OVERTIME",
payroll::overtime::calc_weekend_overtime,
2,
);
registry.register(
"CALC_HOLIDAY_OVERTIME",
payroll::overtime::calc_holiday_overtime,
2,
);
registry.register(
"CALC_TOTAL_OVERTIME",
payroll::overtime::calc_total_overtime,
4,
);
registry.register("CALC_PERSONAL_TAX", payroll::tax::calc_personal_tax, 1);
registry.register("CALC_TAXABLE_INCOME", payroll::tax::calc_taxable_income, 1);
registry.register(
"CALC_ANNUAL_BONUS_TAX",
payroll::tax::calc_annual_bonus_tax,
1,
);
registry.register(
"CALC_EFFECTIVE_TAX_RATE",
payroll::tax::calc_effective_tax_rate,
2,
);
registry.register("CALC_GROSS_FROM_NET", payroll::tax::calc_gross_from_net, 1);
registry.register("CALC_TAX_REFUND", payroll::tax::calc_tax_refund, 2);
registry.register(
"CALC_PENSION_INSURANCE",
payroll::insurance::calc_pension_insurance,
1,
);
registry.register(
"CALC_MEDICAL_INSURANCE",
payroll::insurance::calc_medical_insurance,
1,
);
registry.register(
"CALC_UNEMPLOYMENT_INSURANCE",
payroll::insurance::calc_unemployment_insurance,
1,
);
registry.register(
"CALC_HOUSING_FUND",
payroll::insurance::calc_housing_fund,
1,
);
registry.register(
"CALC_SOCIAL_INSURANCE",
payroll::insurance::calc_social_insurance,
1,
);
registry.register(
"ADJUST_SOCIAL_BASE",
payroll::insurance::adjust_social_base,
3,
);
registry.register(
"CALC_SOCIAL_BASE_LOWER",
payroll::insurance::calc_social_base_lower,
2,
);
registry.register(
"CALC_SOCIAL_BASE_UPPER",
payroll::insurance::calc_social_base_upper,
2,
);
registry.register(
"CALC_INJURY_INSURANCE",
payroll::insurance::calc_injury_insurance,
1,
);
registry.register(
"CALC_MATERNITY_INSURANCE",
payroll::insurance::calc_maternity_insurance,
1,
);
registry.register(
"CALC_ATTENDANCE_RATE",
payroll::attendance::calc_attendance_rate,
2,
);
registry.register(
"CALC_LATE_DEDUCTION",
payroll::attendance::calc_late_deduction,
1,
);
registry.register(
"CALC_EARLY_LEAVE_DEDUCTION",
payroll::attendance::calc_early_leave_deduction,
1,
);
registry.register(
"CALC_ABSENT_DEDUCTION",
payroll::attendance::calc_absent_deduction,
2,
);
registry.register(
"CALC_LEAVE_DEDUCTION",
payroll::attendance::calc_leave_deduction,
2,
);
registry.register(
"CALC_SICK_LEAVE_PAY",
payroll::attendance::calc_sick_leave_pay,
3,
);
registry.register(
"CALC_UNPAID_LEAVE_DEDUCTION",
payroll::attendance::calc_unpaid_leave_deduction,
2,
);
registry.register(
"CALC_PERFORMANCE_PAY",
payroll::bonus::calc_performance_pay,
2,
);
registry.register("CALC_ANNUAL_BONUS", payroll::bonus::calc_annual_bonus, 1);
registry.register(
"CALC_ATTENDANCE_BONUS",
payroll::bonus::calc_attendance_bonus,
2,
);
registry.register(
"CALC_SALES_COMMISSION",
payroll::bonus::calc_sales_commission,
2,
);
registry.register("CALC_PROJECT_BONUS", payroll::bonus::calc_project_bonus, 2);
registry.register("CALC_13TH_SALARY", payroll::bonus::calc_13th_salary, 2);
registry.register(
"CALC_MEAL_ALLOWANCE",
payroll::allowance::calc_meal_allowance,
2,
);
registry.register(
"CALC_TRANSPORT_ALLOWANCE",
payroll::allowance::calc_transport_allowance,
2,
);
registry.register(
"CALC_COMMUNICATION_ALLOWANCE",
payroll::allowance::calc_communication_allowance,
2,
);
registry.register(
"CALC_HOUSING_ALLOWANCE",
payroll::allowance::calc_housing_allowance,
2,
);
registry.register(
"CALC_HIGH_TEMP_ALLOWANCE",
payroll::allowance::calc_high_temp_allowance,
2,
);
registry.register(
"CALC_NIGHT_SHIFT_ALLOWANCE",
payroll::allowance::calc_night_shift_allowance,
2,
);
registry.register(
"CALC_POSITION_ALLOWANCE",
payroll::allowance::calc_position_allowance,
2,
);
registry.register(
"ANNUAL_TO_MONTHLY",
payroll::conversion::annual_to_monthly,
1,
);
registry.register(
"MONTHLY_TO_ANNUAL",
payroll::conversion::monthly_to_annual,
1,
);
registry.register("DAILY_TO_MONTHLY", payroll::conversion::daily_to_monthly, 1);
registry.register("MONTHLY_TO_DAILY", payroll::conversion::monthly_to_daily, 1);
registry.register(
"HOURLY_TO_MONTHLY",
payroll::conversion::hourly_to_monthly,
1,
);
registry.register(
"MONTHLY_TO_HOURLY",
payroll::conversion::monthly_to_hourly,
1,
);
registry.register(
"PRORATE_BY_NATURAL_DAYS",
payroll::conversion::prorate_by_natural_days,
3,
);
registry.register(
"PRORATE_BY_LEGAL_DAYS",
payroll::conversion::prorate_by_legal_days,
2,
);
registry.register(
"PRORATE_BY_WORKDAYS",
payroll::conversion::prorate_by_workdays,
3,
);
registry.register(
"CALC_ONBOARDING_SALARY",
payroll::conversion::calc_onboarding_salary,
4,
);
registry.register(
"CALC_RESIGNATION_SALARY",
payroll::conversion::calc_resignation_salary,
4,
);
registry.register("CALC_14TH_SALARY", payroll::conversion::calc_14th_salary, 2);
registry.register("CALC_NATURAL_DAYS", payroll::datetime::calc_natural_days, 2);
registry.register(
"GET_LEGAL_PAY_DAYS",
payroll::datetime::get_legal_pay_days,
0,
);
registry.register("CALC_WORKDAYS", payroll::datetime::calc_workdays, 2);
registry.register("CALC_WEEKEND_DAYS", payroll::datetime::calc_weekend_days, 2);
registry.register("CALC_HOLIDAY_DAYS", payroll::datetime::calc_holiday_days, 1);
registry.register("IS_WORKDAY", payroll::datetime::is_workday, 2);
registry.register("IS_WEEKEND", payroll::datetime::is_weekend, 1);
registry.register("IS_HOLIDAY", payroll::datetime::is_holiday, 2);
registry.register("CALC_WORK_HOURS", payroll::datetime::calc_work_hours, 1);
registry.register(
"CALC_MONTHLY_WORK_HOURS",
payroll::datetime::calc_monthly_work_hours,
0,
);
registry.register(
"CALC_ANNUAL_WORKDAYS",
payroll::datetime::calc_annual_workdays,
0,
);
registry.register(
"CALC_ANNUAL_PAY_DAYS",
payroll::datetime::calc_annual_pay_days,
0,
);
registry.register(
"CALC_SALARY_AVERAGE",
payroll::statistics::calc_salary_average,
1,
);
registry.register(
"CALC_SALARY_MEDIAN",
payroll::statistics::calc_salary_median,
1,
);
registry.register(
"CALC_SALARY_RANGE",
payroll::statistics::calc_salary_range,
1,
);
registry.register("CALC_PERCENTILE", payroll::statistics::calc_percentile, 2);
registry.register(
"CALC_SALARY_STD_DEV",
payroll::statistics::calc_salary_std_dev,
1,
);
registry.register(
"CALC_SALARY_DISTRIBUTION",
payroll::statistics::calc_salary_distribution,
2,
);
if permissions.filesystem_enabled {
registry.register("READ_FILE", filesystem::read_file, 1);
registry.register("WRITE_FILE", filesystem::write_file, 2);
registry.register("APPEND_FILE", filesystem::append_file, 2);
registry.register("DELETE_FILE", filesystem::delete_file, 1);
registry.register("FILE_EXISTS", filesystem::file_exists, 1);
registry.register("LIST_DIR", filesystem::list_dir, 1);
registry.register("CREATE_DIR", filesystem::create_dir, 1);
}
if permissions.network_enabled {
registry.register("HTTP_GET", network::http_get, 1);
registry.register("HTTP_POST", network::http_post, 2); registry.register("HTTP_PUT", network::http_put, 2); registry.register("HTTP_DELETE", network::http_delete, 1);
}
registry
}
fn register(&mut self, name: &str, func: BuiltInFn, arity: usize) {
self.functions.insert(name.to_string(), (func, arity));
}
#[allow(dead_code)]
fn register_with_doc(&mut self, name: &str, func: BuiltInFn, arity: usize, doc: FunctionDoc) {
self.functions.insert(name.to_string(), (func, arity));
self.docs.insert(name.to_string(), doc);
}
pub fn get(&self, name: &str) -> Option<(BuiltInFn, usize)> {
self.functions.get(name).copied()
}
pub fn has(&self, name: &str) -> bool {
self.functions.contains_key(name)
}
pub fn names(&self) -> Vec<String> {
self.functions.keys().cloned().collect()
}
pub fn get_doc(&self, name: &str) -> Option<&FunctionDoc> {
self.docs.get(name)
}
pub fn all_docs(&self) -> &HashMap<String, FunctionDoc> {
&self.docs
}
}
impl Default for BuiltInRegistry {
fn default() -> Self {
Self::new()
}
}