Fix no_std build.
This commit is contained in:
parent
a306979a9c
commit
b6d839c8a9
@ -21,7 +21,7 @@ num-traits = { version = "0.2.11", default-features = false }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
#default = ["no_stdlib", "no_function", "no_index", "no_object", "no_float", "only_i32", "unchecked", "no_optimize", "sync"]
|
#default = ["no_stdlib", "no_function", "no_index", "no_object", "no_float", "only_i32", "unchecked", "no_optimize", "sync"]
|
||||||
default = []
|
default = ["no_std"]
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
no_index = [] # no arrays and indexing
|
no_index = [] # no arrays and indexing
|
||||||
no_float = [] # no floating-point
|
no_float = [] # no floating-point
|
||||||
@ -33,7 +33,7 @@ only_i64 = [] # set INT=i64 (default) and disable support for all other in
|
|||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
|
|
||||||
# compiling for no-std
|
# compiling for no-std
|
||||||
no_std = [ "num-traits/libm", "hashbrown", "core-error", "libm" ]
|
no_std = [ "num-traits/libm", "hashbrown", "core-error", "libm", "ahash" ]
|
||||||
|
|
||||||
# other developer features
|
# other developer features
|
||||||
no_stdlib = [] # do not register the standard library
|
no_stdlib = [] # do not register the standard library
|
||||||
@ -63,4 +63,5 @@ optional = true
|
|||||||
[dependencies.ahash]
|
[dependencies.ahash]
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
features = ["compile-time-rng"]
|
||||||
optional = true
|
optional = true
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
use rhai::{Engine, EvalAltResult, INT};
|
use rhai::{Engine, EvalAltResult, INT};
|
||||||
|
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<EvalAltResult>> {
|
fn main() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ use crate::stdlib::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
string::String,
|
string::String,
|
||||||
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
@ -923,10 +923,15 @@ impl Engine {
|
|||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
let mut arg_values = args.into_vec();
|
let mut arg_values = args.into_vec();
|
||||||
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
let mut args: Vec<_> = arg_values.iter_mut().collect();
|
||||||
let fn_lib = Some(ast.1.as_ref());
|
let fn_lib = ast.1.as_ref();
|
||||||
let pos = Position::none();
|
let pos = Position::none();
|
||||||
|
|
||||||
let result = self.call_fn_raw(Some(scope), fn_lib, name, &mut args, None, pos, 0)?;
|
let fn_def = fn_lib
|
||||||
|
.get_function(name, args.len())
|
||||||
|
.ok_or_else(|| Box::new(EvalAltResult::ErrorFunctionNotFound(name.to_string(), pos)))?;
|
||||||
|
|
||||||
|
let result =
|
||||||
|
self.call_fn_from_lib(Some(scope), Some(&fn_lib), fn_def, &mut args, pos, 0)?;
|
||||||
|
|
||||||
let return_type = self.map_type_name(result.type_name());
|
let return_type = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
|
246
src/engine.rs
246
src/engine.rs
@ -13,7 +13,7 @@ use crate::token::Position;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{hash_map::DefaultHasher, HashMap},
|
collections::HashMap,
|
||||||
format,
|
format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::once,
|
iter::once,
|
||||||
@ -24,6 +24,12 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
|
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||||
|
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
use ahash::AHasher;
|
||||||
|
|
||||||
/// An dynamic array of `Dynamic` values.
|
/// An dynamic array of `Dynamic` values.
|
||||||
///
|
///
|
||||||
/// Not available under the `no_index` feature.
|
/// Not available under the `no_index` feature.
|
||||||
@ -347,17 +353,25 @@ fn extract_prop_from_setter(fn_name: &str) -> Option<&str> {
|
|||||||
/// Parameter types are passed in via `TypeId` values from an iterator
|
/// Parameter types are passed in via `TypeId` values from an iterator
|
||||||
/// which can come from any source.
|
/// which can come from any source.
|
||||||
pub fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>) -> u64 {
|
pub fn calc_fn_spec(fn_name: &str, params: impl Iterator<Item = TypeId>) -> u64 {
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
let mut s: AHasher = Default::default();
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
let mut s = DefaultHasher::new();
|
let mut s = DefaultHasher::new();
|
||||||
fn_name.hash(&mut s);
|
|
||||||
|
s.write(fn_name.as_bytes());
|
||||||
params.for_each(|t| t.hash(&mut s));
|
params.for_each(|t| t.hash(&mut s));
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate a `u64` hash key from a function name and number of parameters (without regard to types).
|
/// Calculate a `u64` hash key from a function name and number of parameters (without regard to types).
|
||||||
pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 {
|
pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 {
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
let mut s: AHasher = Default::default();
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
let mut s = DefaultHasher::new();
|
let mut s = DefaultHasher::new();
|
||||||
fn_name.hash(&mut s);
|
|
||||||
params.hash(&mut s);
|
s.write(fn_name.as_bytes());
|
||||||
|
s.write_usize(params);
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,67 +543,7 @@ impl Engine {
|
|||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search in script-defined functions (can override built-in)
|
||||||
if let Some(fn_def) = fn_lib.and_then(|lib| lib.get_function(fn_name, args.len())) {
|
if let Some(fn_def) = fn_lib.and_then(|lib| lib.get_function(fn_name, args.len())) {
|
||||||
match scope {
|
return self.call_fn_from_lib(scope, fn_lib, fn_def, args, pos, level);
|
||||||
// Extern scope passed in which is not empty
|
|
||||||
Some(scope) if scope.len() > 0 => {
|
|
||||||
let scope_len = scope.len();
|
|
||||||
|
|
||||||
scope.extend(
|
|
||||||
// Put arguments into scope as variables - variable name is copied
|
|
||||||
// TODO - avoid copying variable name
|
|
||||||
fn_def
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.zip(args.into_iter().map(|v| v.clone()))
|
|
||||||
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Evaluate the function at one higher level of call depth
|
|
||||||
let result = self
|
|
||||||
.eval_stmt(scope, fn_lib, &fn_def.body, level + 1)
|
|
||||||
.or_else(|err| match *err {
|
|
||||||
// Convert return statement to return value
|
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
|
||||||
err => Err(Box::new(err.set_position(pos))),
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.rewind(scope_len);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
// No new scope - create internal scope
|
|
||||||
_ => {
|
|
||||||
let mut scope = Scope::new();
|
|
||||||
|
|
||||||
scope.extend(
|
|
||||||
// Put arguments into scope as variables
|
|
||||||
fn_def
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.zip(args.into_iter().map(|v| v.clone()))
|
|
||||||
.map(|(name, value)| (name, ScopeEntryType::Normal, value)),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Evaluate the function at one higher level of call depth
|
|
||||||
return self
|
|
||||||
.eval_stmt(&mut scope, fn_lib, &fn_def.body, level + 1)
|
|
||||||
.or_else(|err| match *err {
|
|
||||||
// Convert return statement to return value
|
|
||||||
EvalAltResult::Return(x, _) => Ok(x),
|
|
||||||
err => Err(Box::new(err.set_position(pos))),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Argument must be a string
|
|
||||||
fn cast_to_string(r: &Dynamic, pos: Position) -> Result<&str, Box<EvalAltResult>> {
|
|
||||||
r.as_str().map_err(|type_name| {
|
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
type_name.into(),
|
|
||||||
pos,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
@ -607,10 +561,22 @@ impl Engine {
|
|||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT if self.on_print.is_some() => {
|
KEYWORD_PRINT if self.on_print.is_some() => {
|
||||||
self.on_print.as_ref().unwrap()(cast_to_string(&result, pos)?).into()
|
self.on_print.as_ref().unwrap()(result.as_str().map_err(|type_name| {
|
||||||
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
type_name.into(),
|
||||||
|
pos,
|
||||||
|
))
|
||||||
|
})?)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
KEYWORD_DEBUG if self.on_debug.is_some() => {
|
KEYWORD_DEBUG if self.on_debug.is_some() => {
|
||||||
self.on_debug.as_ref().unwrap()(cast_to_string(&result, pos)?).into()
|
self.on_debug.as_ref().unwrap()(result.as_str().map_err(|type_name| {
|
||||||
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
type_name.into(),
|
||||||
|
pos,
|
||||||
|
))
|
||||||
|
})?)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
KEYWORD_PRINT | KEYWORD_DEBUG => ().into(),
|
KEYWORD_PRINT | KEYWORD_DEBUG => ().into(),
|
||||||
_ => result,
|
_ => result,
|
||||||
@ -651,6 +617,69 @@ impl Engine {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call a script-defined function.
|
||||||
|
pub(crate) fn call_fn_from_lib(
|
||||||
|
&self,
|
||||||
|
scope: Option<&mut Scope>,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
|
fn_def: &FnDef,
|
||||||
|
args: &mut FnCallArgs,
|
||||||
|
pos: Position,
|
||||||
|
level: usize,
|
||||||
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
match scope {
|
||||||
|
// Extern scope passed in which is not empty
|
||||||
|
Some(scope) if scope.len() > 0 => {
|
||||||
|
let scope_len = scope.len();
|
||||||
|
|
||||||
|
scope.extend(
|
||||||
|
// Put arguments into scope as variables - variable name is copied
|
||||||
|
// TODO - avoid copying variable name
|
||||||
|
fn_def
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.zip(args.into_iter().map(|v| v.clone()))
|
||||||
|
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Evaluate the function at one higher level of call depth
|
||||||
|
let result = self
|
||||||
|
.eval_stmt(scope, fn_lib, &fn_def.body, level + 1)
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
// Convert return statement to return value
|
||||||
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
|
_ => Err(EvalAltResult::set_position(err, pos)),
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.rewind(scope_len);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// No new scope - create internal scope
|
||||||
|
_ => {
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
|
scope.extend(
|
||||||
|
// Put arguments into scope as variables
|
||||||
|
fn_def
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.zip(args.into_iter().map(|v| v.clone()))
|
||||||
|
.map(|(name, value)| (name, ScopeEntryType::Normal, value)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Evaluate the function at one higher level of call depth
|
||||||
|
return self
|
||||||
|
.eval_stmt(&mut scope, fn_lib, &fn_def.body, level + 1)
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
// Convert return statement to return value
|
||||||
|
EvalAltResult::Return(x, _) => Ok(x),
|
||||||
|
_ => Err(EvalAltResult::set_position(err, pos)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Has a system function an override?
|
// Has a system function an override?
|
||||||
fn has_override(&self, fn_lib: Option<&FunctionsLib>, name: &str) -> bool {
|
fn has_override(&self, fn_lib: Option<&FunctionsLib>, name: &str) -> bool {
|
||||||
let hash = &calc_fn_hash(name, once(TypeId::of::<String>()));
|
let hash = &calc_fn_hash(name, once(TypeId::of::<String>()));
|
||||||
@ -712,6 +741,49 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluate a text string as a script - used primarily for 'eval'.
|
||||||
|
fn eval_script_expr(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
fn_lib: Option<&FunctionsLib>,
|
||||||
|
script: &Dynamic,
|
||||||
|
pos: Position,
|
||||||
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
|
let script = script
|
||||||
|
.as_str()
|
||||||
|
.map_err(|type_name| EvalAltResult::ErrorMismatchOutputType(type_name.into(), pos))?;
|
||||||
|
|
||||||
|
// Compile the script text
|
||||||
|
// No optimizations because we only run it once
|
||||||
|
let mut ast = self.compile_with_scope_and_optimization_level(
|
||||||
|
&Scope::new(),
|
||||||
|
script,
|
||||||
|
OptimizationLevel::None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// If new functions are defined within the eval string, it is an error
|
||||||
|
if ast.1.len() > 0 {
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorParsing(
|
||||||
|
ParseErrorType::WrongFnDefinition.into_err(pos),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(lib) = fn_lib {
|
||||||
|
#[cfg(feature = "sync")]
|
||||||
|
{
|
||||||
|
ast.1 = Arc::new(lib.clone());
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "sync"))]
|
||||||
|
{
|
||||||
|
ast.1 = Rc::new(lib.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the AST
|
||||||
|
self.eval_ast_with_scope_raw(scope, &ast)
|
||||||
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
|
}
|
||||||
|
|
||||||
/// Chain-evaluate a dot setter.
|
/// Chain-evaluate a dot setter.
|
||||||
fn dot_get_helper(
|
fn dot_get_helper(
|
||||||
&self,
|
&self,
|
||||||
@ -1392,44 +1464,8 @@ impl Engine {
|
|||||||
&& args.len() == 1
|
&& args.len() == 1
|
||||||
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
||||||
{
|
{
|
||||||
// Get the script text by evaluating the expression
|
// Evaluate the text string as a script
|
||||||
let script = args[0].as_str().map_err(|type_name| {
|
return self.eval_script_expr(scope, fn_lib, args[0], arg_exprs[0].position());
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
type_name.into(),
|
|
||||||
arg_exprs[0].position(),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Compile the script text
|
|
||||||
// No optimizations because we only run it once
|
|
||||||
let mut ast = self.compile_with_scope_and_optimization_level(
|
|
||||||
&Scope::new(),
|
|
||||||
script,
|
|
||||||
OptimizationLevel::None,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// If new functions are defined within the eval string, it is an error
|
|
||||||
if ast.1.len() > 0 {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorParsing(
|
|
||||||
ParseErrorType::WrongFnDefinition.into_err(*pos),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(lib) = fn_lib {
|
|
||||||
#[cfg(feature = "sync")]
|
|
||||||
{
|
|
||||||
ast.1 = Arc::new(lib.clone());
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "sync"))]
|
|
||||||
{
|
|
||||||
ast.1 = Rc::new(lib.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate the AST
|
|
||||||
return self
|
|
||||||
.eval_ast_with_scope_raw(scope, &ast)
|
|
||||||
.map_err(|err| Box::new(err.set_position(*pos)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal function call
|
// Normal function call
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
use crate::stdlib::{char, error::Error, fmt, string::String};
|
use crate::stdlib::{boxed::Box, char, error::Error, fmt, string::String};
|
||||||
|
|
||||||
/// Error when tokenizing the script text.
|
/// Error when tokenizing the script text.
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
|
||||||
|
@ -187,7 +187,7 @@ pub fn map_result<T: Variant + Clone>(
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
data.map(|v| v.into_dynamic())
|
data.map(|v| v.into_dynamic())
|
||||||
.map_err(|err| Box::new(err.set_position(pos)))
|
.map_err(|err| EvalAltResult::set_position(err, pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! def_register {
|
macro_rules! def_register {
|
||||||
|
@ -15,6 +15,7 @@ use num_traits::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
|
boxed::Box,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
format,
|
format,
|
||||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
|
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub},
|
||||||
|
@ -6,7 +6,7 @@ use crate::engine::Array;
|
|||||||
use crate::fn_register::{map_dynamic as map, map_identity as pass};
|
use crate::fn_register::{map_dynamic as map, map_identity as pass};
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::any::TypeId;
|
use crate::stdlib::{any::TypeId, boxed::Box, string::String};
|
||||||
|
|
||||||
// Register array utility functions
|
// Register array utility functions
|
||||||
fn push<T: Variant + Clone>(list: &mut Array, item: T) {
|
fn push<T: Variant + Clone>(list: &mut Array, item: T) {
|
||||||
|
@ -8,6 +8,7 @@ use crate::parser::INT;
|
|||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
|
boxed::Box,
|
||||||
ops::{Add, Range},
|
ops::{Add, Range},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ use crate::def_package;
|
|||||||
use crate::fn_register::map_dynamic as map;
|
use crate::fn_register::map_dynamic as map;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
use crate::stdlib::string::String;
|
||||||
|
|
||||||
// Comparison operators
|
// Comparison operators
|
||||||
pub fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
pub fn lt<T: PartialOrd>(x: T, y: T) -> bool {
|
||||||
x < y
|
x < y
|
||||||
|
@ -6,6 +6,11 @@ use crate::engine::Map;
|
|||||||
use crate::fn_register::map_dynamic as map;
|
use crate::fn_register::map_dynamic as map;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
|
use crate::stdlib::{
|
||||||
|
string::{String, ToString},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
fn map_get_keys(map: &mut Map) -> Vec<Dynamic> {
|
fn map_get_keys(map: &mut Map) -> Vec<Dynamic> {
|
||||||
map.iter()
|
map.iter()
|
||||||
.map(|(k, _)| k.to_string().into())
|
.map(|(k, _)| k.to_string().into())
|
||||||
|
@ -9,7 +9,7 @@ use crate::token::Position;
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
use crate::stdlib::{i32, i64};
|
use crate::stdlib::{boxed::Box, format, i32, i64};
|
||||||
|
|
||||||
#[cfg(feature = "only_i32")]
|
#[cfg(feature = "only_i32")]
|
||||||
pub const MAX_INT: INT = i32::MAX;
|
pub const MAX_INT: INT = i32::MAX;
|
||||||
|
@ -29,6 +29,7 @@ pub use pkg_core::CorePackage;
|
|||||||
pub use pkg_std::StandardPackage;
|
pub use pkg_std::StandardPackage;
|
||||||
pub use string_basic::BasicStringPackage;
|
pub use string_basic::BasicStringPackage;
|
||||||
pub use string_more::MoreStringPackage;
|
pub use string_more::MoreStringPackage;
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
pub use time_basic::BasicTimePackage;
|
pub use time_basic::BasicTimePackage;
|
||||||
|
|
||||||
pub use utils::*;
|
pub use utils::*;
|
||||||
|
@ -5,6 +5,7 @@ use super::map_basic::BasicMapPackage;
|
|||||||
use super::math_basic::BasicMathPackage;
|
use super::math_basic::BasicMathPackage;
|
||||||
use super::pkg_core::CorePackage;
|
use super::pkg_core::CorePackage;
|
||||||
use super::string_more::MoreStringPackage;
|
use super::string_more::MoreStringPackage;
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
use super::time_basic::BasicTimePackage;
|
use super::time_basic::BasicTimePackage;
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
@ -16,6 +17,7 @@ def_package!(crate:StandardPackage:"_Standard_ package containing all built-in f
|
|||||||
BasicArrayPackage::init(lib);
|
BasicArrayPackage::init(lib);
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
BasicMapPackage::init(lib);
|
BasicMapPackage::init(lib);
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
BasicTimePackage::init(lib);
|
BasicTimePackage::init(lib);
|
||||||
MoreStringPackage::init(lib);
|
MoreStringPackage::init(lib);
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,7 @@ use crate::parser::INT;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
format,
|
format,
|
||||||
|
string::{String, ToString},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register print and debug
|
// Register print and debug
|
||||||
|
@ -5,7 +5,12 @@ use crate::engine::Array;
|
|||||||
use crate::fn_register::map_dynamic as map;
|
use crate::fn_register::map_dynamic as map;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
|
||||||
use crate::stdlib::fmt::Display;
|
use crate::stdlib::{
|
||||||
|
fmt::Display,
|
||||||
|
format,
|
||||||
|
string::{String, ToString},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
fn prepend<T: Display>(x: T, y: String) -> String {
|
fn prepend<T: Display>(x: T, y: String) -> String {
|
||||||
format!("{}{}", x, y)
|
format!("{}{}", x, y)
|
||||||
|
@ -8,64 +8,63 @@ use crate::parser::INT;
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
use crate::stdlib::time::Instant;
|
use crate::stdlib::time::Instant;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, {
|
||||||
#[cfg(not(feature = "no_std"))]
|
// Register date/time functions
|
||||||
{
|
reg_none(lib, "timestamp", || Instant::now(), map);
|
||||||
// Register date/time functions
|
|
||||||
reg_none(lib, "timestamp", || Instant::now(), map);
|
|
||||||
|
|
||||||
reg_binary(
|
reg_binary(
|
||||||
lib,
|
lib,
|
||||||
"-",
|
"-",
|
||||||
|ts1: Instant, ts2: Instant| {
|
|ts1: Instant, ts2: Instant| {
|
||||||
if ts2 > ts1 {
|
if ts2 > ts1 {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Ok(-(ts2 - ts1).as_secs_f64());
|
return Ok(-(ts2 - ts1).as_secs_f64());
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
|
{
|
||||||
|
let seconds = (ts2 - ts1).as_secs();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
let seconds = (ts2 - ts1).as_secs();
|
if seconds > (MAX_INT as u64) {
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
#[cfg(not(feature = "unchecked"))]
|
format!(
|
||||||
{
|
"Integer overflow for timestamp duration: {}",
|
||||||
if seconds > (MAX_INT as u64) {
|
-(seconds as i64)
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
),
|
||||||
format!(
|
Position::none(),
|
||||||
"Integer overflow for timestamp duration: {}",
|
)));
|
||||||
-(seconds as i64)
|
|
||||||
),
|
|
||||||
Position::none(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Ok(-(seconds as INT));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
return Ok((ts1 - ts2).as_secs_f64());
|
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
{
|
|
||||||
let seconds = (ts1 - ts2).as_secs();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
{
|
|
||||||
if seconds > (MAX_INT as u64) {
|
|
||||||
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
|
||||||
format!("Integer overflow for timestamp duration: {}", seconds),
|
|
||||||
Position::none(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(seconds as INT);
|
|
||||||
}
|
}
|
||||||
|
return Ok(-(seconds as INT));
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
result,
|
#[cfg(not(feature = "no_float"))]
|
||||||
);
|
return Ok((ts1 - ts2).as_secs_f64());
|
||||||
}
|
|
||||||
|
#[cfg(feature = "no_float")]
|
||||||
|
{
|
||||||
|
let seconds = (ts1 - ts2).as_secs();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
{
|
||||||
|
if seconds > (MAX_INT as u64) {
|
||||||
|
return Err(Box::new(EvalAltResult::ErrorArithmetic(
|
||||||
|
format!("Integer overflow for timestamp duration: {}", seconds),
|
||||||
|
Position::none(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(seconds as INT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
result,
|
||||||
|
);
|
||||||
|
|
||||||
reg_binary(lib, "<", lt::<Instant>, map);
|
reg_binary(lib, "<", lt::<Instant>, map);
|
||||||
reg_binary(lib, "<=", lte::<Instant>, map);
|
reg_binary(lib, "<=", lte::<Instant>, map);
|
||||||
|
@ -6,7 +6,11 @@ use crate::engine::FnCallArgs;
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box};
|
use crate::stdlib::{
|
||||||
|
any::TypeId,
|
||||||
|
boxed::Box,
|
||||||
|
string::{String, ToString},
|
||||||
|
};
|
||||||
|
|
||||||
/// This macro makes it easy to define a _package_ and register functions into it.
|
/// This macro makes it easy to define a _package_ and register functions into it.
|
||||||
///
|
///
|
||||||
|
@ -6,6 +6,7 @@ use crate::parser::INT;
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
|
boxed::Box,
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt,
|
fmt,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -283,8 +284,8 @@ impl EvalAltResult {
|
|||||||
|
|
||||||
/// Consume the current `EvalAltResult` and return a new one
|
/// Consume the current `EvalAltResult` and return a new one
|
||||||
/// with the specified `Position`.
|
/// with the specified `Position`.
|
||||||
pub(crate) fn set_position(mut self, new_position: Position) -> Self {
|
pub(crate) fn set_position(mut err: Box<Self>, new_position: Position) -> Box<Self> {
|
||||||
match &mut self {
|
match err.as_mut() {
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Self::ErrorReadingScriptFile(_, _) => (),
|
Self::ErrorReadingScriptFile(_, _) => (),
|
||||||
|
|
||||||
@ -314,6 +315,6 @@ impl EvalAltResult {
|
|||||||
| Self::Return(_, pos) => *pos = new_position,
|
| Self::Return(_, pos) => *pos = new_position,
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user