1use crate::evaluator::RuntimeError;
5use crate::value::Value;
6use std::collections::HashMap;
7
8pub mod array;
10pub mod dict;
11pub mod filesystem;
12pub mod help;
13pub mod io;
14pub mod json;
15pub mod math;
16pub mod network;
17pub mod payroll;
18pub mod precise;
19pub mod report;
20pub mod string;
21pub mod trace;
22pub mod types;
23
24pub type BuiltInFn = fn(&[Value]) -> Result<Value, RuntimeError>;
26
27#[derive(Debug, Clone)]
29pub struct FunctionDoc {
30 pub name: String,
32 pub description: String,
34 pub params: Vec<(String, String)>,
36 pub returns: String,
38 pub example: Option<String>,
40}
41
42#[derive(Debug, Clone, Default)]
44pub struct IOPermissions {
45 pub filesystem_enabled: bool,
47 pub network_enabled: bool,
49}
50
51impl IOPermissions {
52 pub fn allow_all() -> Self {
54 Self {
55 filesystem_enabled: true,
56 network_enabled: true,
57 }
58 }
59
60 pub fn deny_all() -> Self {
62 Self::default()
63 }
64}
65
66pub struct BuiltInRegistry {
68 functions: HashMap<String, (BuiltInFn, usize)>, docs: HashMap<String, FunctionDoc>, #[allow(dead_code)]
71 permissions: IOPermissions,
72}
73
74impl BuiltInRegistry {
75 pub fn new() -> Self {
77 Self::with_permissions(IOPermissions::default())
78 }
79
80 pub fn with_permissions(permissions: IOPermissions) -> Self {
82 let mut registry = Self {
83 functions: HashMap::new(),
84 docs: HashMap::new(),
85 permissions: permissions.clone(),
86 };
87
88 registry.register("HELP", help::help, 0); registry.register("PRINT", io::print, 1);
93 registry.register("PRINTLN", io::println, 1);
94 registry.register("INPUT", io::input, 1);
95
96 registry.register("TRACE", trace::trace, 1);
98 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);
106 registry.register("PUSH", array::push, 2);
107 registry.register("POP", array::pop, 1);
108 registry.register("MAP", array::map, 2);
109 registry.register("FILTER", array::filter, 2);
110 registry.register("REDUCE", array::reduce, 3);
111 registry.register("JOIN", array::join, 2);
112 registry.register("REVERSE", array::reverse, 1);
113 registry.register("SORT", array::sort, 1);
114 registry.register("SUM", array::sum, 1);
115 registry.register("MAX", array::max, 1);
116 registry.register("MIN", array::min, 1);
117
118 registry.register("KEYS", dict::keys, 1);
120 registry.register("VALUES", dict::values, 1);
121 registry.register("HAS", dict::has, 2);
122 registry.register("MERGE", dict::merge, 2);
123
124 registry.register("SPLIT", string::split, 2);
126 registry.register("UPPER", string::upper, 1);
127 registry.register("LOWER", string::lower, 1);
128 registry.register("TRIM", string::trim, 1);
129 registry.register("CONTAINS", string::contains, 2);
130 registry.register("STARTS_WITH", string::starts_with, 2);
131 registry.register("ENDS_WITH", string::ends_with, 2);
132 registry.register("REPLACE", string::replace, 3);
133 registry.register("REPEAT", string::repeat, 2);
134 registry.register("STRSLICE", string::substr, 3);
135 registry.register("STRLEN", string::strlen, 1);
136 registry.register("INDEXOF", string::index_of, 2);
137 registry.register("CHARAT", string::char_at, 2);
138
139 registry.register("ABS", math::abs, 1);
141 registry.register("FLOOR", math::floor, 1);
142 registry.register("CEIL", math::ceil, 1);
143 registry.register("ROUND", math::round, 1);
144 registry.register("SQRT", math::sqrt, 1);
145 registry.register("POW", math::pow, 2);
146
147 registry.register("SIN", math::sin, 1);
149 registry.register("COS", math::cos, 1);
150 registry.register("TAN", math::tan, 1);
151 registry.register("ASIN", math::asin, 1);
152 registry.register("ACOS", math::acos, 1);
153 registry.register("ATAN", math::atan, 1);
154 registry.register("ATAN2", math::atan2, 2);
155 registry.register("SINH", math::sinh, 1);
156 registry.register("COSH", math::cosh, 1);
157 registry.register("TANH", math::tanh, 1);
158
159 registry.register("LOG", math::log, 1);
161 registry.register("LN", math::ln, 1);
162 registry.register("LOG2", math::log2, 1);
163 registry.register("EXP", math::exp, 1);
164 registry.register("EXP2", math::exp2, 1);
165 registry.register("EXPM1", math::expm1, 1);
166 registry.register("LOG1P", math::log1p, 1);
167
168 registry.register("FACTORIAL", math::factorial, 1);
170 registry.register("GAMMA", math::gamma, 1);
171 registry.register("ERF", math::erf, 1);
172 registry.register("HYPOT", math::hypot, 2);
173 registry.register("SIGN", math::sign, 1);
174 registry.register("CLAMP", math::clamp, 3);
175
176 registry.register("MEAN", math::mean, 1);
178 registry.register("MEDIAN", math::median, 1);
179 registry.register("VARIANCE", math::variance, 1);
180 registry.register("STD", math::std, 1);
181 registry.register("QUANTILE", math::quantile, 2);
182
183 registry.register("DOT", math::dot, 2);
185 registry.register("NORM", math::norm, 1);
186 registry.register("CROSS", math::cross, 2);
187 registry.register("DISTANCE", math::distance, 2);
188 registry.register("NORMALIZE", math::normalize, 1);
189
190 registry.register("MATMUL", math::matmul, 2);
192 registry.register("TRANSPOSE", math::transpose, 1);
193 registry.register("DETERMINANT", math::determinant, 1);
194 registry.register("INVERSE", math::matrix_inverse, 1);
195
196 registry.register("LINEAR_REGRESSION", math::linear_regression, 2);
198
199 registry.register("NORMAL_PDF", math::normal_pdf, 1); registry.register("NORMAL_CDF", math::normal_cdf, 1); registry.register("POISSON_PMF", math::poisson_pmf, 2);
203
204 registry.register("PI", math::pi, 0);
206 registry.register("E", math::e, 0);
207 registry.register("TAU", math::tau, 0);
208 registry.register("PHI", math::phi, 0);
209
210 registry.register("ROUND_TO", math::round_to, 2);
212 registry.register("ADD_WITH_PRECISION", math::add_with_precision, 3);
213 registry.register("SUB_WITH_PRECISION", math::sub_with_precision, 3);
214 registry.register("MUL_WITH_PRECISION", math::mul_with_precision, 3);
215 registry.register("DIV_WITH_PRECISION", math::div_with_precision, 3);
216 registry.register("SET_PRECISION", math::set_precision, 2);
217
218 registry.register("TO_FRACTION", precise::to_fraction, 1);
220 registry.register("TO_FLOAT", precise::to_float, 1);
221 registry.register("SIMPLIFY", precise::simplify, 1);
222 registry.register("FRAC_ADD", precise::frac_add, 2);
223 registry.register("FRAC_SUB", precise::frac_sub, 2);
224 registry.register("FRAC_MUL", precise::frac_mul, 2);
225 registry.register("FRAC_DIV", precise::frac_div, 2);
226 registry.register("NUMERATOR", precise::numerator, 1);
227 registry.register("DENOMINATOR", precise::denominator, 1);
228 registry.register("GCD", precise::gcd, 2);
229 registry.register("LCM", precise::lcm, 2);
230
231 registry.register("TYPE", types::type_of, 1);
233 registry.register("TO_STRING", types::to_string, 1);
234 registry.register("TO_NUMBER", types::to_number, 1);
235 registry.register("CLONE", types::clone, 1);
236
237 registry.register("JSON_PARSE", json::json_parse, 1);
239 registry.register("JSON_STRINGIFY", json::json_stringify, 1); registry.register("CALC_HOURLY_PAY", payroll::basic::calc_hourly_pay, 2);
243 registry.register("CALC_DAILY_PAY", payroll::basic::calc_daily_pay, 2);
244 registry.register(
245 "CALC_MONTHLY_FROM_HOURLY",
246 payroll::basic::calc_monthly_from_hourly,
247 1,
248 );
249 registry.register("CALC_ANNUAL_SALARY", payroll::basic::calc_annual_salary, 1);
250 registry.register("CALC_BASE_SALARY", payroll::basic::calc_base_salary, 1);
251 registry.register("CALC_GROSS_SALARY", payroll::basic::calc_gross_salary, 2);
252 registry.register("CALC_NET_SALARY", payroll::basic::calc_net_salary, 2);
253
254 registry.register("CALC_OVERTIME_PAY", payroll::overtime::calc_overtime_pay, 2);
256 registry.register(
257 "CALC_WEEKDAY_OVERTIME",
258 payroll::overtime::calc_weekday_overtime,
259 2,
260 );
261 registry.register(
262 "CALC_WEEKEND_OVERTIME",
263 payroll::overtime::calc_weekend_overtime,
264 2,
265 );
266 registry.register(
267 "CALC_HOLIDAY_OVERTIME",
268 payroll::overtime::calc_holiday_overtime,
269 2,
270 );
271 registry.register(
272 "CALC_TOTAL_OVERTIME",
273 payroll::overtime::calc_total_overtime,
274 4,
275 );
276
277 registry.register("CALC_PERSONAL_TAX", payroll::tax::calc_personal_tax, 1);
279 registry.register("CALC_TAXABLE_INCOME", payroll::tax::calc_taxable_income, 1);
280 registry.register(
281 "CALC_ANNUAL_BONUS_TAX",
282 payroll::tax::calc_annual_bonus_tax,
283 1,
284 );
285 registry.register(
286 "CALC_EFFECTIVE_TAX_RATE",
287 payroll::tax::calc_effective_tax_rate,
288 2,
289 );
290 registry.register("CALC_GROSS_FROM_NET", payroll::tax::calc_gross_from_net, 1);
291 registry.register("CALC_TAX_REFUND", payroll::tax::calc_tax_refund, 2);
292
293 registry.register(
295 "CALC_PENSION_INSURANCE",
296 payroll::insurance::calc_pension_insurance,
297 1,
298 );
299 registry.register(
300 "CALC_MEDICAL_INSURANCE",
301 payroll::insurance::calc_medical_insurance,
302 1,
303 );
304 registry.register(
305 "CALC_UNEMPLOYMENT_INSURANCE",
306 payroll::insurance::calc_unemployment_insurance,
307 1,
308 );
309 registry.register(
310 "CALC_HOUSING_FUND",
311 payroll::insurance::calc_housing_fund,
312 1,
313 );
314 registry.register(
315 "CALC_SOCIAL_INSURANCE",
316 payroll::insurance::calc_social_insurance,
317 1,
318 );
319 registry.register(
320 "ADJUST_SOCIAL_BASE",
321 payroll::insurance::adjust_social_base,
322 3,
323 );
324 registry.register(
325 "CALC_SOCIAL_BASE_LOWER",
326 payroll::insurance::calc_social_base_lower,
327 2,
328 );
329 registry.register(
330 "CALC_SOCIAL_BASE_UPPER",
331 payroll::insurance::calc_social_base_upper,
332 2,
333 );
334 registry.register(
335 "CALC_INJURY_INSURANCE",
336 payroll::insurance::calc_injury_insurance,
337 1,
338 );
339 registry.register(
340 "CALC_MATERNITY_INSURANCE",
341 payroll::insurance::calc_maternity_insurance,
342 1,
343 );
344
345 registry.register(
347 "CALC_ATTENDANCE_RATE",
348 payroll::attendance::calc_attendance_rate,
349 2,
350 );
351 registry.register(
352 "CALC_LATE_DEDUCTION",
353 payroll::attendance::calc_late_deduction,
354 1,
355 );
356 registry.register(
357 "CALC_EARLY_LEAVE_DEDUCTION",
358 payroll::attendance::calc_early_leave_deduction,
359 1,
360 );
361 registry.register(
362 "CALC_ABSENT_DEDUCTION",
363 payroll::attendance::calc_absent_deduction,
364 2,
365 );
366 registry.register(
367 "CALC_LEAVE_DEDUCTION",
368 payroll::attendance::calc_leave_deduction,
369 2,
370 );
371 registry.register(
372 "CALC_SICK_LEAVE_PAY",
373 payroll::attendance::calc_sick_leave_pay,
374 3,
375 );
376 registry.register(
377 "CALC_UNPAID_LEAVE_DEDUCTION",
378 payroll::attendance::calc_unpaid_leave_deduction,
379 2,
380 );
381
382 registry.register(
384 "CALC_PERFORMANCE_PAY",
385 payroll::bonus::calc_performance_pay,
386 2,
387 );
388 registry.register("CALC_ANNUAL_BONUS", payroll::bonus::calc_annual_bonus, 1);
389 registry.register(
390 "CALC_ATTENDANCE_BONUS",
391 payroll::bonus::calc_attendance_bonus,
392 2,
393 );
394 registry.register(
395 "CALC_SALES_COMMISSION",
396 payroll::bonus::calc_sales_commission,
397 2,
398 );
399 registry.register("CALC_PROJECT_BONUS", payroll::bonus::calc_project_bonus, 2);
400 registry.register("CALC_13TH_SALARY", payroll::bonus::calc_13th_salary, 2);
401
402 registry.register(
404 "CALC_MEAL_ALLOWANCE",
405 payroll::allowance::calc_meal_allowance,
406 2,
407 );
408 registry.register(
409 "CALC_TRANSPORT_ALLOWANCE",
410 payroll::allowance::calc_transport_allowance,
411 2,
412 );
413 registry.register(
414 "CALC_COMMUNICATION_ALLOWANCE",
415 payroll::allowance::calc_communication_allowance,
416 2,
417 );
418 registry.register(
419 "CALC_HOUSING_ALLOWANCE",
420 payroll::allowance::calc_housing_allowance,
421 2,
422 );
423 registry.register(
424 "CALC_HIGH_TEMP_ALLOWANCE",
425 payroll::allowance::calc_high_temp_allowance,
426 2,
427 );
428 registry.register(
429 "CALC_NIGHT_SHIFT_ALLOWANCE",
430 payroll::allowance::calc_night_shift_allowance,
431 2,
432 );
433 registry.register(
434 "CALC_POSITION_ALLOWANCE",
435 payroll::allowance::calc_position_allowance,
436 2,
437 );
438
439 registry.register(
441 "ANNUAL_TO_MONTHLY",
442 payroll::conversion::annual_to_monthly,
443 1,
444 );
445 registry.register(
446 "MONTHLY_TO_ANNUAL",
447 payroll::conversion::monthly_to_annual,
448 1,
449 );
450 registry.register("DAILY_TO_MONTHLY", payroll::conversion::daily_to_monthly, 1);
451 registry.register("MONTHLY_TO_DAILY", payroll::conversion::monthly_to_daily, 1);
452 registry.register(
453 "HOURLY_TO_MONTHLY",
454 payroll::conversion::hourly_to_monthly,
455 1,
456 );
457 registry.register(
458 "MONTHLY_TO_HOURLY",
459 payroll::conversion::monthly_to_hourly,
460 1,
461 );
462 registry.register(
463 "PRORATE_BY_NATURAL_DAYS",
464 payroll::conversion::prorate_by_natural_days,
465 3,
466 );
467 registry.register(
468 "PRORATE_BY_LEGAL_DAYS",
469 payroll::conversion::prorate_by_legal_days,
470 2,
471 );
472 registry.register(
473 "PRORATE_BY_WORKDAYS",
474 payroll::conversion::prorate_by_workdays,
475 3,
476 );
477 registry.register(
478 "CALC_ONBOARDING_SALARY",
479 payroll::conversion::calc_onboarding_salary,
480 4,
481 );
482 registry.register(
483 "CALC_RESIGNATION_SALARY",
484 payroll::conversion::calc_resignation_salary,
485 4,
486 );
487 registry.register("CALC_14TH_SALARY", payroll::conversion::calc_14th_salary, 2);
488
489 registry.register("CALC_NATURAL_DAYS", payroll::datetime::calc_natural_days, 2);
491 registry.register(
492 "GET_LEGAL_PAY_DAYS",
493 payroll::datetime::get_legal_pay_days,
494 0,
495 );
496 registry.register("CALC_WORKDAYS", payroll::datetime::calc_workdays, 2);
497 registry.register("CALC_WEEKEND_DAYS", payroll::datetime::calc_weekend_days, 2);
498 registry.register("CALC_HOLIDAY_DAYS", payroll::datetime::calc_holiday_days, 1);
499 registry.register("IS_WORKDAY", payroll::datetime::is_workday, 2);
500 registry.register("IS_WEEKEND", payroll::datetime::is_weekend, 1);
501 registry.register("IS_HOLIDAY", payroll::datetime::is_holiday, 2);
502 registry.register("CALC_WORK_HOURS", payroll::datetime::calc_work_hours, 1);
503 registry.register(
504 "CALC_MONTHLY_WORK_HOURS",
505 payroll::datetime::calc_monthly_work_hours,
506 0,
507 );
508 registry.register(
509 "CALC_ANNUAL_WORKDAYS",
510 payroll::datetime::calc_annual_workdays,
511 0,
512 );
513 registry.register(
514 "CALC_ANNUAL_PAY_DAYS",
515 payroll::datetime::calc_annual_pay_days,
516 0,
517 );
518
519 registry.register(
521 "CALC_SALARY_AVERAGE",
522 payroll::statistics::calc_salary_average,
523 1,
524 );
525 registry.register(
526 "CALC_SALARY_MEDIAN",
527 payroll::statistics::calc_salary_median,
528 1,
529 );
530 registry.register(
531 "CALC_SALARY_RANGE",
532 payroll::statistics::calc_salary_range,
533 1,
534 );
535 registry.register("CALC_PERCENTILE", payroll::statistics::calc_percentile, 2);
536 registry.register(
537 "CALC_SALARY_STD_DEV",
538 payroll::statistics::calc_salary_std_dev,
539 1,
540 );
541 registry.register(
542 "CALC_SALARY_DISTRIBUTION",
543 payroll::statistics::calc_salary_distribution,
544 2,
545 );
546
547 if permissions.filesystem_enabled {
549 registry.register("READ_FILE", filesystem::read_file, 1);
550 registry.register("WRITE_FILE", filesystem::write_file, 2);
551 registry.register("APPEND_FILE", filesystem::append_file, 2);
552 registry.register("DELETE_FILE", filesystem::delete_file, 1);
553 registry.register("FILE_EXISTS", filesystem::file_exists, 1);
554 registry.register("LIST_DIR", filesystem::list_dir, 1);
555 registry.register("CREATE_DIR", filesystem::create_dir, 1);
556 }
557
558 if permissions.network_enabled {
560 registry.register("HTTP_GET", network::http_get, 1);
561 registry.register("HTTP_POST", network::http_post, 2); registry.register("HTTP_PUT", network::http_put, 2); registry.register("HTTP_DELETE", network::http_delete, 1);
564 }
565
566 registry.register("FORMAT_NUMBER", report::format_number, 1); registry.register("FORMAT_CURRENCY", report::format_currency, 1); registry.register("FORMAT_PERCENT", report::format_percent, 1); registry.register("FORMAT_DATE", report::format_date, 1); if permissions.filesystem_enabled {
574 registry.register("EXCEL_CREATE", report::excel_create, 0);
575 registry.register("EXCEL_WRITE_CELL", report::excel_write_cell, 5);
576 registry.register("EXCEL_WRITE_ROW", report::excel_write_row, 4);
577 registry.register("EXCEL_WRITE_COLUMN", report::excel_write_column, 4);
578 registry.register("EXCEL_WRITE_TABLE", report::excel_write_table, 5);
579 registry.register("EXCEL_SAVE", report::excel_save, 2);
580 registry.register("EXCEL_READ_SHEET", report::excel_read_sheet, 2);
581 registry.register("EXCEL_READ_CELL", report::excel_read_cell, 4);
582 registry.register("EXCEL_READ_RANGE", report::excel_read_range, 6);
583 registry.register("EXCEL_GET_SHEETS", report::excel_get_sheets, 1);
584 }
585
586 registry
587 }
588
589 fn register(&mut self, name: &str, func: BuiltInFn, arity: usize) {
591 self.functions.insert(name.to_string(), (func, arity));
592 }
593
594 #[allow(dead_code)]
596 fn register_with_doc(&mut self, name: &str, func: BuiltInFn, arity: usize, doc: FunctionDoc) {
597 self.functions.insert(name.to_string(), (func, arity));
598 self.docs.insert(name.to_string(), doc);
599 }
600
601 pub fn get(&self, name: &str) -> Option<(BuiltInFn, usize)> {
603 self.functions.get(name).copied()
604 }
605
606 pub fn has(&self, name: &str) -> bool {
608 self.functions.contains_key(name)
609 }
610
611 pub fn names(&self) -> Vec<String> {
613 self.functions.keys().cloned().collect()
614 }
615
616 pub fn get_doc(&self, name: &str) -> Option<&FunctionDoc> {
618 self.docs.get(name)
619 }
620
621 pub fn all_docs(&self) -> &HashMap<String, FunctionDoc> {
623 &self.docs
624 }
625}
626
627impl Default for BuiltInRegistry {
628 fn default() -> Self {
629 Self::new()
630 }
631}