From b152ed88f0e539685ff9be3b96996c8fefec44c3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 1 Mar 2020 17:37:47 +0800 Subject: [PATCH] Move built-in functions into separate module. --- README.md | 25 +++- src/builtin.rs | 312 ++++++++++++++++++++++++++++++++++++++++++++++++ src/engine.rs | 314 ++----------------------------------------------- src/lib.rs | 1 + 4 files changed, 345 insertions(+), 307 deletions(-) create mode 100644 src/builtin.rs diff --git a/README.md b/README.md index 096a34d9..4096dc82 100644 --- a/README.md +++ b/README.md @@ -474,6 +474,7 @@ The following standard functions operate on arrays: * `shift` - removes the first element and returns it (() if empty) * `len` - returns the number of elements * `pad` - pads the array with an element until a specified length +* `clear` - empties the array * `truncate` - cuts off the array at exactly a specified length (discarding all subsequent elements) ```rust @@ -506,6 +507,10 @@ print(y.len()); // prints 10 y.truncate(5); // truncate the array to 5 elements print(y.len()); // prints 5 + +y.clear(); // empty the array + +print(y.len()); // prints 0 ``` `push` and `pad` are only defined for standard built-in types. If you want to use them with @@ -574,24 +579,36 @@ The following standard functions operate on strings: * `len` - returns the number of characters (not number of bytes) in the string * `pad` - pads the string with an character until a specified number of characters +* `clear` - empties the string * `truncate` - cuts off the string at exactly a specified number of characters +* `contains` - checks if a certain character or sub-string occurs in the string * `replace` - replaces a substring with another +* `trim` - trims the string ```rust -let full_name == "Bob C. Davis"; +let full_name == " Bob C. Davis "; +full_name.len() == 14; + +full_name.trim(); full_name.len() == 12; full_name.pad(15, '$'); -full_name.len() = 15; +full_name.len() == 15; full_name == "Bob C. Davis$$$"; full_name.truncate(6); -full_name.len() = 6; +full_name.len() == 6; full_name == "Bob C."; full_name.replace("Bob", "John"); -full_name.len() = 7; +full_name.len() == 7; full_name = "John C."; + +full_name.contains('C') == true; +full_name.contains("John") == true; + +full_name.clear(); +full_name.len() == 0; ``` ## Print and Debug diff --git a/src/builtin.rs b/src/builtin.rs new file mode 100644 index 00000000..5157eaca --- /dev/null +++ b/src/builtin.rs @@ -0,0 +1,312 @@ +use crate::{any::Any, Array, Dynamic, Engine, RegisterDynamicFn, RegisterFn}; +use std::fmt::{Debug, Display}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; + +macro_rules! reg_op { + ($self:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $y, y: $y)->$y); + )* + ) +} + +macro_rules! reg_un { + ($self:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $y)->$y); + )* + ) +} + +macro_rules! reg_cmp { + ($self:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $y, y: $y)->bool); + )* + ) +} + +macro_rules! reg_func1 { + ($self:expr, $x:expr, $op:expr, $r:ty, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $y)->$r); + )* + ) +} + +macro_rules! reg_func2x { + ($self:expr, $x:expr, $op:expr, $v:ty, $r:ty, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $v, y: $y)->$r); + )* + ) +} + +macro_rules! reg_func2y { + ($self:expr, $x:expr, $op:expr, $v:ty, $r:ty, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(y: $y, x: $v)->$r); + )* + ) +} + +macro_rules! reg_func3 { + ($self:expr, $x:expr, $op:expr, $v:ty, $w:ty, $r:ty, $( $y:ty ),*) => ( + $( + $self.register_fn($x, $op as fn(x: $v, y: $w, z: $y)->$r); + )* + ) +} + +impl Engine { + /// Register the built-in library. + pub(crate) fn register_builtins(&mut self) { + fn add(x: T, y: T) -> ::Output { + x + y + } + fn sub(x: T, y: T) -> ::Output { + x - y + } + fn mul(x: T, y: T) -> ::Output { + x * y + } + fn div(x: T, y: T) -> ::Output { + x / y + } + fn neg(x: T) -> ::Output { + -x + } + fn lt(x: T, y: T) -> bool { + x < y + } + fn lte(x: T, y: T) -> bool { + x <= y + } + fn gt(x: T, y: T) -> bool { + x > y + } + fn gte(x: T, y: T) -> bool { + x >= y + } + fn eq(x: T, y: T) -> bool { + x == y + } + fn ne(x: T, y: T) -> bool { + x != y + } + fn and(x: bool, y: bool) -> bool { + x && y + } + fn or(x: bool, y: bool) -> bool { + x || y + } + fn not(x: bool) -> bool { + !x + } + fn concat(x: String, y: String) -> String { + x + &y + } + fn binary_and(x: T, y: T) -> ::Output { + x & y + } + fn binary_or(x: T, y: T) -> ::Output { + x | y + } + fn binary_xor(x: T, y: T) -> ::Output { + x ^ y + } + fn left_shift>(x: T, y: T) -> >::Output { + x.shl(y) + } + fn right_shift>(x: T, y: T) -> >::Output { + x.shr(y) + } + fn modulo>(x: T, y: T) -> >::Output { + x % y + } + fn pow_i64_i64(x: i64, y: i64) -> i64 { + x.pow(y as u32) + } + fn pow_f64_f64(x: f64, y: f64) -> f64 { + x.powf(y) + } + fn pow_f64_i64(x: f64, y: i64) -> f64 { + x.powi(y as i32) + } + fn unit_eq(_a: (), _b: ()) -> bool { + true + } + + reg_op!(self, "+", add, i32, i64, u32, u64, f32, f64); + reg_op!(self, "-", sub, i32, i64, u32, u64, f32, f64); + reg_op!(self, "*", mul, i32, i64, u32, u64, f32, f64); + reg_op!(self, "/", div, i32, i64, u32, u64, f32, f64); + + reg_cmp!(self, "<", lt, i32, i64, u32, u64, String, char, f32, f64); + reg_cmp!(self, "<=", lte, i32, i64, u32, u64, String, char, f32, f64); + reg_cmp!(self, ">", gt, i32, i64, u32, u64, String, char, f32, f64); + reg_cmp!(self, ">=", gte, i32, i64, u32, u64, String, char, f32, f64); + reg_cmp!(self, "==", eq, i32, i64, u32, u64, bool, String, char, f32, f64); + reg_cmp!(self, "!=", ne, i32, i64, u32, u64, bool, String, char, f32, f64); + + reg_op!(self, "||", or, bool); + reg_op!(self, "&&", and, bool); + reg_op!(self, "|", binary_or, i32, i64, u32, u64); + reg_op!(self, "|", or, bool); + reg_op!(self, "&", binary_and, i32, i64, u32, u64); + reg_op!(self, "&", and, bool); + reg_op!(self, "^", binary_xor, i32, i64, u32, u64); + reg_op!(self, "<<", left_shift, i32, i64, u32, u64); + reg_op!(self, ">>", right_shift, i32, i64, u32, u64); + reg_op!(self, "%", modulo, i32, i64, u32, u64); + self.register_fn("~", pow_i64_i64); + self.register_fn("~", pow_f64_f64); + self.register_fn("~", pow_f64_i64); + + reg_un!(self, "-", neg, i32, i64, f32, f64); + reg_un!(self, "!", not, bool); + + self.register_fn("+", concat); + self.register_fn("==", unit_eq); + + // self.register_fn("[]", idx); + // FIXME? Registering array lookups are a special case because we want to return boxes + // directly let ent = self.fns.entry("[]".to_string()).or_insert_with(Vec::new); + // (*ent).push(FnType::ExternalFn2(Box::new(idx))); + + // Register conversion functions + self.register_fn("to_float", |x: i32| x as f64); + self.register_fn("to_float", |x: u32| x as f64); + self.register_fn("to_float", |x: i64| x as f64); + self.register_fn("to_float", |x: u64| x as f64); + self.register_fn("to_float", |x: f32| x as f64); + + self.register_fn("to_int", |x: i32| x as i64); + self.register_fn("to_int", |x: u32| x as i64); + self.register_fn("to_int", |x: u64| x as i64); + self.register_fn("to_int", |x: f32| x as i64); + self.register_fn("to_int", |x: f64| x as i64); + self.register_fn("to_int", |ch: char| ch as i64); + + // Register print and debug + fn print_debug(x: T) -> String { + format!("{:?}", x) + } + fn print(x: T) -> String { + format!("{}", x) + } + + reg_func1!(self, "print", print, String, i32, i64, u32, u64); + reg_func1!(self, "print", print, String, f32, f64, bool, char, String); + reg_func1!(self, "print", print_debug, String, Array); + self.register_fn("print", |_: ()| println!()); + + reg_func1!(self, "debug", print_debug, String, i32, i64, u32, u64); + reg_func1!(self, "debug", print_debug, String, f32, f64, bool, char); + reg_func1!(self, "debug", print_debug, String, String, Array, ()); + + // Register array utility functions + fn push(list: &mut Array, item: T) { + list.push(Box::new(item)); + } + fn pad(list: &mut Array, len: i64, item: T) { + if len >= 0 { + while list.len() < len as usize { + push(list, item.clone()); + } + } + } + + reg_func2x!(self, "push", push, &mut Array, (), i32, i64, u32, u64); + reg_func2x!(self, "push", push, &mut Array, (), f32, f64, bool, char); + reg_func2x!(self, "push", push, &mut Array, (), String, Array, ()); + reg_func3!(self, "pad", pad, &mut Array, i64, (), i32, u32, f32); + reg_func3!(self, "pad", pad, &mut Array, i64, (), i64, u64, f64); + reg_func3!(self, "pad", pad, &mut Array, i64, (), bool, char); + reg_func3!(self, "pad", pad, &mut Array, i64, (), String, Array, ()); + + self.register_dynamic_fn("pop", |list: &mut Array| list.pop().unwrap_or(Box::new(()))); + self.register_dynamic_fn("shift", |list: &mut Array| { + if list.len() > 0 { + list.remove(0) + } else { + Box::new(()) + } + }); + self.register_fn("len", |list: &mut Array| list.len() as i64); + self.register_fn("clear", |list: &mut Array| list.clear()); + self.register_fn("truncate", |list: &mut Array, len: i64| { + if len >= 0 { + list.truncate(len as usize); + } + }); + + // Register string concatenate functions + fn prepend(x: T, y: String) -> String { + format!("{}{}", x, y) + } + fn append(x: String, y: T) -> String { + format!("{}{}", x, y) + } + + reg_func2x!(self, "+", append, String, String, i32, i64, u32, u64, f32, f64, bool, char); + self.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y)); + self.register_fn("+", |x: String, _: ()| format!("{}", x)); + + reg_func2y!(self, "+", prepend, String, String, i32, i64, u32, u64, f32, f64, bool, char); + self.register_fn("+", |x: Array, y: String| format!("{:?}{}", x, y)); + self.register_fn("+", |_: (), y: String| format!("{}", y)); + + // Register string utility functions + self.register_fn("len", |s: &mut String| s.chars().count() as i64); + self.register_fn("contains", |s: &mut String, ch: char| s.contains(ch)); + self.register_fn("contains", |s: &mut String, find: String| s.contains(&find)); + self.register_fn("clear", |s: &mut String| s.clear()); + self.register_fn("truncate", |s: &mut String, len: i64| { + if len >= 0 { + let chars: Vec<_> = s.chars().take(len as usize).collect(); + s.clear(); + chars.iter().for_each(|&ch| s.push(ch)); + } else { + s.clear(); + } + }); + self.register_fn("pad", |s: &mut String, len: i64, ch: char| { + for _ in 0..s.chars().count() - len as usize { + s.push(ch); + } + }); + self.register_fn("replace", |s: &mut String, find: String, sub: String| { + let new_str = s.replace(&find, &sub); + s.clear(); + s.push_str(&new_str); + }); + self.register_fn("trim", |s: &mut String| { + let trimmed = s.trim(); + + if trimmed.len() < s.len() { + let chars: Vec<_> = trimmed.chars().collect(); + s.clear(); + chars.iter().for_each(|&ch| s.push(ch)); + } + }); + + // Register array iterator + self.register_iterator::(|a| { + Box::new(a.downcast_ref::().unwrap().clone().into_iter()) + }); + + // Register range function + use std::ops::Range; + self.register_iterator::, _>(|a| { + Box::new( + a.downcast_ref::>() + .unwrap() + .clone() + .map(|n| Box::new(n) as Dynamic), + ) + }); + + self.register_fn("range", |i1: i64, i2: i64| (i1..i2)); + } +} diff --git a/src/engine.rs b/src/engine.rs index e4ab6e2e..38849e7e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -3,14 +3,13 @@ use std::cmp::{PartialEq, PartialOrd}; use std::collections::HashMap; use std::error::Error; use std::fmt; -use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::sync::Arc; use crate::any::{Any, AnyExt, Dynamic, Variant}; use crate::call::FunArgs; -use crate::fn_register::{RegisterDynamicFn, RegisterFn}; +use crate::fn_register::RegisterFn; use crate::parser::{lex, parse, Expr, FnDef, ParseError, Stmt, AST}; -use fmt::{Debug, Display}; +use fmt::Debug; pub type Array = Vec; pub type FnCallArgs<'a> = Vec<&'a mut Variant>; @@ -214,7 +213,7 @@ impl Engine { /// Universal method for calling functions, that are either /// registered with the `Engine` or written in Rhai - pub fn call_fn_raw(&self, ident: String, args: FnCallArgs) -> Result { + fn call_fn_raw(&self, ident: String, args: FnCallArgs) -> Result { debug_println!( "Trying to call function {:?} with args {:?}", ident, @@ -286,7 +285,12 @@ impl Engine { }) } - pub fn register_fn_raw(&mut self, ident: String, args: Option>, f: Box) { + pub(crate) fn register_fn_raw( + &mut self, + ident: String, + args: Option>, + f: Box, + ) { debug_println!("Register; {:?} with args {:?}", ident, args); let spec = FnSpec { ident, args }; @@ -501,7 +505,7 @@ impl Engine { // Collect all the characters after the index let mut chars: Vec = s.chars().collect(); chars[idx] = new_ch; - s.truncate(0); + s.clear(); chars.iter().for_each(|&ch| s.push(ch)); } @@ -1008,302 +1012,6 @@ impl Engine { } } - /// Register the default library. That means, numeric types, char, bool - /// String, arithmetics and string concatenations. - pub fn register_default_lib(engine: &mut Engine) { - macro_rules! reg_op { - ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $y, y: $y)->$y); - )* - ) - } - - macro_rules! reg_un { - ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $y)->$y); - )* - ) - } - - macro_rules! reg_cmp { - ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $y, y: $y)->bool); - )* - ) - } - - macro_rules! reg_func1 { - ($engine:expr, $x:expr, $op:expr, $r:ty, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $y)->$r); - )* - ) - } - - macro_rules! reg_func2x { - ($engine:expr, $x:expr, $op:expr, $v:ty, $r:ty, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $v, y: $y)->$r); - )* - ) - } - - macro_rules! reg_func2y { - ($engine:expr, $x:expr, $op:expr, $v:ty, $r:ty, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(y: $y, x: $v)->$r); - )* - ) - } - - macro_rules! reg_func3 { - ($engine:expr, $x:expr, $op:expr, $v:ty, $w:ty, $r:ty, $( $y:ty ),*) => ( - $( - $engine.register_fn($x, $op as fn(x: $v, y: $w, z: $y)->$r); - )* - ) - } - - fn add(x: T, y: T) -> ::Output { - x + y - } - fn sub(x: T, y: T) -> ::Output { - x - y - } - fn mul(x: T, y: T) -> ::Output { - x * y - } - fn div(x: T, y: T) -> ::Output { - x / y - } - fn neg(x: T) -> ::Output { - -x - } - fn lt(x: T, y: T) -> bool { - x < y - } - fn lte(x: T, y: T) -> bool { - x <= y - } - fn gt(x: T, y: T) -> bool { - x > y - } - fn gte(x: T, y: T) -> bool { - x >= y - } - fn eq(x: T, y: T) -> bool { - x == y - } - fn ne(x: T, y: T) -> bool { - x != y - } - fn and(x: bool, y: bool) -> bool { - x && y - } - fn or(x: bool, y: bool) -> bool { - x || y - } - fn not(x: bool) -> bool { - !x - } - fn concat(x: String, y: String) -> String { - x + &y - } - fn binary_and(x: T, y: T) -> ::Output { - x & y - } - fn binary_or(x: T, y: T) -> ::Output { - x | y - } - fn binary_xor(x: T, y: T) -> ::Output { - x ^ y - } - fn left_shift>(x: T, y: T) -> >::Output { - x.shl(y) - } - fn right_shift>(x: T, y: T) -> >::Output { - x.shr(y) - } - fn modulo>(x: T, y: T) -> >::Output { - x % y - } - fn pow_i64_i64(x: i64, y: i64) -> i64 { - x.pow(y as u32) - } - fn pow_f64_f64(x: f64, y: f64) -> f64 { - x.powf(y) - } - fn pow_f64_i64(x: f64, y: i64) -> f64 { - x.powi(y as i32) - } - fn unit_eq(_a: (), _b: ()) -> bool { - true - } - - reg_op!(engine, "+", add, i32, i64, u32, u64, f32, f64); - reg_op!(engine, "-", sub, i32, i64, u32, u64, f32, f64); - reg_op!(engine, "*", mul, i32, i64, u32, u64, f32, f64); - reg_op!(engine, "/", div, i32, i64, u32, u64, f32, f64); - - reg_cmp!(engine, "<", lt, i32, i64, u32, u64, String, char, f32, f64); - reg_cmp!(engine, "<=", lte, i32, i64, u32, u64, String, char, f32, f64); - reg_cmp!(engine, ">", gt, i32, i64, u32, u64, String, char, f32, f64); - reg_cmp!(engine, ">=", gte, i32, i64, u32, u64, String, char, f32, f64); - reg_cmp!(engine, "==", eq, i32, i64, u32, u64, bool, String, char, f32, f64); - reg_cmp!(engine, "!=", ne, i32, i64, u32, u64, bool, String, char, f32, f64); - - reg_op!(engine, "||", or, bool); - reg_op!(engine, "&&", and, bool); - reg_op!(engine, "|", binary_or, i32, i64, u32, u64); - reg_op!(engine, "|", or, bool); - reg_op!(engine, "&", binary_and, i32, i64, u32, u64); - reg_op!(engine, "&", and, bool); - reg_op!(engine, "^", binary_xor, i32, i64, u32, u64); - reg_op!(engine, "<<", left_shift, i32, i64, u32, u64); - reg_op!(engine, ">>", right_shift, i32, i64, u32, u64); - reg_op!(engine, "%", modulo, i32, i64, u32, u64); - engine.register_fn("~", pow_i64_i64); - engine.register_fn("~", pow_f64_f64); - engine.register_fn("~", pow_f64_i64); - - reg_un!(engine, "-", neg, i32, i64, f32, f64); - reg_un!(engine, "!", not, bool); - - engine.register_fn("+", concat); - engine.register_fn("==", unit_eq); - - // engine.register_fn("[]", idx); - // FIXME? Registering array lookups are a special case because we want to return boxes - // directly let ent = engine.fns.entry("[]".to_string()).or_insert_with(Vec::new); - // (*ent).push(FnType::ExternalFn2(Box::new(idx))); - - // Register conversion functions - engine.register_fn("to_float", |x: i32| x as f64); - engine.register_fn("to_float", |x: u32| x as f64); - engine.register_fn("to_float", |x: i64| x as f64); - engine.register_fn("to_float", |x: u64| x as f64); - engine.register_fn("to_float", |x: f32| x as f64); - - engine.register_fn("to_int", |x: i32| x as i64); - engine.register_fn("to_int", |x: u32| x as i64); - engine.register_fn("to_int", |x: u64| x as i64); - engine.register_fn("to_int", |x: f32| x as i64); - engine.register_fn("to_int", |x: f64| x as i64); - engine.register_fn("to_int", |ch: char| ch as i64); - - // Register print and debug - fn print_debug(x: T) -> String { - format!("{:?}", x) - } - fn print(x: T) -> String { - format!("{}", x) - } - - reg_func1!(engine, "print", print, String, i32, i64, u32, u64); - reg_func1!(engine, "print", print, String, f32, f64, bool, char, String); - reg_func1!(engine, "print", print_debug, String, Array); - engine.register_fn("print", |_: ()| println!()); - - reg_func1!(engine, "debug", print_debug, String, i32, i64, u32, u64); - reg_func1!(engine, "debug", print_debug, String, f32, f64, bool, char); - reg_func1!(engine, "debug", print_debug, String, String, Array, ()); - - // Register array utility functions - fn push(list: &mut Array, item: T) { - list.push(Box::new(item)); - } - fn pad(list: &mut Array, len: i64, item: T) { - if len >= 0 { - while list.len() < len as usize { - push(list, item.clone()); - } - } - } - - reg_func2x!(engine, "push", push, &mut Array, (), i32, i64, u32, u64); - reg_func2x!(engine, "push", push, &mut Array, (), f32, f64, bool, char); - reg_func2x!(engine, "push", push, &mut Array, (), String, Array, ()); - reg_func3!(engine, "pad", pad, &mut Array, i64, (), i32, u32, f32); - reg_func3!(engine, "pad", pad, &mut Array, i64, (), i64, u64, f64); - reg_func3!(engine, "pad", pad, &mut Array, i64, (), bool, char); - reg_func3!(engine, "pad", pad, &mut Array, i64, (), String, Array, ()); - - engine.register_dynamic_fn("pop", |list: &mut Array| list.pop().unwrap_or(Box::new(()))); - engine.register_dynamic_fn("shift", |list: &mut Array| { - if list.len() > 0 { - list.remove(0) - } else { - Box::new(()) - } - }); - engine.register_fn("len", |list: &mut Array| -> i64 { list.len() as i64 }); - engine.register_fn("truncate", |list: &mut Array, len: i64| { - if len >= 0 { - list.truncate(len as usize); - } - }); - - // Register string concatenate functions - fn prepend(x: T, y: String) -> String { - format!("{}{}", x, y) - } - fn append(x: String, y: T) -> String { - format!("{}{}", x, y) - } - - reg_func2x!(engine, "+", append, String, String, i32, i64, u32, u64, f32, f64, bool, char); - engine.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y)); - engine.register_fn("+", |x: String, _: ()| format!("{}", x)); - - reg_func2y!(engine, "+", prepend, String, String, i32, i64, u32, u64, f32, f64, bool, char); - engine.register_fn("+", |x: Array, y: String| format!("{:?}{}", x, y)); - engine.register_fn("+", |_: (), y: String| format!("{}", y)); - - // Register string utility functions - engine.register_fn("len", |s: &mut String| -> i64 { s.chars().count() as i64 }); - engine.register_fn("truncate", |s: &mut String, len: i64| { - if len >= 0 { - s.truncate(len as usize); - } - }); - engine.register_fn("pad", |s: &mut String, len: i64, ch: char| { - let gap = s.chars().count() - len as usize; - - for _ in 0..gap { - s.push(ch); - } - }); - engine.register_fn( - "replace", - |s: &mut String, pattern: String, replace: String| { - let new_str = s.replace(&pattern, &replace); - s.truncate(0); - s.push_str(&new_str); - }, - ); - - // Register array iterator - engine.register_iterator::(|a| { - Box::new(a.downcast_ref::().unwrap().clone().into_iter()) - }); - - // Register range function - use std::ops::Range; - engine.register_iterator::, _>(|a| { - Box::new( - a.downcast_ref::>() - .unwrap() - .clone() - .map(|n| Box::new(n) as Dynamic), - ) - }); - - engine.register_fn("range", |i1: i64, i2: i64| (i1..i2)); - } - /// Make a new engine pub fn new() -> Engine { let mut engine = Engine { @@ -1313,7 +1021,7 @@ impl Engine { on_debug: Box::new(|x: &str| println!("{}", x)), }; - Engine::register_default_lib(&mut engine); + engine.register_builtins(); engine } diff --git a/src/lib.rs b/src/lib.rs index c9302bed..443b8a1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,7 @@ macro_rules! debug_println { } mod any; +mod builtin; mod call; mod engine; mod fn_register;