Implement string functions with to_string/to_debug.
This commit is contained in:
parent
1866331e7b
commit
a738f750f9
@ -141,9 +141,12 @@ fn main() {
|
|||||||
engine.set_optimization_level(rhai::OptimizationLevel::None);
|
engine.set_optimization_level(rhai::OptimizationLevel::None);
|
||||||
|
|
||||||
// Set a file module resolver without caching
|
// Set a file module resolver without caching
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
{
|
||||||
let mut resolver = FileModuleResolver::new();
|
let mut resolver = FileModuleResolver::new();
|
||||||
resolver.enable_cache(false);
|
resolver.enable_cache(false);
|
||||||
engine.set_module_resolver(resolver);
|
engine.set_module_resolver(resolver);
|
||||||
|
}
|
||||||
|
|
||||||
// Make Engine immutable
|
// Make Engine immutable
|
||||||
let engine = engine;
|
let engine = engine;
|
||||||
|
@ -712,12 +712,12 @@ pub struct Engine {
|
|||||||
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
||||||
|
|
||||||
/// A map mapping type names to pretty-print names.
|
/// A map mapping type names to pretty-print names.
|
||||||
pub(crate) type_names: BTreeMap<String, String>,
|
pub(crate) type_names: BTreeMap<Identifier, Identifier>,
|
||||||
|
|
||||||
/// A set of symbols to disable.
|
/// A set of symbols to disable.
|
||||||
pub(crate) disabled_symbols: BTreeSet<String>,
|
pub(crate) disabled_symbols: BTreeSet<Identifier>,
|
||||||
/// A map containing custom keywords and precedence to recognize.
|
/// A map containing custom keywords and precedence to recognize.
|
||||||
pub(crate) custom_keywords: BTreeMap<String, Option<Precedence>>,
|
pub(crate) custom_keywords: BTreeMap<Identifier, Option<Precedence>>,
|
||||||
/// Custom syntax.
|
/// Custom syntax.
|
||||||
pub(crate) custom_syntax: BTreeMap<Identifier, CustomSyntax>,
|
pub(crate) custom_syntax: BTreeMap<Identifier, CustomSyntax>,
|
||||||
/// Callback closure for resolving variable access.
|
/// Callback closure for resolving variable access.
|
||||||
@ -2653,7 +2653,7 @@ impl Engine {
|
|||||||
pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
||||||
self.type_names
|
self.type_names
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(String::as_str)
|
.map(|s| s.as_str())
|
||||||
.unwrap_or_else(|| map_std_type_name(name))
|
.unwrap_or_else(|| map_std_type_name(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Configuration settings for [`Engine`].
|
//! Configuration settings for [`Engine`].
|
||||||
|
|
||||||
use crate::engine::Precedence;
|
|
||||||
use crate::stdlib::{format, string::String};
|
use crate::stdlib::{format, string::String};
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::Engine;
|
use crate::Engine;
|
||||||
|
use crate::{engine::Precedence, Identifier};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use crate::stdlib::num::{NonZeroU64, NonZeroUsize};
|
use crate::stdlib::num::{NonZeroU64, NonZeroUsize};
|
||||||
@ -236,7 +236,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn disable_symbol(&mut self, symbol: impl Into<String>) -> &mut Self {
|
pub fn disable_symbol(&mut self, symbol: impl Into<Identifier>) -> &mut Self {
|
||||||
self.disabled_symbols.insert(symbol.into());
|
self.disabled_symbols.insert(symbol.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ impl Engine {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn register_custom_operator(
|
pub fn register_custom_operator(
|
||||||
&mut self,
|
&mut self,
|
||||||
keyword: impl AsRef<str> + Into<String>,
|
keyword: impl AsRef<str> + Into<Identifier>,
|
||||||
precedence: u8,
|
precedence: u8,
|
||||||
) -> Result<&mut Self, String> {
|
) -> Result<&mut Self, String> {
|
||||||
let precedence = Precedence::new(precedence);
|
let precedence = Precedence::new(precedence);
|
||||||
|
@ -3,9 +3,8 @@ use crate::stdlib::{
|
|||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
io::Error as IoError,
|
io::Error as IoError,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
string::String,
|
|
||||||
};
|
};
|
||||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
use crate::{Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Shared};
|
||||||
|
|
||||||
pub const RHAI_SCRIPT_EXTENSION: &str = "rhai";
|
pub const RHAI_SCRIPT_EXTENSION: &str = "rhai";
|
||||||
|
|
||||||
@ -42,7 +41,7 @@ pub const RHAI_SCRIPT_EXTENSION: &str = "rhai";
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileModuleResolver {
|
pub struct FileModuleResolver {
|
||||||
base_path: Option<PathBuf>,
|
base_path: Option<PathBuf>,
|
||||||
extension: String,
|
extension: Identifier,
|
||||||
cache_enabled: bool,
|
cache_enabled: bool,
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
@ -118,7 +117,7 @@ impl FileModuleResolver {
|
|||||||
/// engine.set_module_resolver(resolver);
|
/// engine.set_module_resolver(resolver);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_with_extension(extension: impl Into<String>) -> Self {
|
pub fn new_with_extension(extension: impl Into<Identifier>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_path: None,
|
base_path: None,
|
||||||
extension: extension.into(),
|
extension: extension.into(),
|
||||||
@ -145,7 +144,7 @@ impl FileModuleResolver {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_with_path_and_extension(
|
pub fn new_with_path_and_extension(
|
||||||
path: impl Into<PathBuf>,
|
path: impl Into<PathBuf>,
|
||||||
extension: impl Into<String>,
|
extension: impl Into<Identifier>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
base_path: Some(path.into()),
|
base_path: Some(path.into()),
|
||||||
@ -175,7 +174,7 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
/// Set the script file extension.
|
/// Set the script file extension.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_extension(&mut self, extension: impl Into<String>) -> &mut Self {
|
pub fn set_extension(&mut self, extension: impl Into<Identifier>) -> &mut Self {
|
||||||
self.extension = extension.into();
|
self.extension = extension.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -256,7 +255,7 @@ impl FileModuleResolver {
|
|||||||
file_path = path.into();
|
file_path = path.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
file_path.set_extension(&self.extension); // Force extension
|
file_path.set_extension(self.extension.as_str()); // Force extension
|
||||||
file_path
|
file_path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::stdlib::{boxed::Box, collections::BTreeMap, ops::AddAssign, string::String};
|
use crate::stdlib::{boxed::Box, collections::BTreeMap, ops::AddAssign, string::String};
|
||||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
use crate::{Engine, EvalAltResult, Identifier, Module, ModuleResolver, Position, Shared};
|
||||||
|
|
||||||
/// A static [module][Module] resolution service that serves [modules][Module] added into it.
|
/// A static [module][Module] resolution service that serves [modules][Module] added into it.
|
||||||
///
|
///
|
||||||
@ -19,7 +19,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
|||||||
/// engine.set_module_resolver(resolver);
|
/// engine.set_module_resolver(resolver);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct StaticModuleResolver(BTreeMap<String, Shared<Module>>);
|
pub struct StaticModuleResolver(BTreeMap<Identifier, Shared<Module>>);
|
||||||
|
|
||||||
impl StaticModuleResolver {
|
impl StaticModuleResolver {
|
||||||
/// Create a new [`StaticModuleResolver`].
|
/// Create a new [`StaticModuleResolver`].
|
||||||
@ -44,7 +44,7 @@ impl StaticModuleResolver {
|
|||||||
}
|
}
|
||||||
/// Add a [module][Module] keyed by its path.
|
/// Add a [module][Module] keyed by its path.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn insert(&mut self, path: impl Into<String>, mut module: Module) {
|
pub fn insert(&mut self, path: impl Into<Identifier>, mut module: Module) {
|
||||||
module.build_index();
|
module.build_index();
|
||||||
self.0.insert(path.into(), module.into());
|
self.0.insert(path.into(), module.into());
|
||||||
}
|
}
|
||||||
@ -70,13 +70,13 @@ impl StaticModuleResolver {
|
|||||||
}
|
}
|
||||||
/// Get a mutable iterator of all the modules.
|
/// Get a mutable iterator of all the modules.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_iter(self) -> impl Iterator<Item = (String, Shared<Module>)> {
|
pub fn into_iter(self) -> impl Iterator<Item = (Identifier, Shared<Module>)> {
|
||||||
self.0.into_iter()
|
self.0.into_iter()
|
||||||
}
|
}
|
||||||
/// Get an iterator of all the [module][Module] paths.
|
/// Get an iterator of all the [module][Module] paths.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn paths(&self) -> impl Iterator<Item = &str> {
|
pub fn paths(&self) -> impl Iterator<Item = &str> {
|
||||||
self.0.keys().map(String::as_str)
|
self.0.keys().map(|s| s.as_str())
|
||||||
}
|
}
|
||||||
/// Get an iterator of all the [modules][Module].
|
/// Get an iterator of all the [modules][Module].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -10,8 +10,8 @@ use crate::Array;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
pub const FUNC_TO_STRING: &'static str = "to_string";
|
||||||
const FUNC_TO_DEBUG: &'static str = "to_debug";
|
pub const FUNC_TO_DEBUG: &'static str = "to_debug";
|
||||||
|
|
||||||
def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, {
|
def_package!(crate:BasicStringPackage:"Basic string utilities, including printing.", lib, {
|
||||||
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
||||||
@ -19,9 +19,8 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin
|
|||||||
|
|
||||||
// Register print and debug
|
// Register print and debug
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn print_with_func(
|
pub fn print_with_func(
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
ctx: &NativeCallContext,
|
ctx: &NativeCallContext,
|
||||||
value: &mut Dynamic,
|
value: &mut Dynamic,
|
||||||
@ -39,17 +38,25 @@ fn print_with_func(
|
|||||||
mod print_debug_functions {
|
mod print_debug_functions {
|
||||||
use crate::ImmutableString;
|
use crate::ImmutableString;
|
||||||
|
|
||||||
#[rhai_fn(name = "print", name = "to_string", pure)]
|
#[rhai_fn(name = "print", pure)]
|
||||||
pub fn print_generic(item: &mut Dynamic) -> ImmutableString {
|
pub fn print_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
item.to_string().into()
|
print_with_func(FUNC_TO_STRING, &ctx, item)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "debug", name = "to_debug", pure)]
|
#[rhai_fn(name = "to_string", pure)]
|
||||||
pub fn debug_generic(item: &mut Dynamic) -> ImmutableString {
|
pub fn to_string_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
format!("{:?}", item).into()
|
ctx.engine().map_type_name(&item.to_string()).into()
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "debug", pure)]
|
||||||
|
pub fn debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
|
print_with_func(FUNC_TO_DEBUG, &ctx, item)
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "to_debug", pure)]
|
||||||
|
pub fn to_debug_generic(ctx: NativeCallContext, item: &mut Dynamic) -> ImmutableString {
|
||||||
|
ctx.engine().map_type_name(&format!("{:?}", item)).into()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "print", name = "debug")]
|
#[rhai_fn(name = "print", name = "debug")]
|
||||||
pub fn print_empty_string() -> ImmutableString {
|
pub fn print_empty_string() -> ImmutableString {
|
||||||
"".to_string().into()
|
Default::default()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "print", name = "to_string")]
|
#[rhai_fn(name = "print", name = "to_string")]
|
||||||
pub fn print_string(s: ImmutableString) -> ImmutableString {
|
pub fn print_string(s: ImmutableString) -> ImmutableString {
|
||||||
|
@ -6,6 +6,8 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
use crate::{def_package, Dynamic, ImmutableString, StaticVec, INT};
|
use crate::{def_package, Dynamic, ImmutableString, StaticVec, INT};
|
||||||
|
|
||||||
|
use super::string_basic::{print_with_func, FUNC_TO_STRING};
|
||||||
|
|
||||||
def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
|
def_package!(crate:MoreStringPackage:"Additional string utilities, including string building.", lib, {
|
||||||
combine_with_exported_module!(lib, "string", string_functions);
|
combine_with_exported_module!(lib, "string", string_functions);
|
||||||
|
|
||||||
@ -21,22 +23,30 @@ mod string_functions {
|
|||||||
use crate::ImmutableString;
|
use crate::ImmutableString;
|
||||||
|
|
||||||
#[rhai_fn(name = "+", name = "append")]
|
#[rhai_fn(name = "+", name = "append")]
|
||||||
pub fn add_append(string: &str, item: Dynamic) -> ImmutableString {
|
pub fn add_append(ctx: NativeCallContext, string: &str, mut item: Dynamic) -> ImmutableString {
|
||||||
format!("{}{}", string, item).into()
|
let s = print_with_func(FUNC_TO_STRING, &ctx, &mut item);
|
||||||
|
format!("{}{}", string, s).into()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+", pure)]
|
#[rhai_fn(name = "+", pure)]
|
||||||
pub fn add_prepend(item: &mut Dynamic, string: &str) -> ImmutableString {
|
pub fn add_prepend(
|
||||||
format!("{}{}", item, string).into()
|
ctx: NativeCallContext,
|
||||||
|
item: &mut Dynamic,
|
||||||
|
string: &str,
|
||||||
|
) -> ImmutableString {
|
||||||
|
let s = print_with_func(FUNC_TO_STRING, &ctx, item);
|
||||||
|
format!("{}{}", s, string).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_append_unit(string: ImmutableString, _x: ()) -> ImmutableString {
|
pub fn add_append_unit(string: ImmutableString, _item: ()) -> ImmutableString {
|
||||||
string
|
string
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_prepend_unit(_x: (), string: ImmutableString) -> ImmutableString {
|
pub fn add_prepend_unit(_item: (), string: ImmutableString) -> ImmutableString {
|
||||||
string
|
string
|
||||||
}
|
}
|
||||||
|
#[rhai_fn(name = "+=")]
|
||||||
|
pub fn add_append_assign_unit(_string: &mut ImmutableString, _item: ()) {}
|
||||||
|
|
||||||
#[rhai_fn(name = "len", get = "len")]
|
#[rhai_fn(name = "len", get = "len")]
|
||||||
pub fn len(string: &str) -> INT {
|
pub fn len(string: &str) -> INT {
|
||||||
|
@ -1621,7 +1621,7 @@ fn parse_binary_op(
|
|||||||
Token::Custom(c) => state
|
Token::Custom(c) => state
|
||||||
.engine
|
.engine
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c.as_str())
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or_else(|| PERR::Reserved(c.clone()).into_err(*current_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.clone()).into_err(*current_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
@ -1646,7 +1646,7 @@ fn parse_binary_op(
|
|||||||
Token::Custom(c) => state
|
Token::Custom(c) => state
|
||||||
.engine
|
.engine
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(c.as_str())
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or_else(|| PERR::Reserved(c.clone()).into_err(*next_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.clone()).into_err(*next_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
@ -1753,7 +1753,7 @@ fn parse_binary_op(
|
|||||||
if state
|
if state
|
||||||
.engine
|
.engine
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(&s)
|
.get(s.as_str())
|
||||||
.map_or(false, Option::is_some) =>
|
.map_or(false, Option::is_some) =>
|
||||||
{
|
{
|
||||||
let hash = calc_fn_hash(empty(), &s, 2);
|
let hash = calc_fn_hash(empty(), &s, 2);
|
||||||
|
@ -1828,7 +1828,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
None => return None,
|
None => return None,
|
||||||
// Reserved keyword/symbol
|
// Reserved keyword/symbol
|
||||||
Some((Token::Reserved(s), pos)) => (match
|
Some((Token::Reserved(s), pos)) => (match
|
||||||
(s.as_str(), self.engine.custom_keywords.contains_key(&s))
|
(s.as_str(), self.engine.custom_keywords.contains_key(s.as_str()))
|
||||||
{
|
{
|
||||||
("===", false) => Token::LexError(LERR::ImproperSymbol(s,
|
("===", false) => Token::LexError(LERR::ImproperSymbol(s,
|
||||||
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
|
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?".to_string(),
|
||||||
@ -1869,7 +1869,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
(_, false) => Token::Reserved(s),
|
(_, false) => Token::Reserved(s),
|
||||||
}, pos),
|
}, pos),
|
||||||
// Custom keyword
|
// Custom keyword
|
||||||
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.contains_key(&s) => {
|
Some((Token::Identifier(s), pos)) if self.engine.custom_keywords.contains_key(s.as_str()) => {
|
||||||
(Token::Custom(s), pos)
|
(Token::Custom(s), pos)
|
||||||
}
|
}
|
||||||
// Custom standard keyword/symbol - must be disabled
|
// Custom standard keyword/symbol - must be disabled
|
||||||
|
@ -222,6 +222,40 @@ fn test_string_substring() -> Result<(), Box<EvalAltResult>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_format() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
struct TestStruct {
|
||||||
|
field: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine
|
||||||
|
.register_type_with_name::<TestStruct>("TestStruct")
|
||||||
|
.register_fn("new_ts", || TestStruct { field: 42 })
|
||||||
|
.register_fn("to_string", |ts: TestStruct| format!("TS={}", ts.field))
|
||||||
|
.register_fn("to_debug", |ts: TestStruct| {
|
||||||
|
format!("!!!TS={}!!!", ts.field)
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(r#"let x = new_ts(); "foo" + x"#)?,
|
||||||
|
"fooTS=42"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(r#"let x = new_ts(); x + "foo""#)?,
|
||||||
|
"TS=42foo"
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(r#"let x = [new_ts()]; "foo" + x"#)?,
|
||||||
|
"foo[!!!TS=42!!!]"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string_fn() -> Result<(), Box<EvalAltResult>> {
|
fn test_string_fn() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user