From e2a47b2a65263433c4cb3855a1e55adabf9bc154 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 3 Jan 2021 20:54:08 +0800 Subject: [PATCH 01/12] Disallow duplicated function definitions. --- RELEASES.md | 2 ++ src/fn_call.rs | 2 +- src/parse_error.rs | 20 +++++++++++++++++--- src/parser.rs | 21 ++++++++++++++------- tests/internal_fn.rs | 22 +++++++++++++++++----- 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index d377aa7c..e43a841c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,6 +8,8 @@ Breaking changes ---------------- * The error variant `EvalAltResult::ErrorInFunctionCall` has a new parameter holding the _source_ of the function. +* `ParseErrorType::WrongFnDefinition` is renamed `FnWrongDefinition`. +* Redefining an existing function within the same script now throws a new `ParseErrorType::FnDuplicatedDefinition`. This is to prevent accidental overwriting an earlier function definition. Enhancements ------------ diff --git a/src/fn_call.rs b/src/fn_call.rs index 78879f50..21bc570c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -734,7 +734,7 @@ impl Engine { // If new functions are defined within the eval string, it is an error if ast.lib().count().0 != 0 { - return Err(ParseErrorType::WrongFnDefinition.into()); + return Err(ParseErrorType::FnWrongDefinition.into()); } // Evaluate the AST diff --git a/src/parse_error.rs b/src/parse_error.rs index 0a03726c..e42c851a 100644 --- a/src/parse_error.rs +++ b/src/parse_error.rs @@ -131,7 +131,12 @@ pub enum ParseErrorType { /// Defining a function `fn` in an appropriate place (e.g. inside another function). /// /// Never appears under the `no_function` feature. - WrongFnDefinition, + FnWrongDefinition, + /// Defining a function with a name that conflicts with an existing function. + /// Wrapped values are the function name and number of parameters. + /// + /// Never appears under the `no_object` feature. + FnDuplicatedDefinition(String, usize), /// Missing a function name after the `fn` keyword. /// /// Never appears under the `no_function` feature. @@ -180,7 +185,7 @@ impl ParseErrorType { pub(crate) fn desc(&self) -> &str { match self { Self::UnexpectedEOF => "Script is incomplete", - Self::BadInput(p) => p.desc(), + Self::BadInput(err) => err.desc(), Self::UnknownOperator(_) => "Unknown operator", Self::MissingToken(_, _) => "Expecting a certain token that is missing", Self::MalformedCallExpr(_) => "Invalid expression in function call arguments", @@ -193,12 +198,13 @@ impl ParseErrorType { Self::VariableExpected => "Expecting name of a variable", Self::Reserved(_) => "Invalid use of reserved keyword", Self::ExprExpected(_) => "Expecting an expression", + Self::FnWrongDefinition => "Function definitions must be at global level and cannot be inside a block or another function", + Self::FnDuplicatedDefinition(_, _) => "Function already exists", Self::FnMissingName => "Expecting function name in function declaration", Self::FnMissingParams(_) => "Expecting parameters in function declaration", Self::FnDuplicatedParam(_,_) => "Duplicated parameters in function declaration", Self::FnMissingBody(_) => "Expecting body statement block for function declaration", Self::WrongDocComment => "Doc-comment must be followed immediately by a function definition", - Self::WrongFnDefinition => "Function definitions must be at global level and cannot be inside a block or another function", Self::WrongExport => "Export statement can only appear at global level", Self::AssignmentToConstant(_) => "Cannot assign to a constant value", Self::AssignmentToInvalidLHS(_) => "Expression cannot be assigned to", @@ -221,6 +227,14 @@ impl fmt::Display for ParseErrorType { f.write_str(if s.is_empty() { self.desc() } else { s }) } + Self::FnDuplicatedDefinition(s, n) => { + write!(f, "Function '{}' with ", s)?; + match n { + 0 => f.write_str("no parameters already exists"), + 1 => f.write_str("1 parameter already exists"), + _ => write!(f, "{} parameters already exists", n), + } + } Self::DuplicatedProperty(s) => { write!(f, "Duplicated property '{}' for object map literal", s) } diff --git a/src/parser.rs b/src/parser.rs index 7f43e9c9..10c7945b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2585,7 +2585,7 @@ fn parse_stmt( // fn ... #[cfg(not(feature = "no_function"))] - Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(settings.pos)), + Token::Fn if !settings.is_global => Err(PERR::FnWrongDefinition.into_err(settings.pos)), #[cfg(not(feature = "no_function"))] Token::Fn | Token::Private => { @@ -2621,13 +2621,20 @@ fn parse_stmt( let func = parse_fn(input, &mut new_state, lib, access, settings, _comments)?; - lib.insert( - // Qualifiers (none) + function name + number of arguments. - calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap(), - func, - ); + // Qualifiers (none) + function name + number of arguments. + let hash = calc_script_fn_hash(empty(), &func.name, func.params.len()).unwrap(); - Ok(Stmt::Noop(settings.pos)) + if lib.contains_key(&hash) { + return Err(PERR::FnDuplicatedDefinition( + func.name.into_owned(), + func.params.len(), + ) + .into_err(pos)); + } + + lib.insert(hash, func); + + Ok(Stmt::Noop(pos)) } (_, pos) => Err(PERR::MissingToken( diff --git a/tests/internal_fn.rs b/tests/internal_fn.rs index 67417344..80d904e7 100644 --- a/tests/internal_fn.rs +++ b/tests/internal_fn.rs @@ -1,6 +1,6 @@ #![cfg(not(feature = "no_function"))] -use rhai::{Engine, EvalAltResult, INT}; +use rhai::{Engine, EvalAltResult, ParseErrorType, INT}; #[test] fn test_internal_fn() -> Result<(), Box> { @@ -46,18 +46,30 @@ fn test_internal_fn_overloading() -> Result<(), Box> { assert_eq!( engine.eval::( - r#" + r" fn abc(x,y,z) { 2*x + 3*y + 4*z + 888 } - fn abc(x) { x + 42 } fn abc(x,y) { x + 2*y + 88 } fn abc() { 42 } - fn abc(x) { x - 42 } // should override previous definition + fn abc(x) { x - 42 } abc() + abc(1) + abc(1,2) + abc(1,2,3) - "# + " )?, 1002 ); + assert_eq!( + *engine + .compile( + r" + fn abc(x) { x + 42 } + fn abc(x) { x - 42 } + " + ) + .expect_err("should error") + .0, + ParseErrorType::FnDuplicatedDefinition("abc".to_string(), 1) + ); + Ok(()) } From cf9d35166d68a5a696fc80159aceb4eaf3c6b227 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 4 Jan 2021 11:58:24 +0800 Subject: [PATCH 02/12] Remove hashing of the entire script by making Expr and Stmt Hash. --- src/ast.rs | 176 +++++++++++++++++++++++++++++++++++++--------- src/dynamic.rs | 33 +++++---- src/engine.rs | 21 +++--- src/engine_api.rs | 32 ++------- src/lib.rs | 5 +- src/parser.rs | 36 +++------- 6 files changed, 191 insertions(+), 112 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index fafc4394..06196a67 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -8,14 +8,13 @@ use crate::stdlib::{ boxed::Box, collections::HashMap, fmt, - hash::Hash, + hash::{Hash, Hasher}, num::{NonZeroU64, NonZeroUsize}, - ops::{Add, AddAssign}, + ops::{Add, AddAssign, Deref, DerefMut}, string::String, vec, vec::Vec, }; -use crate::syntax::FnCustomSyntaxEval; use crate::token::Token; use crate::utils::StraightHasherBuilder; use crate::{ @@ -492,11 +491,7 @@ impl AST { (true, true) => vec![], }; - let source = if other.source.is_some() { - other.source.clone() - } else { - self.source.clone() - }; + let source = other.source.clone().or_else(|| self.source.clone()); let mut functions = functions.as_ref().clone(); functions.merge_filtered(&other.functions, &mut filter); @@ -696,24 +691,68 @@ pub enum ReturnType { Exception, } +/// A type that wraps a [`HashMap`]`` for the `switch` statement and implements [`Hash`]. +#[derive(Clone)] +pub struct SwitchHashWrapper(HashMap); + +impl From> for SwitchHashWrapper { + fn from(value: HashMap) -> Self { + Self(value) + } +} +impl AsRef> for SwitchHashWrapper { + fn as_ref(&self) -> &HashMap { + &self.0 + } +} +impl AsMut> for SwitchHashWrapper { + fn as_mut(&mut self) -> &mut HashMap { + &mut self.0 + } +} +impl Deref for SwitchHashWrapper { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SwitchHashWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl fmt::Debug for SwitchHashWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} +impl Hash for SwitchHashWrapper { + fn hash(&self, state: &mut H) { + let mut keys: Vec<_> = self.0.keys().collect(); + keys.sort(); + + keys.into_iter().for_each(|key| { + key.hash(state); + self.0.get(&key).unwrap().hash(state); + }); + } +} + /// _(INTERNALS)_ A statement. /// Exported under the `internals` feature only. /// /// # WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub enum Stmt { /// No-op. Noop(Position), /// `if` expr `{` stmt `}` `else` `{` stmt `}` If(Expr, Box<(Stmt, Option)>, Position), /// `switch` expr `{` literal or _ `=>` stmt `,` ... `}` - Switch( - Expr, - Box<(HashMap, Option)>, - Position, - ), + Switch(Expr, Box<(SwitchHashWrapper, Option)>, Position), /// `while` expr `{` stmt `}` While(Expr, Box, Position), /// `do` `{` stmt `}` `while`|`until` expr @@ -899,10 +938,8 @@ impl Stmt { /// # WARNING /// /// This type is volatile and may change. -#[derive(Clone)] +#[derive(Clone, Hash)] pub struct CustomExpr { - /// Implementation function. - pub func: Shared, /// List of keywords. pub keywords: StaticVec, /// List of tokens actually parsed. @@ -926,7 +963,7 @@ impl fmt::Debug for CustomExpr { /// # WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub struct BinaryExpr { /// LHS expression. pub lhs: Expr, @@ -940,7 +977,7 @@ pub struct BinaryExpr { /// # WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Hash)] pub struct FnCallExpr { /// Pre-calculated hash for a script-defined function of the same name and number of parameters. /// None if native Rust only. @@ -959,13 +996,83 @@ pub struct FnCallExpr { pub args: StaticVec, } +/// A type that wraps a [`FLOAT`] and implements [`Hash`]. +#[cfg(not(feature = "no_float"))] +#[derive(Clone, Copy)] +pub struct FloatWrapper(FLOAT); + +#[cfg(not(feature = "no_float"))] +impl Hash for FloatWrapper { + fn hash(&self, state: &mut H) { + self.0.to_le_bytes().hash(state); + } +} + +#[cfg(not(feature = "no_float"))] +impl AsRef for FloatWrapper { + fn as_ref(&self) -> &FLOAT { + &self.0 + } +} + +#[cfg(not(feature = "no_float"))] +impl AsMut for FloatWrapper { + fn as_mut(&mut self) -> &mut FLOAT { + &mut self.0 + } +} + +#[cfg(not(feature = "no_float"))] +impl Deref for FloatWrapper { + type Target = FLOAT; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[cfg(not(feature = "no_float"))] +impl DerefMut for FloatWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(not(feature = "no_float"))] +impl fmt::Debug for FloatWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[cfg(not(feature = "no_float"))] +impl fmt::Display for FloatWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[cfg(not(feature = "no_float"))] +impl From for FloatWrapper { + fn from(value: FLOAT) -> Self { + Self::new(value) + } +} + +#[cfg(not(feature = "no_float"))] +impl FloatWrapper { + pub const fn new(value: FLOAT) -> Self { + Self(value) + } +} + /// _(INTERNALS)_ An expression sub-tree. /// Exported under the `internals` feature only. /// /// # WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub enum Expr { /// Dynamic constant. /// Used to hold either an [`Array`] or [`Map`] literal for quick cloning. @@ -977,7 +1084,7 @@ pub enum Expr { IntegerConstant(INT, Position), /// Floating-point constant. #[cfg(not(feature = "no_float"))] - FloatConstant(FLOAT, Position), + FloatConstant(FloatWrapper, Position), /// Character constant. CharConstant(char, Position), /// [String][ImmutableString] constant. @@ -1250,19 +1357,20 @@ mod tests { /// This test is to make sure no code changes increase the sizes of critical data structures. #[test] fn check_struct_sizes() { - use std::mem::size_of; + use crate::stdlib::mem::size_of; + use crate::*; - assert_eq!(size_of::(), 16); - assert_eq!(size_of::>(), 16); - assert_eq!(size_of::(), 4); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::>(), 16); - assert_eq!(size_of::(), 32); - assert_eq!(size_of::>(), 32); - assert_eq!(size_of::(), 32); - assert_eq!(size_of::(), 48); - assert_eq!(size_of::(), 56); - assert_eq!(size_of::(), 16); - assert_eq!(size_of::(), 72); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::>(), 16); + assert_eq!(size_of::(), 4); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::>(), 16); + assert_eq!(size_of::(), 32); + assert_eq!(size_of::>(), 32); + assert_eq!(size_of::(), 32); + assert_eq!(size_of::(), 48); + assert_eq!(size_of::(), 56); + assert_eq!(size_of::(), 16); + assert_eq!(size_of::(), 72); } } diff --git a/src/dynamic.rs b/src/dynamic.rs index 47507ff6..fc5ab807 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -7,14 +7,13 @@ use crate::stdlib::{ boxed::Box, fmt, hash::{Hash, Hasher}, - mem, ops::{Deref, DerefMut}, string::String, }; use crate::{FnPtr, ImmutableString, INT}; #[cfg(not(feature = "no_float"))] -use crate::FLOAT; +use crate::{ast::FloatWrapper, FLOAT}; #[cfg(not(feature = "no_index"))] use crate::Array; @@ -155,7 +154,7 @@ pub enum Union { Char(char, AccessMode), Int(INT, AccessMode), #[cfg(not(feature = "no_float"))] - Float(FLOAT, AccessMode), + Float(FloatWrapper, AccessMode), #[cfg(not(feature = "no_index"))] Array(Box, AccessMode), #[cfg(not(feature = "no_object"))] @@ -362,8 +361,6 @@ impl Dynamic { impl Hash for Dynamic { fn hash(&self, state: &mut H) { - mem::discriminant(self).hash(state); - match &self.0 { Union::Unit(_, _) => ().hash(state), Union::Bool(value, _) => value.hash(state), @@ -371,7 +368,7 @@ impl Hash for Dynamic { Union::Char(ch, _) => ch.hash(state), Union::Int(i, _) => i.hash(state), #[cfg(not(feature = "no_float"))] - Union::Float(f, _) => f.to_le_bytes().hash(state), + Union::Float(f, _) => f.hash(state), #[cfg(not(feature = "no_index"))] Union::Array(a, _) => (**a).hash(state), #[cfg(not(feature = "no_object"))] @@ -559,13 +556,16 @@ impl Dynamic { pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessMode::ReadWrite)); /// A [`Dynamic`] containing the floating-point zero. #[cfg(not(feature = "no_float"))] - pub const FLOAT_ZERO: Dynamic = Self(Union::Float(0.0, AccessMode::ReadWrite)); + pub const FLOAT_ZERO: Dynamic = + Self(Union::Float(FloatWrapper::new(0.0), AccessMode::ReadWrite)); /// A [`Dynamic`] containing the floating-point one. #[cfg(not(feature = "no_float"))] - pub const FLOAT_ONE: Dynamic = Self(Union::Float(1.0, AccessMode::ReadWrite)); + pub const FLOAT_ONE: Dynamic = + Self(Union::Float(FloatWrapper::new(1.0), AccessMode::ReadWrite)); /// A [`Dynamic`] containing the floating-point negative one. #[cfg(not(feature = "no_float"))] - pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float(-1.0, AccessMode::ReadWrite)); + pub const FLOAT_NEGATIVE_ONE: Dynamic = + Self(Union::Float(FloatWrapper::new(-1.0), AccessMode::ReadWrite)); /// Get the [`AccessMode`] for this [`Dynamic`]. pub(crate) fn access_mode(&self) -> AccessMode { @@ -836,7 +836,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match self.0 { - Union::Float(value, _) => unsafe_try_cast(value), + Union::Float(value, _) => unsafe_try_cast(*value), _ => None, }; } @@ -1105,7 +1105,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match &self.0 { - Union::Float(value, _) => ::downcast_ref::(value), + Union::Float(value, _) => ::downcast_ref::(value.as_ref()), _ => None, }; } @@ -1194,7 +1194,7 @@ impl Dynamic { #[cfg(not(feature = "no_float"))] if TypeId::of::() == TypeId::of::() { return match &mut self.0 { - Union::Float(value, _) => ::downcast_mut::(value), + Union::Float(value, _) => ::downcast_mut::(value.as_mut()), _ => None, }; } @@ -1277,7 +1277,7 @@ impl Dynamic { #[inline(always)] pub fn as_float(&self) -> Result { match self.0 { - Union::Float(n, _) => Ok(n), + Union::Float(n, _) => Ok(*n), #[cfg(not(feature = "no_closure"))] Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()), _ => Err(self.type_name()), @@ -1380,6 +1380,13 @@ impl From for Dynamic { impl From for Dynamic { #[inline(always)] fn from(value: FLOAT) -> Self { + Self(Union::Float(value.into(), AccessMode::ReadWrite)) + } +} +#[cfg(not(feature = "no_float"))] +impl From for Dynamic { + #[inline(always)] + fn from(value: FloatWrapper) -> Self { Self(Union::Float(value, AccessMode::ReadWrite)) } } diff --git a/src/engine.rs b/src/engine.rs index 05d67062..f11e1762 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1923,6 +1923,10 @@ impl Engine { .iter() .map(Into::into) .collect::>(); + let custom_def = self + .custom_syntax + .get(custom.tokens.first().unwrap()) + .unwrap(); let mut context = EvalContext { engine: self, scope, @@ -1932,7 +1936,7 @@ impl Engine { this_ptr, level, }; - (custom.func)(&mut context, &expressions) + (custom_def.func)(&mut context, &expressions) } _ => unreachable!("expression cannot be evaluated: {:?}", expr), @@ -2072,11 +2076,7 @@ impl Engine { let args = &mut [lhs_ptr_inner, &mut rhs_val]; // Overriding exact implementation - let source = if source.is_none() { - state.source.as_ref() - } else { - source - }; + let source = source.or_else(|| state.source.as_ref()); if func.is_plugin_fn() { func.get_plugin_fn() .call((self, source, &*mods, lib).into(), args)?; @@ -2130,14 +2130,13 @@ impl Engine { &mut rhs_val, ]; - let result = self - .exec_fn_call( + Some( + self.exec_fn_call( mods, state, lib, op, None, args, false, false, false, *op_pos, None, None, level, ) - .map(|(v, _)| v)?; - - Some((result, rhs_expr.position())) + .map(|(v, _)| (v, rhs_expr.position()))?, + ) }; // Must be either `var[index] op= val` or `var.prop op= val` diff --git a/src/engine_api.rs b/src/engine_api.rs index 5f5b4b21..fed074bf 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -8,11 +8,9 @@ use crate::stdlib::{ any::{type_name, TypeId}, boxed::Box, format, - hash::{Hash, Hasher}, string::String, vec::Vec, }; -use crate::utils::get_hasher; use crate::{ scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Module, NativeCallContext, ParseError, Position, Shared, AST, @@ -24,13 +22,6 @@ use crate::Array; #[cfg(not(feature = "no_object"))] use crate::Map; -/// Calculate a unique hash for a script. -fn calc_hash_for_scripts<'a>(scripts: impl IntoIterator) -> u64 { - let s = &mut get_hasher(); - scripts.into_iter().for_each(|&script| script.hash(s)); - s.finish() -} - /// Engine public API impl Engine { /// Register a function of the [`Engine`]. @@ -960,9 +951,8 @@ impl Engine { scripts: &[&str], optimization_level: OptimizationLevel, ) -> Result { - let hash = calc_hash_for_scripts(scripts); let stream = self.lex(scripts); - self.parse(hash, &mut stream.peekable(), scope, optimization_level) + self.parse(&mut stream.peekable(), scope, optimization_level) } /// Read the contents of a file into a string. #[cfg(not(feature = "no_std"))] @@ -1123,8 +1113,6 @@ impl Engine { .into()); }; - let hash = calc_hash_for_scripts(&scripts); - let stream = self.lex_with_map( &scripts, if has_null { @@ -1138,12 +1126,8 @@ impl Engine { }, ); - let ast = self.parse_global_expr( - hash, - &mut stream.peekable(), - &scope, - OptimizationLevel::None, - )?; + let ast = + self.parse_global_expr(&mut stream.peekable(), &scope, OptimizationLevel::None)?; // Handle null - map to () if has_null { @@ -1222,11 +1206,10 @@ impl Engine { script: &str, ) -> Result { let scripts = [script]; - let hash = calc_hash_for_scripts(&scripts); let stream = self.lex(&scripts); let mut peekable = stream.peekable(); - self.parse_global_expr(hash, &mut peekable, scope, self.optimization_level) + self.parse_global_expr(&mut peekable, scope, self.optimization_level) } /// Evaluate a script file. /// @@ -1384,12 +1367,10 @@ impl Engine { script: &str, ) -> Result> { let scripts = [script]; - let hash = calc_hash_for_scripts(&scripts); let stream = self.lex(&scripts); // No need to optimize a lone expression - let ast = - self.parse_global_expr(hash, &mut stream.peekable(), scope, OptimizationLevel::None)?; + let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?; self.eval_ast_with_scope(scope, &ast) } @@ -1522,9 +1503,8 @@ impl Engine { script: &str, ) -> Result<(), Box> { let scripts = [script]; - let hash = calc_hash_for_scripts(&scripts); let stream = self.lex(&scripts); - let ast = self.parse(hash, &mut stream.peekable(), scope, self.optimization_level)?; + let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?; self.consume_ast_with_scope(scope, &ast) } /// Evaluate an AST, but throw away the result and only return error (if any). diff --git a/src/lib.rs b/src/lib.rs index a618879d..642f6139 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -183,7 +183,10 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni #[cfg(feature = "internals")] #[deprecated = "this type is volatile and may change"] -pub use ast::{BinaryExpr, CustomExpr, Expr, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt}; +pub use ast::{ + BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt, + SwitchHashWrapper, +}; #[cfg(feature = "internals")] #[deprecated = "this type is volatile and may change"] diff --git a/src/parser.rs b/src/parser.rs index 10c7945b..a86095ac 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -41,8 +41,6 @@ type FunctionsLib = HashMap; struct ParseState<'e> { /// Reference to the scripting [`Engine`]. engine: &'e Engine, - /// Hash that uniquely identifies a script. - script_hash: u64, /// Interned strings. strings: HashMap, /// Encapsulates a local stack with variable names to simulate an actual runtime scope. @@ -75,7 +73,6 @@ impl<'e> ParseState<'e> { #[inline(always)] pub fn new( engine: &'e Engine, - script_hash: u64, #[cfg(not(feature = "unchecked"))] max_expr_depth: usize, #[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "no_function"))] @@ -83,7 +80,6 @@ impl<'e> ParseState<'e> { ) -> Self { Self { engine, - script_hash, #[cfg(not(feature = "unchecked"))] max_expr_depth, #[cfg(not(feature = "unchecked"))] @@ -919,7 +915,7 @@ fn parse_switch( Ok(Stmt::Switch( item, - Box::new((final_table, def_stmt)), + Box::new((final_table.into(), def_stmt)), settings.pos, )) } @@ -956,7 +952,7 @@ fn parse_primary( }, #[cfg(not(feature = "no_float"))] Token::FloatConstant(x) => { - let x = *x; + let x = (*x).into(); input.next().unwrap(); Expr::FloatConstant(x, settings.pos) } @@ -986,7 +982,6 @@ fn parse_primary( Token::Pipe | Token::Or if settings.allow_anonymous_fn => { let mut new_state = ParseState::new( state.engine, - state.script_hash, #[cfg(not(feature = "unchecked"))] state.max_function_expr_depth, #[cfg(not(feature = "unchecked"))] @@ -1284,7 +1279,7 @@ fn parse_unary( .map(|i| Expr::IntegerConstant(i, pos)) .or_else(|| { #[cfg(not(feature = "no_float"))] - return Some(Expr::FloatConstant(-(num as FLOAT), pos)); + return Some(Expr::FloatConstant((-(num as FLOAT)).into(), pos)); #[cfg(feature = "no_float")] return None; }) @@ -1292,7 +1287,7 @@ fn parse_unary( // Negative float #[cfg(not(feature = "no_float"))] - Expr::FloatConstant(x, pos) => Ok(Expr::FloatConstant(-x, pos)), + Expr::FloatConstant(x, pos) => Ok(Expr::FloatConstant((-(*x)).into(), pos)), // Call negative function expr => { @@ -1998,14 +1993,7 @@ fn parse_custom_syntax( } } - Ok(Expr::Custom( - Box::new(CustomExpr { - keywords, - func: syntax.func.clone(), - tokens, - }), - pos, - )) + Ok(Expr::Custom(Box::new(CustomExpr { keywords, tokens }), pos)) } /// Parse an expression. @@ -2600,7 +2588,6 @@ fn parse_stmt( (Token::Fn, pos) => { let mut new_state = ParseState::new( state.engine, - state.script_hash, #[cfg(not(feature = "unchecked"))] state.max_function_expr_depth, #[cfg(not(feature = "unchecked"))] @@ -3009,10 +2996,10 @@ fn parse_anon_fn( params.into_iter().map(|(v, _)| v).collect() }; - // Create unique function name by hashing the script hash plus the position + // Create unique function name by hashing the script body plus the parameters. let hasher = &mut get_hasher(); - state.script_hash.hash(hasher); - settings.pos.hash(hasher); + params.iter().for_each(|p| p.as_str().hash(hasher)); + body.hash(hasher); let hash = hasher.finish(); let fn_name: ImmutableString = format!("{}{:016x}", crate::engine::FN_ANONYMOUS, hash).into(); @@ -3045,7 +3032,6 @@ fn parse_anon_fn( impl Engine { pub(crate) fn parse_global_expr( &self, - script_hash: u64, input: &mut TokenStream, scope: &Scope, optimization_level: OptimizationLevel, @@ -3053,7 +3039,6 @@ impl Engine { let mut functions = Default::default(); let mut state = ParseState::new( self, - script_hash, #[cfg(not(feature = "unchecked"))] self.max_expr_depth(), #[cfg(not(feature = "unchecked"))] @@ -3095,14 +3080,12 @@ impl Engine { /// Parse the global level statements. fn parse_global_level( &self, - script_hash: u64, input: &mut TokenStream, ) -> Result<(Vec, Vec), ParseError> { let mut statements = Vec::with_capacity(16); let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder); let mut state = ParseState::new( self, - script_hash, #[cfg(not(feature = "unchecked"))] self.max_expr_depth(), #[cfg(not(feature = "unchecked"))] @@ -3165,12 +3148,11 @@ impl Engine { #[inline(always)] pub(crate) fn parse( &self, - script_hash: u64, input: &mut TokenStream, scope: &Scope, optimization_level: OptimizationLevel, ) -> Result { - let (statements, lib) = self.parse_global_level(script_hash, input)?; + let (statements, lib) = self.parse_global_level(input)?; Ok( // Optimize AST From d5891d4802ef549923f7b51cc951c5dbdd218e42 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 5 Jan 2021 18:01:42 +0800 Subject: [PATCH 03/12] Remove eval_expr_as_target. --- src/engine.rs | 120 +------------------------------------------------- 1 file changed, 2 insertions(+), 118 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index f11e1762..7f34733a 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1666,118 +1666,6 @@ impl Engine { } } - /// Get a [`Target`] from an expression. - pub(crate) fn eval_expr_as_target<'s>( - &self, - scope: &'s mut Scope, - mods: &mut Imports, - state: &mut State, - lib: &[&Module], - this_ptr: &'s mut Option<&mut Dynamic>, - expr: &Expr, - _no_const: bool, - level: usize, - ) -> Result<(Target<'s>, Position), Box> { - match expr { - // var - point directly to the value - Expr::Variable(_) => { - let (mut target, pos) = - self.search_namespace(scope, mods, state, lib, this_ptr, expr)?; - - // If necessary, constants are cloned - if target.as_ref().is_read_only() { - target = target.into_owned(); - } - - Ok((target, pos)) - } - // var[...] - #[cfg(not(feature = "no_index"))] - Expr::Index(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs { - Expr::Property(_) => unreachable!("unexpected Expr::Property in indexing"), - // var[...]... - Expr::FnCall(_, _) | Expr::Index(_, _) | Expr::Dot(_, _) => self - .eval_expr(scope, mods, state, lib, this_ptr, expr, level) - .map(|v| (v.into(), expr.position())), - // var[expr] - point directly to the item - _ => { - let idx = self.eval_expr(scope, mods, state, lib, this_ptr, &x.rhs, level)?; - let idx_pos = x.rhs.position(); - let (mut target, pos) = self.eval_expr_as_target( - scope, mods, state, lib, this_ptr, &x.lhs, _no_const, level, - )?; - - let is_ref = target.is_ref(); - - if target.is_shared() || target.is_value() { - let target_ref = target.as_mut(); - self.get_indexed_mut( - mods, state, lib, target_ref, idx, idx_pos, false, is_ref, true, level, - ) - .map(Target::into_owned) - } else { - let target_ref = target.take_ref().unwrap(); - self.get_indexed_mut( - mods, state, lib, target_ref, idx, idx_pos, false, is_ref, true, level, - ) - } - .map(|v| (v, pos)) - } - }, - // var.prop - #[cfg(not(feature = "no_object"))] - Expr::Dot(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs { - Expr::Variable(_) => unreachable!( - "unexpected Expr::Variable in dot access (should be Expr::Property)" - ), - // var.prop - Expr::Property(ref p) => { - let (mut target, _) = self.eval_expr_as_target( - scope, mods, state, lib, this_ptr, &x.lhs, _no_const, level, - )?; - let is_ref = target.is_ref(); - - if target.is::() { - // map.prop - point directly to the item - let (_, _, Ident { name, pos }) = p.as_ref(); - let idx = name.clone().into(); - - if target.is_shared() || target.is_value() { - let target_ref = target.as_mut(); - self.get_indexed_mut( - mods, state, lib, target_ref, idx, *pos, false, is_ref, true, level, - ) - .map(Target::into_owned) - } else { - let target_ref = target.take_ref().unwrap(); - self.get_indexed_mut( - mods, state, lib, target_ref, idx, *pos, false, is_ref, true, level, - ) - } - .map(|v| (v, *pos)) - } else { - // var.prop - call property getter - let (getter, _, Ident { pos, .. }) = p.as_ref(); - let mut args = [target.as_mut()]; - self.exec_fn_call( - mods, state, lib, getter, None, &mut args, is_ref, true, false, *pos, - None, None, level, - ) - .map(|(v, _)| (v.into(), *pos)) - } - } - // var.??? - _ => self - .eval_expr(scope, mods, state, lib, this_ptr, expr, level) - .map(|v| (v.into(), expr.position())), - }, - // expr - _ => self - .eval_expr(scope, mods, state, lib, this_ptr, expr, level) - .map(|v| (v.into(), expr.position())), - } - } - /// Evaluate an expression. pub(crate) fn eval_expr( &self, @@ -2192,12 +2080,8 @@ impl Engine { let (table, def_stmt) = x.as_ref(); let hasher = &mut get_hasher(); - self.eval_expr_as_target( - scope, mods, state, lib, this_ptr, match_expr, false, level, - )? - .0 - .as_ref() - .hash(hasher); + self.eval_expr(scope, mods, state, lib, this_ptr, match_expr, level)? + .hash(hasher); let hash = hasher.finish(); if let Some(stmt) = table.get(&hash) { From 3fbcefe0edb90c3a3a2a689bf53c382550a50821 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 5 Jan 2021 18:37:07 +0800 Subject: [PATCH 04/12] Move HashableHashMap to utils. --- src/ast.rs | 60 ++++++++------------------------------------------- src/lib.rs | 4 ++-- src/utils.rs | 61 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 06196a67..4891878b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,7 +6,6 @@ use crate::module::NamespaceRef; use crate::stdlib::{ borrow::Cow, boxed::Box, - collections::HashMap, fmt, hash::{Hash, Hasher}, num::{NonZeroU64, NonZeroUsize}, @@ -16,7 +15,7 @@ use crate::stdlib::{ vec::Vec, }; use crate::token::Token; -use crate::utils::StraightHasherBuilder; +use crate::utils::{HashableHashMap, StraightHasherBuilder}; use crate::{ Dynamic, FnNamespace, FnPtr, ImmutableString, Module, Position, Shared, StaticVec, INT, }; @@ -691,54 +690,6 @@ pub enum ReturnType { Exception, } -/// A type that wraps a [`HashMap`]`` for the `switch` statement and implements [`Hash`]. -#[derive(Clone)] -pub struct SwitchHashWrapper(HashMap); - -impl From> for SwitchHashWrapper { - fn from(value: HashMap) -> Self { - Self(value) - } -} -impl AsRef> for SwitchHashWrapper { - fn as_ref(&self) -> &HashMap { - &self.0 - } -} -impl AsMut> for SwitchHashWrapper { - fn as_mut(&mut self) -> &mut HashMap { - &mut self.0 - } -} -impl Deref for SwitchHashWrapper { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} -impl DerefMut for SwitchHashWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} -impl fmt::Debug for SwitchHashWrapper { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} -impl Hash for SwitchHashWrapper { - fn hash(&self, state: &mut H) { - let mut keys: Vec<_> = self.0.keys().collect(); - keys.sort(); - - keys.into_iter().for_each(|key| { - key.hash(state); - self.0.get(&key).unwrap().hash(state); - }); - } -} - /// _(INTERNALS)_ A statement. /// Exported under the `internals` feature only. /// @@ -752,7 +703,14 @@ pub enum Stmt { /// `if` expr `{` stmt `}` `else` `{` stmt `}` If(Expr, Box<(Stmt, Option)>, Position), /// `switch` expr `{` literal or _ `=>` stmt `,` ... `}` - Switch(Expr, Box<(SwitchHashWrapper, Option)>, Position), + Switch( + Expr, + Box<( + HashableHashMap, + Option, + )>, + Position, + ), /// `while` expr `{` stmt `}` While(Expr, Box, Position), /// `do` `{` stmt `}` `while`|`until` expr diff --git a/src/lib.rs b/src/lib.rs index 642f6139..21a57ab1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -184,8 +184,8 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni #[cfg(feature = "internals")] #[deprecated = "this type is volatile and may change"] pub use ast::{ - BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt, - SwitchHashWrapper, + BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, HashableHashMap, Ident, ReturnType, + ScriptFnDef, Stmt, }; #[cfg(feature = "internals")] diff --git a/src/utils.rs b/src/utils.rs index c43a5aaf..9d2a2417 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,11 +6,13 @@ use crate::stdlib::{ borrow::Borrow, boxed::Box, cmp::Ordering, + collections::HashMap, fmt, + fmt::{Debug, Display}, hash::{BuildHasher, Hash, Hasher}, iter::{empty, FromIterator}, num::NonZeroU64, - ops::{Add, AddAssign, Deref}, + ops::{Add, AddAssign, Deref, DerefMut}, str::FromStr, string::{String, ToString}, }; @@ -140,6 +142,55 @@ pub(crate) fn combine_hashes(a: NonZeroU64, b: NonZeroU64) -> NonZeroU64 { NonZeroU64::new(a.get() ^ b.get()).unwrap_or_else(|| NonZeroU64::new(42).unwrap()) } +/// _(INTERNALS)_ A type that wraps a [`HashMap`] and implements [`Hash`]. +/// Exported under the `internals` feature only. +#[derive(Clone, Default)] +pub struct HashableHashMap(HashMap); + +impl From> for HashableHashMap { + fn from(value: HashMap) -> Self { + Self(value) + } +} +impl AsRef> for HashableHashMap { + fn as_ref(&self) -> &HashMap { + &self.0 + } +} +impl AsMut> for HashableHashMap { + fn as_mut(&mut self) -> &mut HashMap { + &mut self.0 + } +} +impl Deref for HashableHashMap { + type Target = HashMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for HashableHashMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl Debug for HashableHashMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} +impl Hash for HashableHashMap { + fn hash(&self, state: &mut B) { + let mut keys: Vec<_> = self.0.keys().collect(); + keys.sort(); + + keys.into_iter().for_each(|key| { + key.hash(state); + self.0.get(&key).unwrap().hash(state); + }); + } +} + /// The system immutable string type. /// /// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>` @@ -276,17 +327,17 @@ impl<'a> FromIterator for ImmutableString { } } -impl fmt::Display for ImmutableString { +impl Display for ImmutableString { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.0.as_str(), f) + Display::fmt(self.0.as_str(), f) } } -impl fmt::Debug for ImmutableString { +impl Debug for ImmutableString { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.0.as_str(), f) + Debug::fmt(self.0.as_str(), f) } } From a5d63921074e530d584262508820fa707479376a Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 6 Jan 2021 13:46:53 +0800 Subject: [PATCH 05/12] Use NonZero for limits. --- src/engine.rs | 138 +++++++++++++++++++++-------------------- src/engine_settings.rs | 44 ++++++------- src/parser.rs | 34 +++++----- src/token.rs | 15 +++-- 4 files changed, 119 insertions(+), 112 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 7f34733a..37f279d2 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -135,7 +135,8 @@ impl Imports { .rev() .find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) } - /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]? + /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of + /// imported [modules][Module]? #[allow(dead_code)] #[inline(always)] pub fn contains_iter(&self, id: TypeId) -> bool { @@ -508,8 +509,8 @@ pub struct State { /// In some situation, e.g. after running an `eval` statement, subsequent offsets become mis-aligned. /// When that happens, this flag is turned on to force a scope lookup by name. pub always_search: bool, - /// Level of the current scope. The global (root) level is zero, a new block (or function call) - /// is one level higher, and so on. + /// Level of the current scope. The global (root) level is zero, a new block + /// (or function call) is one level higher, and so on. pub scope_level: usize, /// Number of operations performed. pub operations: u64, @@ -542,30 +543,34 @@ impl State { pub struct Limits { /// Maximum levels of call-stack to prevent infinite recursion. /// Not available under `no_function`. + /// + /// Set to zero to effectively disable function calls. #[cfg(not(feature = "no_function"))] pub max_call_stack_depth: usize, - /// Maximum depth of statements/expressions at global level (0 = unlimited). - pub max_expr_depth: usize, - /// Maximum depth of statements/expressions in functions (0 = unlimited). + /// Maximum depth of statements/expressions at global level. + pub max_expr_depth: Option, + /// Maximum depth of statements/expressions in functions. /// Not available under `no_function`. #[cfg(not(feature = "no_function"))] - pub max_function_expr_depth: usize, - /// Maximum number of operations allowed to run (0 = unlimited). - pub max_operations: u64, + pub max_function_expr_depth: Option, + /// Maximum number of operations allowed to run. + pub max_operations: Option, /// Maximum number of [modules][Module] allowed to load. /// Not available under `no_module`. + /// + /// Set to zero to effectively disable loading any [module][Module]. #[cfg(not(feature = "no_module"))] pub max_modules: usize, - /// Maximum length of a [string][ImmutableString] (0 = unlimited). - pub max_string_size: usize, - /// Maximum length of an [array][Array] (0 = unlimited). + /// Maximum length of a [string][ImmutableString]. + pub max_string_size: Option, + /// Maximum length of an [array][Array]. /// Not available under `no_index`. #[cfg(not(feature = "no_index"))] - pub max_array_size: usize, - /// Maximum number of properties in an [object map][Map] (0 = unlimited). + pub max_array_size: Option, + /// Maximum number of properties in an [object map][Map]. /// Not available under `no_object`. #[cfg(not(feature = "no_object"))] - pub max_map_size: usize, + pub max_map_size: Option, } /// Context of a script evaluation process. @@ -777,13 +782,13 @@ pub fn search_imports( // Qualified - check if the root module is directly indexed let index = if state.always_search { - 0 + None } else { - namespace.index().map_or(0, NonZeroUsize::get) + namespace.index() }; - Ok(if index > 0 { - let offset = mods.len() - index; + Ok(if let Some(index) = index { + let offset = mods.len() - index.get(); mods.get(offset).expect("invalid index in Imports") } else { mods.find(root) @@ -838,17 +843,17 @@ impl Engine { limits: Limits { #[cfg(not(feature = "no_function"))] max_call_stack_depth: MAX_CALL_STACK_DEPTH, - max_expr_depth: MAX_EXPR_DEPTH, + max_expr_depth: NonZeroUsize::new(MAX_EXPR_DEPTH), #[cfg(not(feature = "no_function"))] - max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, - max_operations: 0, + max_function_expr_depth: NonZeroUsize::new(MAX_FUNCTION_EXPR_DEPTH), + max_operations: None, #[cfg(not(feature = "no_module"))] max_modules: usize::MAX, - max_string_size: 0, + max_string_size: None, #[cfg(not(feature = "no_index"))] - max_array_size: 0, + max_array_size: None, #[cfg(not(feature = "no_object"))] - max_map_size: 0, + max_map_size: None, }, disable_doc_comments: false, @@ -895,17 +900,17 @@ impl Engine { limits: Limits { #[cfg(not(feature = "no_function"))] max_call_stack_depth: MAX_CALL_STACK_DEPTH, - max_expr_depth: MAX_EXPR_DEPTH, + max_expr_depth: NonZeroUsize::new(MAX_EXPR_DEPTH), #[cfg(not(feature = "no_function"))] - max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH, - max_operations: 0, + max_function_expr_depth: NonZeroUsize::new(MAX_FUNCTION_EXPR_DEPTH), + max_operations: None, #[cfg(not(feature = "no_module"))] max_modules: usize::MAX, - max_string_size: 0, + max_string_size: None, #[cfg(not(feature = "no_index"))] - max_array_size: 0, + max_array_size: None, #[cfg(not(feature = "no_object"))] - max_map_size: 0, + max_map_size: None, }, disable_doc_comments: false, @@ -975,14 +980,11 @@ impl Engine { } // Check if it is directly indexed - let index = if state.always_search { - 0 - } else { - index.map_or(0, NonZeroUsize::get) - }; + let index = if state.always_search { &None } else { index }; // Check the variable resolver, if any if let Some(ref resolve_var) = self.resolve_var { + let index = index.map(NonZeroUsize::get).unwrap_or(0); let context = EvalContext { engine: self, scope, @@ -1000,8 +1002,8 @@ impl Engine { } } - let index = if index > 0 { - scope.len() - index + let index = if let Some(index) = index { + scope.len() - index.get() } else { // Find the variable in the scope scope @@ -1012,8 +1014,8 @@ impl Engine { let val = scope.get_mut_by_index(index); - // Check for data race - probably not necessary because the only place it should conflict is in a method call - // when the object variable is also used as a parameter. + // Check for data race - probably not necessary because the only place it should conflict is + // in a method call when the object variable is also used as a parameter. // if cfg!(not(feature = "no_closure")) && val.is_locked() { // return EvalAltResult::ErrorDataRace(name.into(), *pos).into(); // } @@ -1285,7 +1287,8 @@ impl Engine { ) .or_else( |err| match *err { - // If there is no setter, no need to feed it back because the property is read-only + // If there is no setter, no need to feed it back because + // the property is read-only EvalAltResult::ErrorDotExpr(_, _) => { Ok((Dynamic::UNIT, false)) } @@ -1405,7 +1408,8 @@ impl Engine { } /// Evaluate a chain of indexes and store the results in a [`StaticVec`]. - /// [`StaticVec`] is used to avoid an allocation in the overwhelming cases of just a few levels of indexing. + /// [`StaticVec`] is used to avoid an allocation in the overwhelming cases of + /// just a few levels of indexing. #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] fn eval_indexed_chain( &self, @@ -2400,20 +2404,23 @@ impl Engine { result: Result>, pos: Position, ) -> Result> { - // If no data size limits, just return - let mut total = 0; + // Simply return all errors + if result.is_err() { + return result; + } - total += self.max_string_size(); + // If no data size limits, just return + let mut has_limit = self.limits.max_string_size.is_some(); #[cfg(not(feature = "no_index"))] { - total += self.max_array_size(); + has_limit = has_limit || self.limits.max_array_size.is_some(); } #[cfg(not(feature = "no_object"))] { - total += self.max_map_size(); + has_limit = has_limit || self.limits.max_map_size.is_some(); } - if total == 0 { + if !has_limit { return result; } @@ -2469,34 +2476,33 @@ impl Engine { } } - match result { - // Simply return all errors - Err(_) => return result, - // String with limit - Ok(Dynamic(Union::Str(_, _))) if self.max_string_size() > 0 => (), - // Array with limit - #[cfg(not(feature = "no_index"))] - Ok(Dynamic(Union::Array(_, _))) if self.max_array_size() > 0 => (), - // Map with limit - #[cfg(not(feature = "no_object"))] - Ok(Dynamic(Union::Map(_, _))) if self.max_map_size() > 0 => (), - // Everything else is simply returned - Ok(_) => return result, - }; - let (_arr, _map, s) = calc_size(result.as_ref().unwrap()); - if s > self.max_string_size() { + if s > self + .limits + .max_string_size + .map_or(usize::MAX, NonZeroUsize::get) + { return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), pos).into(); } #[cfg(not(feature = "no_index"))] - if _arr > self.max_array_size() { + if _arr + > self + .limits + .max_array_size + .map_or(usize::MAX, NonZeroUsize::get) + { return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), pos).into(); } #[cfg(not(feature = "no_object"))] - if _map > self.max_map_size() { + if _map + > self + .limits + .max_map_size + .map_or(usize::MAX, NonZeroUsize::get) + { return EvalAltResult::ErrorDataTooLarge("Size of object map".to_string(), pos).into(); } diff --git a/src/engine_settings.rs b/src/engine_settings.rs index 7d99c1fa..e44d8d30 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -1,6 +1,10 @@ //! Configuration settings for [`Engine`]. -use crate::stdlib::{format, num::NonZeroU8, string::String}; +use crate::stdlib::{ + format, + num::{NonZeroU64, NonZeroU8, NonZeroUsize}, + string::String, +}; use crate::token::Token; use crate::Engine; @@ -62,11 +66,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn set_max_operations(&mut self, operations: u64) -> &mut Self { - self.limits.max_operations = if operations == u64::MAX { - 0 - } else { - operations - }; + self.limits.max_operations = NonZeroU64::new(operations); self } /// The maximum number of operations allowed for a script to run (0 for unlimited). @@ -75,7 +75,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn max_operations(&self) -> u64 { - self.limits.max_operations + self.limits.max_operations.map_or(0, NonZeroU64::get) } /// Set the maximum number of imported [modules][crate::Module] allowed for a script. /// @@ -106,18 +106,10 @@ impl Engine { max_expr_depth: usize, #[cfg(not(feature = "no_function"))] max_function_expr_depth: usize, ) -> &mut Self { - self.limits.max_expr_depth = if max_expr_depth == usize::MAX { - 0 - } else { - max_expr_depth - }; + self.limits.max_expr_depth = NonZeroUsize::new(max_expr_depth); #[cfg(not(feature = "no_function"))] { - self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX { - 0 - } else { - max_function_expr_depth - }; + self.limits.max_function_expr_depth = NonZeroUsize::new(max_function_expr_depth); } self } @@ -127,7 +119,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn max_expr_depth(&self) -> usize { - self.limits.max_expr_depth + self.limits.max_expr_depth.map_or(0, NonZeroUsize::get) } /// The depth limit for expressions in functions (0 for unlimited). /// @@ -136,7 +128,9 @@ impl Engine { #[cfg(not(feature = "no_function"))] #[inline(always)] pub fn max_function_expr_depth(&self) -> usize { - self.limits.max_function_expr_depth + self.limits + .max_function_expr_depth + .map_or(0, NonZeroUsize::get) } /// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited). /// @@ -144,7 +138,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self { - self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size }; + self.limits.max_string_size = NonZeroUsize::new(max_size); self } /// The maximum length of [strings][crate::ImmutableString] (0 for unlimited). @@ -153,7 +147,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] #[inline(always)] pub fn max_string_size(&self) -> usize { - self.limits.max_string_size + self.limits.max_string_size.map_or(0, NonZeroUsize::get) } /// Set the maximum length of [arrays][crate::Array] (0 for unlimited). /// @@ -162,7 +156,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] #[inline(always)] pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self { - self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size }; + self.limits.max_array_size = NonZeroUsize::new(max_size); self } /// The maximum length of [arrays][crate::Array] (0 for unlimited). @@ -172,7 +166,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] #[inline(always)] pub fn max_array_size(&self) -> usize { - self.limits.max_array_size + self.limits.max_array_size.map_or(0, NonZeroUsize::get) } /// Set the maximum size of [object maps][crate::Map] (0 for unlimited). /// @@ -181,7 +175,7 @@ impl Engine { #[cfg(not(feature = "no_object"))] #[inline(always)] pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self { - self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size }; + self.limits.max_map_size = NonZeroUsize::new(max_size); self } /// The maximum size of [object maps][crate::Map] (0 for unlimited). @@ -191,7 +185,7 @@ impl Engine { #[cfg(not(feature = "no_object"))] #[inline(always)] pub fn max_map_size(&self) -> usize { - self.limits.max_map_size + self.limits.max_map_size.map_or(0, NonZeroUsize::get) } /// Set the module resolution service used by the [`Engine`]. /// diff --git a/src/parser.rs b/src/parser.rs index a86095ac..4c462f66 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -61,11 +61,11 @@ struct ParseState<'e> { modules: StaticVec, /// Maximum levels of expression nesting. #[cfg(not(feature = "unchecked"))] - max_expr_depth: usize, + max_expr_depth: Option, /// Maximum levels of expression nesting in functions. #[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "no_function"))] - max_function_expr_depth: usize, + max_function_expr_depth: Option, } impl<'e> ParseState<'e> { @@ -73,10 +73,10 @@ impl<'e> ParseState<'e> { #[inline(always)] pub fn new( engine: &'e Engine, - #[cfg(not(feature = "unchecked"))] max_expr_depth: usize, + #[cfg(not(feature = "unchecked"))] max_expr_depth: Option, #[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "no_function"))] - max_function_expr_depth: usize, + max_function_expr_depth: Option, ) -> Self { Self { engine, @@ -212,15 +212,17 @@ impl ParseSettings { } /// Make sure that the current level of expression nesting is within the maximum limit. #[cfg(not(feature = "unchecked"))] - #[inline] - pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> { - if limit == 0 { - Ok(()) - } else if self.level > limit { - Err(PERR::ExprTooDeep.into_err(self.pos)) - } else { - Ok(()) + #[inline(always)] + pub fn ensure_level_within_max_limit( + &self, + limit: Option, + ) -> Result<(), ParseError> { + if let Some(limit) = limit { + if self.level > limit.get() { + return Err(PERR::ExprTooDeep.into_err(self.pos)); + } } + Ok(()) } } @@ -3040,10 +3042,10 @@ impl Engine { let mut state = ParseState::new( self, #[cfg(not(feature = "unchecked"))] - self.max_expr_depth(), + NonZeroUsize::new(self.max_expr_depth()), #[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "no_function"))] - self.max_function_expr_depth(), + NonZeroUsize::new(self.max_function_expr_depth()), ); let settings = ParseSettings { @@ -3087,10 +3089,10 @@ impl Engine { let mut state = ParseState::new( self, #[cfg(not(feature = "unchecked"))] - self.max_expr_depth(), + NonZeroUsize::new(self.max_expr_depth()), #[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "no_function"))] - self.max_function_expr_depth(), + NonZeroUsize::new(self.max_function_expr_depth()), ); while !input.peek().unwrap().0.is_eof() { diff --git a/src/token.rs b/src/token.rs index 7ae8ba8a..b08339d4 100644 --- a/src/token.rs +++ b/src/token.rs @@ -8,6 +8,7 @@ use crate::stdlib::{ borrow::Cow, char, fmt, format, iter::Peekable, + num::NonZeroUsize, str::{Chars, FromStr}, string::{String, ToString}, }; @@ -747,7 +748,7 @@ impl From for String { #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct TokenizeState { /// Maximum length of a string (0 = unlimited). - pub max_string_size: usize, + pub max_string_size: Option, /// Can the next token be a unary operator? pub non_unary: bool, /// Is the tokenizer currently inside a block comment? @@ -796,8 +797,10 @@ pub fn parse_string_literal( pos.advance(); - if state.max_string_size > 0 && result.len() > state.max_string_size { - return Err((LexError::StringTooLong(state.max_string_size), *pos)); + if let Some(max) = state.max_string_size { + if result.len() > max.get() { + return Err((LexError::StringTooLong(max.get()), *pos)); + } } match next_char { @@ -902,8 +905,10 @@ pub fn parse_string_literal( let s = result.iter().collect::(); - if state.max_string_size > 0 && s.len() > state.max_string_size { - return Err((LexError::StringTooLong(state.max_string_size), *pos)); + if let Some(max) = state.max_string_size { + if s.len() > max.get() { + return Err((LexError::StringTooLong(max.get()), *pos)); + } } Ok(s) From e059ca009ccb58031dc993e0daccf99bb1433d8c Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 6 Jan 2021 18:22:45 +0800 Subject: [PATCH 06/12] Fix feature builds. --- codegen/ui_tests/rhai_mod_unknown_type.rs | 7 ++----- src/engine_settings.rs | 9 ++++----- src/lib.rs | 5 ++--- src/token.rs | 2 +- src/utils.rs | 1 + 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/codegen/ui_tests/rhai_mod_unknown_type.rs b/codegen/ui_tests/rhai_mod_unknown_type.rs index 7c19ab18..ae582726 100644 --- a/codegen/ui_tests/rhai_mod_unknown_type.rs +++ b/codegen/ui_tests/rhai_mod_unknown_type.rs @@ -9,16 +9,13 @@ pub struct Point { #[export_module] pub mod test_module { pub use super::Point; - pub fn test_fn(input: Pointer) -> bool { + pub fn test_fn(input: Point) -> bool { input.x < input.y } } fn main() { - let n = Point { - x: 0.0, - y: 10.0, - }; + let n = Point { x: 0.0, y: 10.0 }; if test_module::test_fn(n) { println!("yes"); } else { diff --git a/src/engine_settings.rs b/src/engine_settings.rs index e44d8d30..396c155e 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -1,13 +1,12 @@ //! Configuration settings for [`Engine`]. -use crate::stdlib::{ - format, - num::{NonZeroU64, NonZeroU8, NonZeroUsize}, - string::String, -}; +use crate::stdlib::{format, num::NonZeroU8, string::String}; use crate::token::Token; use crate::Engine; +#[cfg(not(feature = "unchecked"))] +use crate::stdlib::num::{NonZeroU64, NonZeroUsize}; + #[cfg(not(feature = "no_module"))] use crate::stdlib::boxed::Box; diff --git a/src/lib.rs b/src/lib.rs index 21a57ab1..14bc390d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,7 +136,7 @@ pub use utils::ImmutableString; use fn_native::Locked; #[cfg(feature = "internals")] -pub use utils::{calc_native_fn_hash, calc_script_fn_hash}; +pub use utils::{calc_native_fn_hash, calc_script_fn_hash, HashableHashMap}; #[cfg(not(feature = "internals"))] pub(crate) use utils::{calc_native_fn_hash, calc_script_fn_hash}; @@ -184,8 +184,7 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni #[cfg(feature = "internals")] #[deprecated = "this type is volatile and may change"] pub use ast::{ - BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, HashableHashMap, Ident, ReturnType, - ScriptFnDef, Stmt, + BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt, }; #[cfg(feature = "internals")] diff --git a/src/token.rs b/src/token.rs index b08339d4..de291fbe 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1806,7 +1806,7 @@ impl Engine { #[cfg(not(feature = "unchecked"))] max_string_size: self.limits.max_string_size, #[cfg(feature = "unchecked")] - max_string_size: 0, + max_string_size: None, non_unary: false, comment_level: 0, end_with_none: false, diff --git a/src/utils.rs b/src/utils.rs index 9d2a2417..6931476a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -15,6 +15,7 @@ use crate::stdlib::{ ops::{Add, AddAssign, Deref, DerefMut}, str::FromStr, string::{String, ToString}, + vec::Vec, }; use crate::Shared; From 67a85a19ae581939e0fc7c69c37567910a98b3b7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 6 Jan 2021 19:30:58 +0800 Subject: [PATCH 07/12] Fix codegen test. --- codegen/ui_tests/rhai_mod_unknown_type.rs | 7 +++++-- codegen/ui_tests/rhai_mod_unknown_type.stderr | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/codegen/ui_tests/rhai_mod_unknown_type.rs b/codegen/ui_tests/rhai_mod_unknown_type.rs index ae582726..4c067fd3 100644 --- a/codegen/ui_tests/rhai_mod_unknown_type.rs +++ b/codegen/ui_tests/rhai_mod_unknown_type.rs @@ -9,13 +9,16 @@ pub struct Point { #[export_module] pub mod test_module { pub use super::Point; - pub fn test_fn(input: Point) -> bool { + pub fn test_fn(input: Pointer) -> bool { input.x < input.y } } fn main() { - let n = Point { x: 0.0, y: 10.0 }; + let n = Point { + x: 0.0, + y: 10.0 + }; if test_module::test_fn(n) { println!("yes"); } else { diff --git a/codegen/ui_tests/rhai_mod_unknown_type.stderr b/codegen/ui_tests/rhai_mod_unknown_type.stderr index 87360967..1b400234 100644 --- a/codegen/ui_tests/rhai_mod_unknown_type.stderr +++ b/codegen/ui_tests/rhai_mod_unknown_type.stderr @@ -19,5 +19,5 @@ help: consider importing one of these items | 11 | use std::fmt::Pointer; | -11 | use syn::export::fmt::Pointer; +11 | use syn::__private::fmt::Pointer; | From 96b1e7777b56dab720630812a9fcc248ed8b1889 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 7 Jan 2021 17:30:06 +0800 Subject: [PATCH 08/12] Update URL links. --- Cargo.toml | 4 +-- README.md | 50 +++++++++++++++++------------------ RELEASES.md | 4 +-- codegen/Cargo.toml | 4 +-- codegen/README.md | 2 +- doc/README.md | 14 +++++----- doc/book.toml | 2 +- doc/src/about/related.md | 2 +- doc/src/context.json | 4 +-- doc/src/patterns/multiple.md | 8 +++--- doc/src/start/install.md | 4 +-- no_std/no_std_test/Cargo.toml | 4 +-- src/lib.rs | 4 +-- tests/expressions.rs | 2 +- 14 files changed, 54 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6ee58d61..8d3234c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ version = "0.19.10" edition = "2018" authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"] description = "Embedded scripting for Rust" -homepage = "https://schungx.github.io/rhai" -repository = "https://github.com/jonathandturner/rhai" +homepage = "https://rhaiscript.github.io/book" +repository = "https://github.com/rhaiscript/rhai" readme = "README.md" license = "MIT OR Apache-2.0" include = [ diff --git a/README.md b/README.md index b812b5c4..7a24a1ba 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ Rhai - Embedded Scripting for Rust ================================= -![GitHub last commit](https://img.shields.io/github/last-commit/jonathandturner/rhai?logo=github) -[![Build Status](https://github.com/jonathandturner/rhai/workflows/Build/badge.svg)](https://github.com/jonathandturner/rhai/actions) -[![license](https://img.shields.io/crates/l/rhai)](https://github.com/license/jonathandturner/rhai) +![GitHub last commit](https://img.shields.io/github/last-commit/rhaiscript/rhai?logo=github) +[![Build Status](https://github.com/rhaiscript/rhai/workflows/Build/badge.svg)](https://github.com/rhaiscript/rhai/actions) +[![license](https://img.shields.io/crates/l/rhai)](https://github.com/license/rhaiscript/rhai) [![crates.io](https://img.shields.io/crates/v/rhai?logo=rust)](https://crates.io/crates/rhai/) [![crates.io](https://img.shields.io/crates/d/rhai?logo=rust)](https://crates.io/crates/rhai/) [![API Docs](https://docs.rs/rhai/badge.svg?logo=docs.rs)](https://docs.rs/rhai/) [![chat](https://img.shields.io/discord/767611025456889857.svg?logo=discord)](https://discord.gg/HquqbYFcZ9) [![Reddit](https://img.shields.io/reddit/subreddit-subscribers/Rhai?logo=reddit)](https://www.reddit.com/r/Rhai) -![Rhai logo](https://schungx.github.io/rhai/images/logo/rhai-banner-transparent-colour.svg) +![Rhai logo](https://rhaiscript.github.io/book/images/logo/rhai-banner-transparent-colour.svg) Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way to add scripting to any application. @@ -31,44 +31,44 @@ Standard features * Easy-to-use language similar to JavaScript+Rust with dynamic typing. * Fairly low compile-time overhead. * Fairly efficient evaluation (1 million iterations in 0.3 sec on a single core, 2.3 GHz Linux VM). -* Tight integration with native Rust [functions](https://schungx.github.io/rhai/rust/functions.html) and [types]([#custom-types-and-methods](https://schungx.github.io/rhai/rust/custom.html)), including [getters/setters](https://schungx.github.io/rhai/rust/getters-setters.html), [methods](https://schungx.github.io/rhai/rust/custom.html) and [indexers](https://schungx.github.io/rhai/rust/indexers.html). -* Freely pass Rust variables/constants into a script via an external [`Scope`](https://schungx.github.io/rhai/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. -* Easily [call a script-defined function](https://schungx.github.io/rhai/engine/call-fn.html) from Rust. +* Tight integration with native Rust [functions](https://rhaiscript.github.io/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhaiscript.github.io/book/rust/custom.html)), including [getters/setters](https://rhaiscript.github.io/book/rust/getters-setters.html), [methods](https://rhaiscript.github.io/book/rust/custom.html) and [indexers](https://rhaiscript.github.io/book/rust/indexers.html). +* Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhaiscript.github.io/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. +* Easily [call a script-defined function](https://rhaiscript.github.io/book/engine/call-fn.html) from Rust. * Relatively little `unsafe` code (yes there are some for performance reasons). * Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec)). * Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature). -* Scripts are [optimized](https://schungx.github.io/rhai/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations. -* Easy custom API development via [plugins](https://schungx.github.io/rhai/plugins/index.html) system powered by procedural macros. -* [Function overloading](https://schungx.github.io/rhai/language/overload.html) and [operator overloading](https://schungx.github.io/rhai/rust/operators.html). -* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html) with additional support for [currying](https://schungx.github.io/rhai/language/fn-curry.html). -* [Closures](https://schungx.github.io/rhai/language/fn-closure.html) (anonymous functions) that can capture shared values. -* Some syntactic support for [object-oriented programming (OOP)](https://schungx.github.io/rhai/language/oop.html). -* Organize code base with dynamically-loadable [modules](https://schungx.github.io/rhai/language/modules.html). +* Scripts are [optimized](https://rhaiscript.github.io/book/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations. +* Easy custom API development via [plugins](https://rhaiscript.github.io/book/plugins/index.html) system powered by procedural macros. +* [Function overloading](https://rhaiscript.github.io/book/language/overload.html) and [operator overloading](https://rhaiscript.github.io/book/rust/operators.html). +* Dynamic dispatch via [function pointers](https://rhaiscript.github.io/book/language/fn-ptr.html) with additional support for [currying](https://rhaiscript.github.io/book/language/fn-curry.html). +* [Closures](https://rhaiscript.github.io/book/language/fn-closure.html) (anonymous functions) that can capture shared values. +* Some syntactic support for [object-oriented programming (OOP)](https://rhaiscript.github.io/book/language/oop.html). +* Organize code base with dynamically-loadable [modules](https://rhaiscript.github.io/book/language/modules.html). * Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature). -* Support for [minimal builds](https://schungx.github.io/rhai/start/builds/minimal.html) by excluding unneeded language [features](https://schungx.github.io/rhai/start/features.html). +* Support for [minimal builds](https://rhaiscript.github.io/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhaiscript.github.io/book/start/features.html). Protected against attacks ------------------------- -* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://schungx.github.io/rhai/patterns/control.html). -* Rugged - protected against malicious attacks (such as [stack-overflow](https://schungx.github.io/rhai/safety/max-call-stack.html), [over-sized data](https://schungx.github.io/rhai/safety/max-string-size.html), and [runaway scripts](https://schungx.github.io/rhai/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts. -* Track script evaluation [progress](https://schungx.github.io/rhai/safety/progress.html) and manually terminate a script run. +* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhaiscript.github.io/book/patterns/control.html). +* Rugged - protected against malicious attacks (such as [stack-overflow](https://rhaiscript.github.io/book/safety/max-call-stack.html), [over-sized data](https://rhaiscript.github.io/book/safety/max-string-size.html), and [runaway scripts](https://rhaiscript.github.io/book/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts. +* Track script evaluation [progress](https://rhaiscript.github.io/book/safety/progress.html) and manually terminate a script run. For those who actually want their own language --------------------------------------------- -* Use as a [DSL](https://schungx.github.io/rhai/engine/dsl.html). -* Restrict the language by surgically [disabling keywords and operators](https://schungx.github.io/rhai/engine/disable.html). -* Define [custom operators](https://schungx.github.io/rhai/engine/custom-op.html). -* Extend the language with [custom syntax](https://schungx.github.io/rhai/engine/custom-syntax.html). +* Use as a [DSL](https://rhaiscript.github.io/book/engine/dsl.html). +* Restrict the language by surgically [disabling keywords and operators](https://rhaiscript.github.io/book/engine/disable.html). +* Define [custom operators](https://rhaiscript.github.io/book/engine/custom-op.html). +* Extend the language with [custom syntax](https://rhaiscript.github.io/book/engine/custom-syntax.html). Documentation ------------- -See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai scripting engine and language. +See [The Rhai Book](https://rhaiscript.github.io/book) for details on the Rhai scripting engine and language. To build _The Book_, first install [`mdbook`](https://github.com/rust-lang/mdBook) and [`mdbook-tera`](https://github.com/avitex/mdbook-tera) (for templating). @@ -87,8 +87,8 @@ License Licensed under either of the following, at your choice: -* [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or -* [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt) +* [Apache License, Version 2.0](https://github.com/rhaiscript/rhai/blob/master/LICENSE-APACHE.txt), or +* [MIT license](https://github.com/rhaiscript/rhai/blob/master/LICENSE-MIT.txt) Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate, as defined in the Apache-2.0 license, shall diff --git a/RELEASES.md b/RELEASES.md index e43a841c..517c82d0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -480,7 +480,7 @@ Version 0.16.0 The major new feature in this version is OOP - well, poor man's OOP, that is. -The `README` is officially transferred to [The Rhai Book](https://schungx.github.io/rhai). +The `README` is officially transferred to [The Rhai Book](https://rhaiscript.github.io/book). An online [Playground](https://alvinhochun.github.io/rhai-demo/) is available. @@ -505,7 +505,7 @@ New features Enhancements ------------ -* [The Rhai Book](https://schungx.github.io/rhai) is online. Most content in the original `README` was transferred to the Book. +* [The Rhai Book](https://rhaiscript.github.io/book) is online. Most content in the original `README` was transferred to the Book. * New feature `internals` to expose internal data structures (e.g. the AST nodes). diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 97d80523..073843b1 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -4,8 +4,8 @@ version = "0.3.1" edition = "2018" authors = ["jhwgh1968"] description = "Procedural macro support package for Rhai, a scripting language for Rust" -homepage = "https://schungx.github.io/rhai/plugins/index.html" -repository = "https://github.com/jonathandturner/rhai" +homepage = "https://rhaiscript.github.io/book/plugins/index.html" +repository = "https://github.com/rhaiscript/rhai" license = "MIT OR Apache-2.0" [lib] diff --git a/codegen/README.md b/codegen/README.md index 275c26eb..5099d3a4 100644 --- a/codegen/README.md +++ b/codegen/README.md @@ -2,4 +2,4 @@ Procedural Macros for Plugins ============================= This crate holds procedural macros for code generation, supporting the plugins system -for [Rhai](https://github.com/jonathandturner/rhai). +for [Rhai](https://github.com/rhaiscript/rhai). diff --git a/doc/README.md b/doc/README.md index 63d79bc4..bc521a4f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,7 +1,7 @@ The Rhai Book ============= -[_The Rhai Book_](https://schungx.github.io/rhai) serves as Rhai's primary +[_The Rhai Book_](https://rhaiscript.github.io/book) serves as Rhai's primary documentation and tutorial resource. @@ -33,9 +33,9 @@ Configuration Settings Settings stored in `context.json`: -| Setting | Description | -| ---------- | ------------------------------------------------------------------------------------------------- | -| `version` | version of Rhai | -| `repoHome` | points to the [root of the GitHub repo](https://github.com/jonathandturner/rhai/blob/master) | -| `repoTree` | points to the [root of the GitHub repo tree](https://github.com/jonathandturner/rhai/tree/master) | -| `rootUrl` | sub-directory for the root domain, e.g. `/rhai` | +| Setting | Description | +| ---------- | -------------------------------------------------------------------------------------------- | +| `version` | version of Rhai | +| `repoHome` | points to the [root of the GitHub repo](https://github.com/rhaiscript/rhai/blob/master) | +| `repoTree` | points to the [root of the GitHub repo tree](https://github.com/rhaiscript/rhai/tree/master) | +| `rootUrl` | sub-directory for the root domain, e.g. `/rhai` | diff --git a/doc/book.toml b/doc/book.toml index a48eadaf..d72fe611 100644 --- a/doc/book.toml +++ b/doc/book.toml @@ -6,7 +6,7 @@ language = "en" [output.html] no-section-label = true -git-repository-url = "https://github.com/jonathandturner/rhai" +git-repository-url = "https://github.com/rhaiscript/rhai" curly-quotes = true [output.html.fold] diff --git a/doc/src/about/related.md b/doc/src/about/related.md index 84af9824..cc6e2503 100644 --- a/doc/src/about/related.md +++ b/doc/src/about/related.md @@ -7,7 +7,7 @@ Related Resources Online Resources for Rhai ------------------------- -* [GitHub](https://github.com/jonathandturner/rhai) – Home repository +* [GitHub](https://github.com/rhaiscript/rhai) – Home repository * [`crates.io`](https://crates.io/crates/rhai) – Rhai crate diff --git a/doc/src/context.json b/doc/src/context.json index d19c1ac0..e3ba5b9b 100644 --- a/doc/src/context.json +++ b/doc/src/context.json @@ -1,7 +1,7 @@ { "version": "0.19.10", - "repoHome": "https://github.com/jonathandturner/rhai/blob/master", - "repoTree": "https://github.com/jonathandturner/rhai/tree/master", + "repoHome": "https://github.com/rhaiscript/rhai/blob/master", + "repoTree": "https://github.com/rhaiscript/rhai/tree/master", "rootUrl": "", "rootUrlX": "/rhai", "rootUrlXX": "/rhai/vnext" diff --git a/doc/src/patterns/multiple.md b/doc/src/patterns/multiple.md index e7806265..dad53501 100644 --- a/doc/src/patterns/multiple.md +++ b/doc/src/patterns/multiple.md @@ -47,18 +47,18 @@ a different [features] set, by their _sources_: * Different versions from [`crates.io`](https://crates.io/crates/rhai/) – The official crate. -* Different releases from [`GitHub`](https://github.com/jonathandturner/rhai) – Crate source on GitHub. +* Different releases from [`GitHub`](https://github.com/rhaiscript/rhai) – Crate source on GitHub. -* Forked copy of [https://github.com/jonathandturner/rhai](https://github.com/jonathandturner/rhai) on GitHub. +* Forked copy of [https://github.com/rhaiscript/rhai](https://github.com/rhaiscript/rhai) on GitHub. -* Local copy of [https://github.com/jonathandturner/rhai](https://github.com/jonathandturner/rhai) downloaded form GitHub. +* Local copy of [https://github.com/rhaiscript/rhai](https://github.com/rhaiscript/rhai) downloaded form GitHub. Use the following configuration in `Cargo.toml` to pull in multiple copies of Rhai within the same project: ```toml [dependencies] rhai = { version = "{{version}}", features = [ "no_float" ] } -rhai_github = { git = "https://github.com/jonathandturner/rhai", features = [ "unchecked" ] } +rhai_github = { git = "https://github.com/rhaiscript/rhai", features = [ "unchecked" ] } rhai_my_github = { git = "https://github.com/my_github/rhai", branch = "variation1", features = [ "serde", "no_closure" ] } rhai_local = { path = "../rhai_copy" } ``` diff --git a/doc/src/start/install.md b/doc/src/start/install.md index 007f6d63..18b75223 100644 --- a/doc/src/start/install.md +++ b/doc/src/start/install.md @@ -22,9 +22,9 @@ rhai = "*" Crate versions are released on [`crates.io`](https:/crates.io/crates/rhai/) infrequently, so to track the latest features, enhancements and bug fixes, pull directly from -[GitHub](https://github.com/jonathandturner/rhai): +[GitHub](https://github.com/rhaiscript/rhai): ```toml [dependencies] -rhai = { git = "https://github.com/jonathandturner/rhai" } +rhai = { git = "https://github.com/rhaiscript/rhai" } ``` diff --git a/no_std/no_std_test/Cargo.toml b/no_std/no_std_test/Cargo.toml index 1db56f57..6a85b79d 100644 --- a/no_std/no_std_test/Cargo.toml +++ b/no_std/no_std_test/Cargo.toml @@ -8,8 +8,8 @@ version = "0.1.0" edition = "2018" authors = ["Stephen Chung"] description = "no-std test application" -homepage = "https://github.com/jonathandturner/rhai/tree/no_std/no_std_test" -repository = "https://github.com/jonathandturner/rhai" +homepage = "https://github.com/rhaiscript/rhai/tree/no_std/no_std_test" +repository = "https://github.com/rhaiscript/rhai" [dependencies] rhai = { path = "../../", features = [ "no_std" ], default_features = false } diff --git a/src/lib.rs b/src/lib.rs index 14bc390d..fb28dcf1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! # Rhai - embedded scripting for Rust //! -//! ![Rhai logo](https://schungx.github.io/rhai/images/logo/rhai-banner-transparent-colour.svg) +//! ![Rhai logo](https://rhaiscript.github.io/book/images/logo/rhai-banner-transparent-colour.svg) //! //! Rhai is a tiny, simple and fast embedded scripting language for Rust //! that gives you a safe and easy way to add scripting to your applications. @@ -54,7 +54,7 @@ //! //! # Documentation //! -//! See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai scripting engine and language. +//! See [The Rhai Book](https://rhaiscript.github.io/book) for details on the Rhai scripting engine and language. #![cfg_attr(feature = "no_std", no_std)] diff --git a/tests/expressions.rs b/tests/expressions.rs index 771d1d02..e6c09b5c 100644 --- a/tests/expressions.rs +++ b/tests/expressions.rs @@ -26,7 +26,7 @@ fn test_expressions() -> Result<(), Box> { Ok(()) } -/// This example taken from https://github.com/jonathandturner/rhai/issues/115 +/// This example taken from https://github.com/rhaiscript/rhai/issues/115 #[test] #[cfg(not(feature = "no_object"))] fn test_expressions_eval() -> Result<(), Box> { From 9a037afbb9460c8d788ab02a8b260910d9cb6f01 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 7 Jan 2021 18:57:40 +0800 Subject: [PATCH 09/12] Remove book. --- doc/README.md | 41 -- doc/book.toml | 22 - doc/src/SUMMARY.md | 149 ----- doc/src/about/features.md | 79 --- doc/src/about/index.md | 46 -- doc/src/about/license.md | 14 - doc/src/about/non-design.md | 77 --- doc/src/about/related.md | 36 -- doc/src/about/targets.md | 18 - doc/src/advanced.md | 6 - doc/src/appendix/index.md | 6 - doc/src/appendix/keywords.md | 75 --- doc/src/appendix/literals.md | 16 - doc/src/appendix/operators.md | 74 --- doc/src/context.json | 8 - doc/src/engine/call-fn.md | 95 ---- doc/src/engine/compile.md | 27 - doc/src/engine/custom-op.md | 115 ---- doc/src/engine/custom-syntax.md | 404 -------------- doc/src/engine/disable.md | 28 - doc/src/engine/dsl.md | 92 ---- doc/src/engine/expressions.md | 27 - doc/src/engine/func.md | 43 -- doc/src/engine/hello-world.md | 60 --- doc/src/engine/index.md | 8 - doc/src/engine/metadata/export_to_json.md | 107 ---- doc/src/engine/metadata/gen_fn_sig.md | 91 ---- doc/src/engine/metadata/index.md | 28 - doc/src/engine/optimize/disable.md | 24 - doc/src/engine/optimize/eager.md | 26 - doc/src/engine/optimize/index.md | 146 ----- doc/src/engine/optimize/optimize-levels.md | 34 -- doc/src/engine/optimize/reoptimize.md | 38 -- doc/src/engine/optimize/semantics.md | 43 -- doc/src/engine/optimize/side-effects.md | 22 - doc/src/engine/optimize/volatility.md | 16 - doc/src/engine/options.md | 19 - doc/src/engine/raw.md | 28 - doc/src/engine/scope.md | 55 -- doc/src/engine/var.md | 93 ---- doc/src/images/logo/favicon.png | Bin 1238 -> 0 bytes doc/src/images/logo/favicon.svg | 15 - .../logo/rhai-banner-transparent-colour.png | Bin 22200 -> 0 bytes .../logo/rhai-banner-transparent-colour.svg | 31 -- doc/src/images/logo/rhai-colour-black.png | Bin 23348 -> 0 bytes doc/src/images/logo/rhai-colour-black.svg | 39 -- doc/src/images/logo/rhai-colour-white.png | Bin 23363 -> 0 bytes doc/src/images/logo/rhai-colour-white.svg | 34 -- .../images/logo/rhai-icon-colour-black.png | Bin 17621 -> 0 bytes .../images/logo/rhai-icon-colour-black.svg | 23 - .../images/logo/rhai-icon-colour-white.png | Bin 17375 -> 0 bytes .../images/logo/rhai-icon-colour-white.svg | 23 - .../logo/rhai-icon-transparent-black.png | Bin 3991 -> 0 bytes .../logo/rhai-icon-transparent-black.svg | 11 - .../logo/rhai-icon-transparent-colour.png | Bin 15548 -> 0 bytes .../logo/rhai-icon-transparent-colour.svg | 14 - .../logo/rhai-icon-transparent-white.png | Bin 4496 -> 0 bytes .../logo/rhai-icon-transparent-white.svg | 11 - .../rhai-logo-transparent-colour-black.png | Bin 20505 -> 0 bytes .../rhai-logo-transparent-colour-black.svg | 28 - .../rhai-logo-transparent-colour-white.png | Bin 20664 -> 0 bytes .../rhai-logo-transparent-colour-white.svg | 28 - .../logo/rhai-logo-transparent-sil-black.png | Bin 7392 -> 0 bytes .../logo/rhai-logo-transparent-sil-black.svg | 25 - .../logo/rhai-logo-transparent-sil-white.png | Bin 8310 -> 0 bytes .../logo/rhai-logo-transparent-sil-white.svg | 25 - doc/src/images/logo/rhai-sil-black.png | Bin 11249 -> 0 bytes doc/src/images/logo/rhai-sil-black.svg | 36 -- doc/src/images/logo/rhai-sil-white.png | Bin 12297 -> 0 bytes doc/src/images/logo/rhai-sil-white.svg | 29 - doc/src/language/arrays.md | 218 -------- doc/src/language/assignment-op.md | 66 --- doc/src/language/comments.md | 24 - doc/src/language/constants.md | 97 ---- doc/src/language/convert.md | 56 -- doc/src/language/do.md | 28 - doc/src/language/doc-comments.md | 77 --- doc/src/language/dynamic.md | 100 ---- doc/src/language/eval.md | 83 --- doc/src/language/fn-anon.md | 60 --- doc/src/language/fn-capture.md | 71 --- doc/src/language/fn-closure.md | 192 ------- doc/src/language/fn-curry.md | 39 -- doc/src/language/fn-namespaces.md | 119 ---- doc/src/language/fn-ptr.md | 271 ---------- doc/src/language/for.md | 103 ---- doc/src/language/functions.md | 190 ------- doc/src/language/if.md | 51 -- doc/src/language/index.md | 7 - doc/src/language/iterator.md | 45 -- doc/src/language/json.md | 95 ---- doc/src/language/keywords.md | 26 - doc/src/language/logic.md | 78 --- doc/src/language/loop.md | 26 - doc/src/language/method.md | 95 ---- doc/src/language/modules/export.md | 98 ---- doc/src/language/modules/import.md | 113 ---- doc/src/language/modules/index.md | 14 - doc/src/language/num-fn.md | 46 -- doc/src/language/num-op.md | 51 -- doc/src/language/numbers.md | 22 - doc/src/language/object-maps-oop.md | 39 -- doc/src/language/object-maps.md | 169 ------ doc/src/language/overload.md | 29 - doc/src/language/print-debug.md | 72 --- doc/src/language/return.md | 16 - doc/src/language/statements.md | 42 -- doc/src/language/string-fn.md | 65 --- doc/src/language/strings-chars.md | 133 ----- doc/src/language/switch.md | 111 ---- doc/src/language/throw.md | 52 -- doc/src/language/timestamps.md | 40 -- doc/src/language/try-catch.md | 108 ---- doc/src/language/type-of.md | 47 -- doc/src/language/values-and-types.md | 42 -- doc/src/language/variables.md | 68 --- doc/src/language/while.md | 20 - doc/src/links.md | 147 ----- doc/src/patterns/config.md | 163 ------ doc/src/patterns/control.md | 144 ----- doc/src/patterns/dynamic-const.md | 56 -- doc/src/patterns/enums.md | 237 -------- doc/src/patterns/events.md | 202 ------- doc/src/patterns/index.md | 7 - doc/src/patterns/multi-layer.md | 117 ---- doc/src/patterns/multiple.md | 89 --- doc/src/patterns/oop.md | 109 ---- doc/src/patterns/parallel.md | 75 --- doc/src/patterns/singleton.md | 175 ------ doc/src/plugins/function.md | 156 ------ doc/src/plugins/index.md | 13 - doc/src/plugins/module.md | 507 ------------------ doc/src/rust/custom.md | 200 ------- doc/src/rust/disable-custom.md | 18 - doc/src/rust/fallible.md | 41 -- doc/src/rust/functions.md | 73 --- doc/src/rust/generic.md | 30 -- doc/src/rust/getters-setters.md | 69 --- doc/src/rust/index.md | 9 - doc/src/rust/indexers.md | 82 --- doc/src/rust/modules/ast.md | 80 --- doc/src/rust/modules/create.md | 158 ------ doc/src/rust/modules/imp-resolver.md | 72 --- doc/src/rust/modules/index.md | 29 - doc/src/rust/modules/resolvers.md | 181 ------- doc/src/rust/operators.md | 74 --- doc/src/rust/override.md | 22 - doc/src/rust/packages/builtin.md | 40 -- doc/src/rust/packages/create.md | 130 ----- doc/src/rust/packages/index.md | 58 -- doc/src/rust/print-custom.md | 18 - doc/src/rust/register-raw.md | 189 ------- doc/src/rust/serde.md | 126 ----- doc/src/rust/strings.md | 43 -- doc/src/rust/traits.md | 14 - doc/src/safety/checked.md | 11 - doc/src/safety/index.md | 45 -- doc/src/safety/max-array-size.md | 40 -- doc/src/safety/max-call-stack.md | 31 -- doc/src/safety/max-map-size.md | 40 -- doc/src/safety/max-modules.md | 26 - doc/src/safety/max-operations.md | 44 -- doc/src/safety/max-stmt-depth.md | 56 -- doc/src/safety/max-string-size.md | 36 -- doc/src/safety/progress.md | 52 -- doc/src/safety/sandbox.md | 39 -- doc/src/start/bin.md | 59 -- doc/src/start/builds/index.md | 7 - doc/src/start/builds/minimal.md | 54 -- doc/src/start/builds/no-std.md | 79 --- doc/src/start/builds/performance.md | 61 --- doc/src/start/builds/wasm.md | 55 -- doc/src/start/examples/index.md | 7 - doc/src/start/examples/rust.md | 45 -- doc/src/start/examples/scripts.md | 53 -- doc/src/start/features.md | 68 --- doc/src/start/index.md | 6 - doc/src/start/install.md | 30 -- doc/src/start/playground.md | 10 - doc/src/tools/index.md | 6 - doc/src/tools/playground.md | 15 - doc/src/tools/rhai-doc.md | 6 - doc/theme/favicon.png | Bin 1238 -> 0 bytes doc/theme/favicon.svg | 12 - 184 files changed, 11268 deletions(-) delete mode 100644 doc/README.md delete mode 100644 doc/book.toml delete mode 100644 doc/src/SUMMARY.md delete mode 100644 doc/src/about/features.md delete mode 100644 doc/src/about/index.md delete mode 100644 doc/src/about/license.md delete mode 100644 doc/src/about/non-design.md delete mode 100644 doc/src/about/related.md delete mode 100644 doc/src/about/targets.md delete mode 100644 doc/src/advanced.md delete mode 100644 doc/src/appendix/index.md delete mode 100644 doc/src/appendix/keywords.md delete mode 100644 doc/src/appendix/literals.md delete mode 100644 doc/src/appendix/operators.md delete mode 100644 doc/src/context.json delete mode 100644 doc/src/engine/call-fn.md delete mode 100644 doc/src/engine/compile.md delete mode 100644 doc/src/engine/custom-op.md delete mode 100644 doc/src/engine/custom-syntax.md delete mode 100644 doc/src/engine/disable.md delete mode 100644 doc/src/engine/dsl.md delete mode 100644 doc/src/engine/expressions.md delete mode 100644 doc/src/engine/func.md delete mode 100644 doc/src/engine/hello-world.md delete mode 100644 doc/src/engine/index.md delete mode 100644 doc/src/engine/metadata/export_to_json.md delete mode 100644 doc/src/engine/metadata/gen_fn_sig.md delete mode 100644 doc/src/engine/metadata/index.md delete mode 100644 doc/src/engine/optimize/disable.md delete mode 100644 doc/src/engine/optimize/eager.md delete mode 100644 doc/src/engine/optimize/index.md delete mode 100644 doc/src/engine/optimize/optimize-levels.md delete mode 100644 doc/src/engine/optimize/reoptimize.md delete mode 100644 doc/src/engine/optimize/semantics.md delete mode 100644 doc/src/engine/optimize/side-effects.md delete mode 100644 doc/src/engine/optimize/volatility.md delete mode 100644 doc/src/engine/options.md delete mode 100644 doc/src/engine/raw.md delete mode 100644 doc/src/engine/scope.md delete mode 100644 doc/src/engine/var.md delete mode 100644 doc/src/images/logo/favicon.png delete mode 100644 doc/src/images/logo/favicon.svg delete mode 100644 doc/src/images/logo/rhai-banner-transparent-colour.png delete mode 100644 doc/src/images/logo/rhai-banner-transparent-colour.svg delete mode 100644 doc/src/images/logo/rhai-colour-black.png delete mode 100644 doc/src/images/logo/rhai-colour-black.svg delete mode 100644 doc/src/images/logo/rhai-colour-white.png delete mode 100644 doc/src/images/logo/rhai-colour-white.svg delete mode 100644 doc/src/images/logo/rhai-icon-colour-black.png delete mode 100644 doc/src/images/logo/rhai-icon-colour-black.svg delete mode 100644 doc/src/images/logo/rhai-icon-colour-white.png delete mode 100644 doc/src/images/logo/rhai-icon-colour-white.svg delete mode 100644 doc/src/images/logo/rhai-icon-transparent-black.png delete mode 100644 doc/src/images/logo/rhai-icon-transparent-black.svg delete mode 100644 doc/src/images/logo/rhai-icon-transparent-colour.png delete mode 100644 doc/src/images/logo/rhai-icon-transparent-colour.svg delete mode 100644 doc/src/images/logo/rhai-icon-transparent-white.png delete mode 100644 doc/src/images/logo/rhai-icon-transparent-white.svg delete mode 100644 doc/src/images/logo/rhai-logo-transparent-colour-black.png delete mode 100644 doc/src/images/logo/rhai-logo-transparent-colour-black.svg delete mode 100644 doc/src/images/logo/rhai-logo-transparent-colour-white.png delete mode 100644 doc/src/images/logo/rhai-logo-transparent-colour-white.svg delete mode 100644 doc/src/images/logo/rhai-logo-transparent-sil-black.png delete mode 100644 doc/src/images/logo/rhai-logo-transparent-sil-black.svg delete mode 100644 doc/src/images/logo/rhai-logo-transparent-sil-white.png delete mode 100644 doc/src/images/logo/rhai-logo-transparent-sil-white.svg delete mode 100644 doc/src/images/logo/rhai-sil-black.png delete mode 100644 doc/src/images/logo/rhai-sil-black.svg delete mode 100644 doc/src/images/logo/rhai-sil-white.png delete mode 100644 doc/src/images/logo/rhai-sil-white.svg delete mode 100644 doc/src/language/arrays.md delete mode 100644 doc/src/language/assignment-op.md delete mode 100644 doc/src/language/comments.md delete mode 100644 doc/src/language/constants.md delete mode 100644 doc/src/language/convert.md delete mode 100644 doc/src/language/do.md delete mode 100644 doc/src/language/doc-comments.md delete mode 100644 doc/src/language/dynamic.md delete mode 100644 doc/src/language/eval.md delete mode 100644 doc/src/language/fn-anon.md delete mode 100644 doc/src/language/fn-capture.md delete mode 100644 doc/src/language/fn-closure.md delete mode 100644 doc/src/language/fn-curry.md delete mode 100644 doc/src/language/fn-namespaces.md delete mode 100644 doc/src/language/fn-ptr.md delete mode 100644 doc/src/language/for.md delete mode 100644 doc/src/language/functions.md delete mode 100644 doc/src/language/if.md delete mode 100644 doc/src/language/index.md delete mode 100644 doc/src/language/iterator.md delete mode 100644 doc/src/language/json.md delete mode 100644 doc/src/language/keywords.md delete mode 100644 doc/src/language/logic.md delete mode 100644 doc/src/language/loop.md delete mode 100644 doc/src/language/method.md delete mode 100644 doc/src/language/modules/export.md delete mode 100644 doc/src/language/modules/import.md delete mode 100644 doc/src/language/modules/index.md delete mode 100644 doc/src/language/num-fn.md delete mode 100644 doc/src/language/num-op.md delete mode 100644 doc/src/language/numbers.md delete mode 100644 doc/src/language/object-maps-oop.md delete mode 100644 doc/src/language/object-maps.md delete mode 100644 doc/src/language/overload.md delete mode 100644 doc/src/language/print-debug.md delete mode 100644 doc/src/language/return.md delete mode 100644 doc/src/language/statements.md delete mode 100644 doc/src/language/string-fn.md delete mode 100644 doc/src/language/strings-chars.md delete mode 100644 doc/src/language/switch.md delete mode 100644 doc/src/language/throw.md delete mode 100644 doc/src/language/timestamps.md delete mode 100644 doc/src/language/try-catch.md delete mode 100644 doc/src/language/type-of.md delete mode 100644 doc/src/language/values-and-types.md delete mode 100644 doc/src/language/variables.md delete mode 100644 doc/src/language/while.md delete mode 100644 doc/src/links.md delete mode 100644 doc/src/patterns/config.md delete mode 100644 doc/src/patterns/control.md delete mode 100644 doc/src/patterns/dynamic-const.md delete mode 100644 doc/src/patterns/enums.md delete mode 100644 doc/src/patterns/events.md delete mode 100644 doc/src/patterns/index.md delete mode 100644 doc/src/patterns/multi-layer.md delete mode 100644 doc/src/patterns/multiple.md delete mode 100644 doc/src/patterns/oop.md delete mode 100644 doc/src/patterns/parallel.md delete mode 100644 doc/src/patterns/singleton.md delete mode 100644 doc/src/plugins/function.md delete mode 100644 doc/src/plugins/index.md delete mode 100644 doc/src/plugins/module.md delete mode 100644 doc/src/rust/custom.md delete mode 100644 doc/src/rust/disable-custom.md delete mode 100644 doc/src/rust/fallible.md delete mode 100644 doc/src/rust/functions.md delete mode 100644 doc/src/rust/generic.md delete mode 100644 doc/src/rust/getters-setters.md delete mode 100644 doc/src/rust/index.md delete mode 100644 doc/src/rust/indexers.md delete mode 100644 doc/src/rust/modules/ast.md delete mode 100644 doc/src/rust/modules/create.md delete mode 100644 doc/src/rust/modules/imp-resolver.md delete mode 100644 doc/src/rust/modules/index.md delete mode 100644 doc/src/rust/modules/resolvers.md delete mode 100644 doc/src/rust/operators.md delete mode 100644 doc/src/rust/override.md delete mode 100644 doc/src/rust/packages/builtin.md delete mode 100644 doc/src/rust/packages/create.md delete mode 100644 doc/src/rust/packages/index.md delete mode 100644 doc/src/rust/print-custom.md delete mode 100644 doc/src/rust/register-raw.md delete mode 100644 doc/src/rust/serde.md delete mode 100644 doc/src/rust/strings.md delete mode 100644 doc/src/rust/traits.md delete mode 100644 doc/src/safety/checked.md delete mode 100644 doc/src/safety/index.md delete mode 100644 doc/src/safety/max-array-size.md delete mode 100644 doc/src/safety/max-call-stack.md delete mode 100644 doc/src/safety/max-map-size.md delete mode 100644 doc/src/safety/max-modules.md delete mode 100644 doc/src/safety/max-operations.md delete mode 100644 doc/src/safety/max-stmt-depth.md delete mode 100644 doc/src/safety/max-string-size.md delete mode 100644 doc/src/safety/progress.md delete mode 100644 doc/src/safety/sandbox.md delete mode 100644 doc/src/start/bin.md delete mode 100644 doc/src/start/builds/index.md delete mode 100644 doc/src/start/builds/minimal.md delete mode 100644 doc/src/start/builds/no-std.md delete mode 100644 doc/src/start/builds/performance.md delete mode 100644 doc/src/start/builds/wasm.md delete mode 100644 doc/src/start/examples/index.md delete mode 100644 doc/src/start/examples/rust.md delete mode 100644 doc/src/start/examples/scripts.md delete mode 100644 doc/src/start/features.md delete mode 100644 doc/src/start/index.md delete mode 100644 doc/src/start/install.md delete mode 100644 doc/src/start/playground.md delete mode 100644 doc/src/tools/index.md delete mode 100644 doc/src/tools/playground.md delete mode 100644 doc/src/tools/rhai-doc.md delete mode 100644 doc/theme/favicon.png delete mode 100644 doc/theme/favicon.svg diff --git a/doc/README.md b/doc/README.md deleted file mode 100644 index bc521a4f..00000000 --- a/doc/README.md +++ /dev/null @@ -1,41 +0,0 @@ -The Rhai Book -============= - -[_The Rhai Book_](https://rhaiscript.github.io/book) serves as Rhai's primary -documentation and tutorial resource. - - -How to Build from Source ------------------------- - -* Install [`mdbook`](https://github.com/rust-lang/mdBook): - -```bash -cargo install mdbook -``` - -* Install [`mdbook-tera`](https://github.com/avitex/mdbook-tera) (for templating): - -```bash -cargo install mdbook-tera -``` - -* Run build in source directory: - -```bash -cd doc -mdbook build -``` - - -Configuration Settings ----------------------- - -Settings stored in `context.json`: - -| Setting | Description | -| ---------- | -------------------------------------------------------------------------------------------- | -| `version` | version of Rhai | -| `repoHome` | points to the [root of the GitHub repo](https://github.com/rhaiscript/rhai/blob/master) | -| `repoTree` | points to the [root of the GitHub repo tree](https://github.com/rhaiscript/rhai/tree/master) | -| `rootUrl` | sub-directory for the root domain, e.g. `/rhai` | diff --git a/doc/book.toml b/doc/book.toml deleted file mode 100644 index d72fe611..00000000 --- a/doc/book.toml +++ /dev/null @@ -1,22 +0,0 @@ -[book] -title = "Rhai - Embedded Scripting for Rust" -authors = ["Jonathan Turner", "Stephen Chung"] -description = "Tutorial and reference on the Rhai scripting engine and language." -language = "en" - -[output.html] -no-section-label = true -git-repository-url = "https://github.com/rhaiscript/rhai" -curly-quotes = true - -[output.html.fold] -enable = true -level = 4 - -[outputX.linkcheck] -follow-web-links = false -traverse-parent-directories = false -warning-policy = "ignore" - -[preprocessor.tera] -command = "mdbook-tera --json ./src/context.json" diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md deleted file mode 100644 index 0f16501f..00000000 --- a/doc/src/SUMMARY.md +++ /dev/null @@ -1,149 +0,0 @@ -The Rhai Scripting Language -========================== - -1. [What is Rhai](about/index.md) - 1. [Features](about/features.md) - 2. [Supported Targets and Builds](about/targets.md) - 3. [What Rhai Isn't](about/non-design.md) - 4. [Licensing](about/license.md) - 5. [Related Resources](about/related.md) -2. [Getting Started](start/index.md) - 1. [Online Playground](start/playground.md) - 2. [Install the Rhai Crate](start/install.md) - 3. [Optional Features](start/features.md) - 4. [Special Builds](start/builds/index.md) - 1. [Performance](start/builds/performance.md) - 2. [Minimal](start/builds/minimal.md) - 3. [no-std](start/builds/no-std.md) - 4. [WebAssembly (WASM)](start/builds/wasm.md) - 5. [Packaged Utilities](start/bin.md) - 6. [Examples](start/examples/index.md) - 1. [Rust](start/examples/rust.md) - 2. [Scripts](start/examples/scripts.md) -3. [Using the `Engine`](engine/index.md) - 1. [Hello World in Rhai – Evaluate a Script](engine/hello-world.md) - 2. [Compile to AST for Repeated Evaluations](engine/compile.md) - 3. [Call a Rhai Function from Rust](engine/call-fn.md) - 4. [Create a Rust Closure from a Rhai Function](engine/func.md) - 5. [Evaluate Expressions Only](engine/expressions.md) - 6. [Raw Engine](engine/raw.md) - 7. [Scope – Initializing and Maintaining State](engine/scope.md) - 8. [Engine Configuration Options](engine/options.md) -4. [Extend Rhai with Rust](rust/index.md) - 1. [Traits](rust/traits.md) - 2. [Register a Rust Function](rust/functions.md) - 1. [String Parameters in Rust Functions](rust/strings.md) - 3. [Register a Generic Rust Function](rust/generic.md) - 4. [Register a Fallible Rust Function](rust/fallible.md) - 5. [Override a Built-in Function](rust/override.md) - 6. [Operator Overloading](rust/operators.md) - 7. [Register any Rust Type and its Methods](rust/custom.md) - 1. [Property Getters and Setters](rust/getters-setters.md) - 2. [Indexers](rust/indexers.md) - 3. [Disable Custom Types](rust/disable-custom.md) - 4. [Printing Custom Types](rust/print-custom.md) - 8. [Modules](rust/modules/index.md) - 1. [Create from Rust](rust/modules/create.md) - 2. [Create from AST](rust/modules/ast.md) - 3. [Module Resolvers](rust/modules/resolvers.md) - 1. [Custom Module Resolvers](rust/modules/imp-resolver.md) - 9. [Plugins](plugins/index.md) - 1. [Export a Rust Module](plugins/module.md) - 2. [Export a Rust Function](plugins/function.md) - 10. [Packages](rust/packages/index.md) - 1. [Built-in Packages](rust/packages/builtin.md) - 2. [Custom Packages](rust/packages/create.md) -5. [Rhai Language Reference](language/index.md) - 1. [Comments](language/comments.md) - 1. [Doc-Comments](language/doc-comments.md) - 2. [Values and Types](language/values-and-types.md) - 1. [Dynamic Values](language/dynamic.md) - 2. [Serialization/Deserialization with `serde`](rust/serde.md) - 3. [type_of()](language/type-of.md) - 4. [Numbers](language/numbers.md) - 1. [Operators](language/num-op.md) - 2. [Functions](language/num-fn.md) - 3. [Value Conversions](language/convert.md) - 5. [Strings and Characters](language/strings-chars.md) - 1. [Built-in Functions](language/string-fn.md) - 6. [Arrays](language/arrays.md) - 7. [Object Maps](language/object-maps.md) - 1. [Parse from JSON](language/json.md) - 2. [Special Support for OOP](language/object-maps-oop.md) - 8. [Time-Stamps](language/timestamps.md) - 3. [Keywords](language/keywords.md) - 4. [Statements](language/statements.md) - 5. [Variables](language/variables.md) - 6. [Constants](language/constants.md) - 7. [Logic Operators](language/logic.md) - 8. [Assignment Operators](language/assignment-op.md) - 9. [If Statement](language/if.md) - 10. [Switch Expression](language/switch.md) - 11. [While Loop](language/while.md) - 12. [Do Loop](language/do.md) - 13. [Loop Statement](language/loop.md) - 14. [For Loop](language/for.md) - 1. [Iterators for Custom Types](language/iterator.md) - 15. [Return Values](language/return.md) - 16. [Throw Exception on Error](language/throw.md) - 17. [Catch Exceptions](language/try-catch.md) - 18. [Functions](language/functions.md) - 1. [Call Method as Function](language/method.md) - 2. [Overloading](language/overload.md) - 3. [Namespaces](language/fn-namespaces.md) - 4. [Function Pointers](language/fn-ptr.md) - 5. [Currying](language/fn-curry.md) - 6. [Anonymous Functions](language/fn-anon.md) - 7. [Closures](language/fn-closure.md) - 19. [Print and Debug](language/print-debug.md) - 20. [Modules](language/modules/index.md) - 1. [Export Variables, Functions and Sub-Modules](language/modules/export.md) - 2. [Import Modules](language/modules/import.md) - 21. [Eval Function](language/eval.md) -6. [Safety and Protection](safety/index.md) - 1. [Checked Arithmetic](safety/checked.md) - 2. [Sand-Boxing](safety/sandbox.md) - 3. [Maximum Length of Strings](safety/max-string-size.md) - 4. [Maximum Size of Arrays](safety/max-array-size.md) - 5. [Maximum Size of Object Maps](safety/max-map-size.md) - 6. [Maximum Number of Operations](safety/max-operations.md) - 1. [Tracking Progress and Force-Termination](safety/progress.md) - 7. [Maximum Number of Modules](safety/max-modules.md) - 8. [Maximum Call Stack Depth](safety/max-call-stack.md) - 9. [Maximum Statement Depth](safety/max-stmt-depth.md) -7. [Script Optimization](engine/optimize/index.md) - 1. [Optimization Levels](engine/optimize/optimize-levels.md) - 2. [Re-Optimize an AST](engine/optimize/reoptimize.md) - 3. [Eager Function Evaluation](engine/optimize/eager.md) - 4. [Side-Effect Considerations](engine/optimize/side-effects.md) - 5. [Volatility Considerations](engine/optimize/volatility.md) - 6. [Subtle Semantic Changes](engine/optimize/semantics.md) -8. [Usage Patterns](patterns/index.md) - 1. [Object-Oriented Programming (OOP)](patterns/oop.md) - 2. [Working With Rust Enums](patterns/enums.md) - 3. [Loadable Configuration](patterns/config.md) - 4. [Control Layer](patterns/control.md) - 5. [Singleton Command](patterns/singleton.md) - 6. [Multi-Layer Functions](patterns/multi-layer.md) - 7. [One Engine Instance Per Call](patterns/parallel.md) - 8. [Scriptable Event Handler with State](patterns/events.md) - 9. [Dynamic Constants Provider](patterns/dynamic-const.md) -9. [Advanced Topics](advanced.md) - 1. [Capture Scope for Function Call](language/fn-capture.md) - 2. [Low-Level API](rust/register-raw.md) - 3. [Variable Resolver](engine/var.md) - 4. [Use as DSL](engine/dsl.md) - 1. [Disable Keywords and/or Operators](engine/disable.md) - 2. [Custom Operators](engine/custom-op.md) - 3. [Extending with Custom Syntax](engine/custom-syntax.md) - 5. [Multiple Instantiation](patterns/multiple.md) - 6. [Functions Metadata](engine/metadata/index.md) - 1. [Generate Function Signatures](engine/metadata/gen_fn_sig.md) - 2. [Export Metadata to JSON](engine/metadata/export_to_json.md) -10. [External Tools](tools/index.md) - 1. [Online Playground](tools/playground.md) - 2. [`rhai-doc`](tools/rhai-doc.md) -11. [Appendix](appendix/index.md) - 1. [Keywords](appendix/keywords.md) - 2. [Operators and Symbols](appendix/operators.md) - 3. [Literals](appendix/literals.md) diff --git a/doc/src/about/features.md b/doc/src/about/features.md deleted file mode 100644 index 597f6677..00000000 --- a/doc/src/about/features.md +++ /dev/null @@ -1,79 +0,0 @@ -Features -======== - -{{#include ../links.md}} - -Easy ----- - -* Easy-to-use language similar to JavaScript+Rust with dynamic typing. - -* Tight integration with native Rust [functions] and [types][custom types] including [getters/setters], - [methods][custom type] and [indexers]. - -* Freely pass Rust variables/constants into a script via an external [`Scope`] – all clonable Rust types are supported seamlessly - without the need to implement any special trait. - -* Easily [call a script-defined function]({{rootUrl}}/engine/call-fn.md) from Rust. - -* Very few additional dependencies – right now only [`smallvec`](https://crates.io/crates/smallvec/) plus crates for procedural macros; - for [`no-std`] and `WASM` builds, a number of additional dependencies are pulled in to provide for missing functionalities. - -* [Plugins] system powered by procedural macros simplifies custom API development. - -Fast ----- - -* Fairly low compile-time overhead. - -* Fairly efficient evaluation (1 million iterations in 0.3 sec on a single core, 2.3 GHz Linux VM). - -* Scripts are [optimized][script optimization] (useful for template-based machine-generated scripts) for repeated evaluations. - -Dynamic -------- - -* [Function overloading]({{rootUrl}}/language/overload.md). - -* [Operator overloading]({{rootUrl}}/rust/operators.md). - -* Organize code base with dynamically-loadable [modules]. - -* Dynamic dispatch via [function pointers] with additional support for [currying]. - -* [Closures] that can capture shared variables. - -* Some support for [object-oriented programming (OOP)][OOP]. - -* Hook into variables access via [variable resolver]. - -Safe ----- - -* Relatively little `unsafe` code (yes there are some for performance reasons). - -* Sand-boxed – the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless - [explicitly permitted]({{rootUrl}}/patterns/control.md). - -Rugged ------- - -* Protected against malicious attacks (such as [stack-overflow][maximum call stack depth], [over-sized data][maximum length of strings], - and [runaway scripts][maximum number of operations] etc.) that may come from untrusted third-party user-land scripts. - -* Track script evaluation [progress] and manually terminate a script run. - -Flexible --------- - -* Re-entrant scripting [`Engine`] can be made `Send + Sync` (via the [`sync`] feature). - -* Serialization/deserialization support via [`serde`](https://crates.io/crates/serde). - -* Support for [minimal builds] by excluding unneeded language [features]. - -* Supports [most build targets](targets.md) including `no-std` and [WASM]. - -* Surgically [disable keywords and operators] to restrict the language. - -* Use as a [DSL] by defining [custom operators] and/or extending the language with [custom syntax]. diff --git a/doc/src/about/index.md b/doc/src/about/index.md deleted file mode 100644 index f316698d..00000000 --- a/doc/src/about/index.md +++ /dev/null @@ -1,46 +0,0 @@ -What is Rhai -============ - -{{#include ../links.md}} - -![Rhai Logo]({{rootUrl}}/images/logo/rhai-banner-transparent-colour.svg) - -Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way -to add scripting to any application. - - -Versions --------- - -This Book is for version **{{version}}** of Rhai. - -{% if rootUrl != "" and not rootUrl is ending_with("vnext") %} -For the latest development version, see [here]({{rootUrl}}/vnext/). -{% endif %} - - -Etymology of the name "Rhai" ---------------------------- - -### As per Rhai's author Johnathan Turner - -In the beginning there was [ChaiScript](http://chaiscript.com), -which is an embedded scripting language for C++. -Originally it was intended to be a scripting language similar to **JavaScript**. - -With java being a kind of hot beverage, the new language was named after -another hot beverage – **Chai**, which is the word for "tea" in many world languages -and, in particular, a popular kind of milk tea consumed in India. - -Later, when the novel implementation technique behind ChaiScript was ported from C++ to Rust, -logically the `C` was changed to an `R` to make it "RhaiScript", or just "Rhai". - -### On the origin of the semi-official Rhai logo - -One of Rhai's maintainers, [Stephen Chung](https://github.com/schungx), was thinking about a logo when he accidentally -came across a copy of _Catcher in the Rye_ in a restaurant, and drew the first version -of the logo. - -Then [`@semirix`](https://github.com/semirix) refined it to the current version. - -The plan is to make the logo official together with a `1.0` release. diff --git a/doc/src/about/license.md b/doc/src/about/license.md deleted file mode 100644 index 8465ec4c..00000000 --- a/doc/src/about/license.md +++ /dev/null @@ -1,14 +0,0 @@ -Licensing -========= - -{{#include ../links.md}} - -Rhai is licensed under either of the following, at your choice: - -* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or - -* [MIT license]({{repoHome}}/LICENSE-MIT.txt). - -Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate, -as defined in the Apache-2.0 license, shall be dual-licensed as above, -without any additional terms or conditions. diff --git a/doc/src/about/non-design.md b/doc/src/about/non-design.md deleted file mode 100644 index aa39f465..00000000 --- a/doc/src/about/non-design.md +++ /dev/null @@ -1,77 +0,0 @@ -What Rhai Isn't -=============== - -{{#include ../links.md}} - -Rhai's purpose is to provide a dynamic layer over Rust code, in the same spirit of _zero cost abstractions_. -It doesn't attempt to be a new language. For example: - -* **No classes**. Well, Rust doesn't either. On the other hand... - -* **No traits**... so it is also not Rust. Do your Rusty stuff in Rust. - -* **No structures/records/tuples** – define your types in Rust instead; Rhai can seamlessly work with _any Rust type_. - - There is, however, a built-in [object map] type which is adequate for most uses. - It is possible to simulate [object-oriented programming (OOP)][OOP] by storing [function pointers] - or [closures] in [object map] properties, turning them into _methods_. - -* **No first-class functions** – Code your functions in Rust instead, and register them with Rhai. - - There is, however, support for simple [function pointers] to allow runtime dispatch by function name. - -* **No garbage collection** – this should be expected, so... - -* **No first-class closures** – do your closure magic in Rust instead: [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md). - - There is, however, support for simulated [closures] via [currying] a [function pointer] with - captured shared variables. - -* **No byte-codes/JIT** – Rhai has an optimized AST-walking interpreter which is fast enough for most casual - usage scenarios. Essential AST data structures are packed and kept together to maximize cache friendliness. - - Functions are dispatched based on pre-calculated hashes and accessing variables are mostly through pre-calculated - offsets to the variables file (a [`Scope`]), so it is seldom necessary to look something up by text name. - - In addition, Rhai's design deliberately avoids maintaining a _scope chain_ so function scopes do not - pay any speed penalty. This particular design also allows variables data to be kept together in a contiguous - block, avoiding allocations and fragmentation while being cache-friendly. In a typical script evaluation run, - no data is shared and nothing is locked. - - Still, the purpose of Rhai is not to be super _fast_, but to make it as easy and versatile as possible to - integrate with native Rust applications. - -* **No formal language grammar** – Rhai uses a hand-coded lexer, a hand-coded top-down recursive-descent parser - for statements, and a hand-coded Pratt parser for expressions. - - This lack of formalism allows the _tokenizer_ and _parser_ themselves to be exposed as services in order - to support [disabling keywords/operators][disable keywords and operators], adding [custom operators], - and defining [custom syntax]. - - -Do Not Write The Next 4D VR Game in Rhai ---------------------------------------- - -Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting -advanced language features such as classes, inheritance, interfaces, generics, -first-class functions/closures, pattern matching, concurrency, byte-codes VM, JIT etc. -Focus is on _flexibility_ and _ease of use_ instead of raw speed. - -Avoid the temptation to write full-fledge application logic entirely in Rhai - -that use case is best fulfilled by more complete languages such as JavaScript or Lua. - - -Thin Dynamic Wrapper Layer Over Rust Code ----------------------------------------- - -In actual practice, it is usually best to expose a Rust API into Rhai for scripts to call. - -All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer. - -This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ -standard library. - -Another similar scenario is a web front-end driving back-end services written in a systems language. -In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust. -Except that Rhai integrates with Rust _much_ more tightly, removing the need for interfaces such -as XHR calls and payload encoding such as JSON. diff --git a/doc/src/about/related.md b/doc/src/about/related.md deleted file mode 100644 index cc6e2503..00000000 --- a/doc/src/about/related.md +++ /dev/null @@ -1,36 +0,0 @@ -Related Resources -================= - -{{#include ../links.md}} - - -Online Resources for Rhai -------------------------- - -* [GitHub](https://github.com/rhaiscript/rhai) – Home repository - -* [`crates.io`](https://crates.io/crates/rhai) – Rhai crate - -* [`DOCS.RS`](https://docs.rs/rhai) – Rhai API documentation - -* [`LIB.RS`](https://lib.rs/crates/rhai) – Rhai library info - -* [Discord Chat](https://discord.gg/HquqbYFcZ9) – Rhai channel - -* [Reddit](https://www.reddit.com/r/Rhai) – Rhai community - - -External Tools --------------- - -* [Online Playground][playground] – Run Rhai scripts directly from an editor in the browser - -* [`rhai-doc`] – Rhai script documentation tool - - -Other Cool Projects -------------------- - -* [ChaiScript](http://chaiscript.com) – A strong inspiration for Rhai. An embedded scripting language for C++. - -* Check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust) diff --git a/doc/src/about/targets.md b/doc/src/about/targets.md deleted file mode 100644 index a68430a0..00000000 --- a/doc/src/about/targets.md +++ /dev/null @@ -1,18 +0,0 @@ -Supported Targets and Builds -=========================== - -{{#include ../links.md}} - -The following targets and builds are support by Rhai: - -* All common CPU targets for Windows, Linux and MacOS. - -* WebAssembly ([WASM]) - -* [`no-std`] - - -Minimum Rust Version --------------------- - -The minimum version of Rust required to compile Rhai is `1.45.0`. diff --git a/doc/src/advanced.md b/doc/src/advanced.md deleted file mode 100644 index 87136de0..00000000 --- a/doc/src/advanced.md +++ /dev/null @@ -1,6 +0,0 @@ -Advanced Topics -=============== - -{{#include links.md}} - -This section covers advanced features of the Rhai [`Engine`]. diff --git a/doc/src/appendix/index.md b/doc/src/appendix/index.md deleted file mode 100644 index bdb6cae9..00000000 --- a/doc/src/appendix/index.md +++ /dev/null @@ -1,6 +0,0 @@ -Appendix -======== - -{{#include ../links.md}} - -This section contains miscellaneous reference materials. diff --git a/doc/src/appendix/keywords.md b/doc/src/appendix/keywords.md deleted file mode 100644 index 2866cb5d..00000000 --- a/doc/src/appendix/keywords.md +++ /dev/null @@ -1,75 +0,0 @@ -Keywords List -============= - -{{#include ../links.md}} - -| Keyword | Description | Inactive under | Is function? | Overloadable | -| :-------------------: | ------------------------------------------- | :-------------: | :----------: | :----------: | -| `true` | boolean true literal | | no | | -| `false` | boolean false literal | | no | | -| `let` | variable declaration | | no | | -| `const` | constant declaration | | no | | -| `if` | if statement | | no | | -| `else` | else block of if statement | | no | | -| `switch` | matching | | no | | -| `do` | looping | | no | | -| `while` | 1) while loop
2) condition for do loop | | no | | -| `until` | do loop | | no | | -| `loop` | infinite loop | | no | | -| `for` | for loop | | no | | -| `in` | 1) containment test
2) part of for loop | | no | | -| `continue` | continue a loop at the next iteration | | no | | -| `break` | break out of loop iteration | | no | | -| `return` | return value | | no | | -| `throw` | throw exception | | no | | -| `try` | trap exception | | no | | -| `catch` | catch exception | | no | | -| `import` | import module | [`no_module`] | no | | -| `export` | export variable | [`no_module`] | no | | -| `as` | alias for variable export | [`no_module`] | no | | -| `private` | mark function private | [`no_function`] | no | | -| `fn` (lower-case `f`) | function definition | [`no_function`] | no | | -| `Fn` (capital `F`) | create a [function pointer] | | yes | yes | -| `call` | call a [function pointer] | | yes | no | -| `curry` | curry a [function pointer] | | yes | no | -| `this` | reference to base object for method call | [`no_function`] | no | | -| `type_of` | get type name of value | | yes | yes | -| `print` | print value | | yes | yes | -| `debug` | print value in debug format | | yes | yes | -| `eval` | evaluate script | | yes | yes | - - -Reserved Keywords ------------------ - -| Keyword | Potential usage | -| --------- | --------------------- | -| `var` | variable declaration | -| `static` | variable declaration | -| `begin` | block scope | -| `end` | block scope | -| `shared` | share value | -| `each` | looping | -| `then` | control flow | -| `goto` | control flow | -| `exit` | control flow | -| `unless` | control flow | -| `match` | matching | -| `case` | matching | -| `public` | function/field access | -| `new` | constructor | -| `use` | import namespace | -| `with` | scope | -| `module` | module | -| `package` | package | -| `thread` | threading | -| `spawn` | threading | -| `go` | threading | -| `await` | async | -| `async` | async | -| `sync` | async | -| `yield` | async | -| `default` | special value | -| `void` | special value | -| `null` | special value | -| `nil` | special value | diff --git a/doc/src/appendix/literals.md b/doc/src/appendix/literals.md deleted file mode 100644 index 3e5a5fdf..00000000 --- a/doc/src/appendix/literals.md +++ /dev/null @@ -1,16 +0,0 @@ -Literals Syntax -=============== - -{{#include ../links.md}} - -| Type | Literal syntax | -| :--------------------------------: | :-----------------------------------------------------------------------------------------: | -| `INT` | decimal: `42`, `-123`, `0`
hex: `0x????..`
binary: `0b????..`
octal: `0o????..` | -| `FLOAT` | `42.0`, `-123.456`, `0.0` | -| [String] | `"... \x?? \u???? \U???????? ..."` | -| [Character][string] | single: `'?'`
ASCII hex: `'\x??'`
Unicode: `'\u????'`, `'\U????????'` | -| [`Array`] | `[ ???, ???, ??? ]` | -| [Object map] | `#{ a: ???, b: ???, c: ???, "def": ??? }` | -| Boolean true | `true` | -| Boolean false | `false` | -| `Nothing`/`null`/`nil`/`void`/Unit | `()` | diff --git a/doc/src/appendix/operators.md b/doc/src/appendix/operators.md deleted file mode 100644 index 71e94965..00000000 --- a/doc/src/appendix/operators.md +++ /dev/null @@ -1,74 +0,0 @@ -Operators and Symbols -==================== - -{{#include ../links.md}} - - -Operators ---------- - -| Operator | Description | Binary? | Binding direction | -| :-----------------------------------------------------------------------------------------: | -------------------------------------- | :--------: | :---------------: | -| `+` | add | yes | left | -| `-` | 1) subtract
2) negative (prefix) | yes
no | left
right | -| `*` | multiply | yes | left | -| `/` | divide | yes | left | -| `%` | modulo | yes | left | -| `~` | power | yes | left | -| `>>` | right bit-shift | yes | left | -| `<<` | left bit-shift | yes | left | -| `&` | 1) bit-wise _AND_
2) boolean _AND_ | yes | left | -| \| | 1) bit-wise _OR_
2) boolean _OR_ | yes | left | -| `^` | 1) bit-wise _XOR_
2) boolean _XOR_ | yes | left | -| `=`, `+=`, `-=`, `*=`, `/=`,
`~=`, `%=`, `<<=`, `>>=`, `&=`,
\|=, `^=` | assignments | yes | right | -| `==` | equals to | yes | left | -| `~=` | not equals to | yes | left | -| `>` | greater than | yes | left | -| `>=` | greater than or equals to | yes | left | -| `<` | less than | yes | left | -| `<=` | less than or equals to | yes | left | -| `&&` | boolean _AND_ (short-circuits) | yes | left | -| \|\| | boolean _OR_ (short-circuits) | yes | left | -| `!` | boolean _NOT_ | no | left | -| `[` .. `]` | indexing | yes | right | -| `.` | 1) property access
2) method call | yes | right | - - -Symbols and Patterns --------------------- - -| Symbol | Name | Description | -| ---------------------------------- | :------------------: | ------------------------------------- | -| `_` | underscore | default `switch` case | -| `;` | semicolon | statement separator | -| `,` | comma | list separator | -| `:` | colon | [object map] property value separator | -| `::` | path | module path separator | -| `#{` .. `}` | hash map | [object map] literal | -| `"` .. `"` | double quote | [string] | -| `'` .. `'` | single quote | [character][string] | -| `\` | escape | escape character literal | -| `(` .. `)` | parentheses | expression grouping | -| `{` .. `}` | braces | block statement | -| \| .. \| | pipes | closure | -| `[` .. `]` | brackets | [array] literal | -| `!` | bang | function call in calling scope | -| `=>` | double arrow | `switch` expression case separator | -| `//` | comment | line comment | -| `/*` .. `*/` | comment | block comment | -| `(*` .. `*)` | comment | _reserved_ | -| `<` .. `>` | angular brackets | _reserved_ | -| `++` | increment | _reserved_ | -| `--` | decrement | _reserved_ | -| `..` | range | _reserved_ | -| `...` | range | _reserved_ | -| `**` | exponentiation | _reserved_ | -| `#` | hash | _reserved_ | -| `@` | at | _reserved_ | -| `$` | dollar | _reserved_ | -| `->` | arrow | _reserved_ | -| `<-` | left arrow | _reserved_ | -| `===` | strict equals to | _reserved_ | -| `!==` | strict not equals to | _reserved_ | -| `:=` | assignment | _reserved_ | -| `::<` .. `>` | turbofish | _reserved_ | diff --git a/doc/src/context.json b/doc/src/context.json deleted file mode 100644 index e3ba5b9b..00000000 --- a/doc/src/context.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": "0.19.10", - "repoHome": "https://github.com/rhaiscript/rhai/blob/master", - "repoTree": "https://github.com/rhaiscript/rhai/tree/master", - "rootUrl": "", - "rootUrlX": "/rhai", - "rootUrlXX": "/rhai/vnext" -} \ No newline at end of file diff --git a/doc/src/engine/call-fn.md b/doc/src/engine/call-fn.md deleted file mode 100644 index 548b058a..00000000 --- a/doc/src/engine/call-fn.md +++ /dev/null @@ -1,95 +0,0 @@ -Calling Rhai Functions from Rust -=============================== - -{{#include ../links.md}} - -Rhai also allows working _backwards_ from the other direction – i.e. calling a Rhai-scripted function -from Rust via `Engine::call_fn`. - -Functions declared with `private` are hidden and cannot be called from Rust (see also [modules]). - -```rust -// Define functions in a script. -let ast = engine.compile(true, - r#" - // a function with two parameters: string and i64 - fn hello(x, y) { - x.len + y - } - - // functions can be overloaded: this one takes only one parameter - fn hello(x) { - x * 2 - } - - // this one takes no parameters - fn hello() { - 42 - } - - // this one is private and cannot be called by 'call_fn' - private hidden() { - throw "you shouldn't see me!"; - } - "#)?; - -// A custom scope can also contain any variables/constants available to the functions -let mut scope = Scope::new(); - -// Evaluate a function defined in the script, passing arguments into the script as a tuple. -// Beware, arguments must be of the correct types because Rhai does not have built-in type conversions. -// If arguments of the wrong types are passed, the Engine will not find the function. - -let result: i64 = engine.call_fn(&mut scope, &ast, "hello", ( String::from("abc"), 123_i64 ) )?; -// ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// return type must be specified put arguments in a tuple - -let result: i64 = engine.call_fn(&mut scope, &ast, "hello", (123_i64,) )?; -// ^^^^^^^^^^ tuple of one - -let result: i64 = engine.call_fn(&mut scope, &ast, "hello", () )?; -// ^^ unit = tuple of zero - -// The following call will return a function-not-found error because -// 'hidden' is declared with 'private'. -let result: () = engine.call_fn(&mut scope, &ast, "hidden", ())?; -``` - - -Low-Level API – `Engine::call_fn_dynamic` ----------------------------------------------- - -For more control, construct all arguments as `Dynamic` values and use `Engine::call_fn_dynamic`, passing it -anything that implements `AsMut` (such as a simple array or a `Vec`): - -```rust -let result = engine.call_fn_dynamic( - &mut scope, // scope to use - &ast, // AST containing the functions - "hello", // function entry-point - None, // 'this' pointer, if any - [ String::from("abc").into(), 123_i64.into() ] // arguments - )?; -``` - - -Binding the `this` Pointer -------------------------- - -`Engine::call_fn_dynamic` can also bind a value to the `this` pointer of a script-defined function. - -```rust -let ast = engine.compile("fn action(x) { this += x; }")?; - -let mut value: Dynamic = 1_i64.into(); - -let result = engine.call_fn_dynamic( - &mut scope, - &ast, - "action", - Some(&mut value), // binding the 'this' pointer - [ 41_i64.into() ] - )?; - -assert_eq!(value.as_int()?, 42); -``` diff --git a/doc/src/engine/compile.md b/doc/src/engine/compile.md deleted file mode 100644 index 07c172c1..00000000 --- a/doc/src/engine/compile.md +++ /dev/null @@ -1,27 +0,0 @@ -Compile a Script (to AST) -======================== - -{{#include ../links.md}} - -To repeatedly evaluate a script, _compile_ it first with `Engine::compile` into an `AST` -(abstract syntax tree) form. - -`Engine::eval_ast` evaluates a pre-compiled `AST`. - -```rust -// Compile to an AST and store it for later evaluations -let ast = engine.compile("40 + 2")?; - -for _ in 0..42 { - let result: i64 = engine.eval_ast(&ast)?; - - println!("Answer #{}: {}", i, result); // prints 42 -} -``` - -Compiling a script file is also supported with `Engine::compile_file` -(not available under [`no_std`] or in [WASM] builds): - -```rust -let ast = engine.compile_file("hello_world.rhai".into())?; -``` diff --git a/doc/src/engine/custom-op.md b/doc/src/engine/custom-op.md deleted file mode 100644 index 3dacfa9d..00000000 --- a/doc/src/engine/custom-op.md +++ /dev/null @@ -1,115 +0,0 @@ -Custom Operators -================ - -{{#include ../links.md}} - -For use as a DSL (Domain-Specific Languages), it is sometimes more convenient to augment Rhai with -customized operators performing specific logic. - -`Engine::register_custom_operator` registers a keyword as a custom operator, giving it a particular -_precedence_ (which cannot be zero). - - -Example -------- - -```rust -use rhai::{Engine, RegisterFn}; - -let mut engine = Engine::new(); - -// Register a custom operator named 'foo' and give it a precedence of 160 -// (i.e. between +|- and *|/) -// Also register the implementation of the customer operator as a function -engine - .register_custom_operator("foo", 160)? - .register_fn("foo", |x: i64, y: i64| (x * y) - (x + y)); - -// The custom operator can be used in expressions -let result = engine.eval_expression::("1 + 2 * 3 foo 4 - 5 / 6")?; -// ^ custom operator - -// The above is equivalent to: 1 + ((2 * 3) foo 4) - (5 / 6) -result == 15; -``` - - -Alternatives to a Custom Operator --------------------------------- - -Custom operators are merely _syntactic sugar_. They map directly to registered functions. - -Therefore, the following are equivalent (assuming `foo` has been registered as a custom operator): - -```rust -1 + 2 * 3 foo 4 - 5 / 6 // use custom operator - -1 + foo(2 * 3, 4) - 5 / 6 // use function call -``` - -A script using custom operators can always be pre-processed, via a pre-processor application, -into a syntax that uses the corresponding function calls. - -Using `Engine::register_custom_operator` merely enables a convenient shortcut. - - -Must be a Valid Identifier or Reserved Symbol --------------------------------------------- - -All custom operators must be _identifiers_ that follow the same naming rules as [variables]. - -Alternatively, they can also be [reserved symbols]({{rootUrl}}/appendix/operators.md#symbols), -[disabled operators or keywords][disable keywords and operators]. - -```rust -engine.register_custom_operator("foo", 20); // 'foo' is a valid custom operator - -engine.register_custom_operator("#", 20); // the reserved symbol '#' is also - // a valid custom operator - -engine.register_custom_operator("+", 30); // <- error: '+' is an active operator - -engine.register_custom_operator("=>", 30); // <- error: '=>' is an active symbol -``` - - -Binary Operators Only ---------------------- - -All custom operators must be _binary_ (i.e. they take two operands). -_Unary_ custom operators are not supported. - -```rust -engine - .register_custom_operator("foo", 160)? - .register_fn("foo", |x: i64| x * x); - -engine.eval::("1 + 2 * 3 foo 4 - 5 / 6")?; // error: function 'foo (i64, i64)' not found -``` - - -Operator Precedence -------------------- - -All operators in Rhai has a _precedence_ indicating how tightly they bind. - -A higher precedence binds more tightly than a lower precedence, so `*` and `/` binds before `+` and `-` etc. - -When registering a custom operator, the operator's precedence must also be provided. - -The following _precedence table_ shows the built-in precedence of standard Rhai operators: - -| Category | Operators | Precedence (0-255) | -| ------------------- | :-------------------------------------------------------------------------------------: | :----------------: | -| Assignments | `=`, `+=`, `-=`, `*=`, `/=`, `~=`, `%=`,
`<<=`, `>>=`, `&=`, \|=, `^=` | 0 | -| Logic and bit masks | \|\|, \|, `^` | 30 | -| Logic and bit masks | `&&`, `&` | 60 | -| Comparisons | `==`, `!=` | 90 | -| | `in` | 110 | -| Comparisons | `>`, `>=`, `<`, `<=` | 130 | -| Arithmetic | `+`, `-` | 150 | -| Arithmetic | `*`, `/`, `%` | 180 | -| Arithmetic | `~` | 190 | -| Bit-shifts | `<<`, `>>` | 210 | -| Object | `.` _(binds to right)_ | 240 | -| Unary operators | unary `+`, `-`, `!` _(binds to right)_ | 255 | diff --git a/doc/src/engine/custom-syntax.md b/doc/src/engine/custom-syntax.md deleted file mode 100644 index 5c27142a..00000000 --- a/doc/src/engine/custom-syntax.md +++ /dev/null @@ -1,404 +0,0 @@ -Extend Rhai with Custom Syntax -============================= - -{{#include ../links.md}} - - -For the ultimate adventurous, there is a built-in facility to _extend_ the Rhai language -with custom-defined _syntax_. - -But before going off to define the next weird statement type, heed this warning: - - -Don't Do It™ ------------- - -Stick with standard language syntax as much as possible. - -Having to learn Rhai is bad enough, no sane user would ever want to learn _yet_ another -obscure language syntax just to do something. - -Try to use [custom operators] first. Defining a custom syntax should be considered a _last resort_. - - -Where This Might Be Useful -------------------------- - -* Where an operation is used a _LOT_ and a custom syntax saves a lot of typing. - -* Where a custom syntax _significantly_ simplifies the code and _significantly_ enhances understanding of the code's intent. - -* Where certain logic cannot be easily encapsulated inside a function. - -* Where you just want to confuse your user and make their lives miserable, because you can. - - -Step One – Design The Syntax ---------------------------------- - -A custom syntax is simply a list of symbols. - -These symbol types can be used: - -* Standard [keywords]({{rootUrl}}/appendix/keywords.md) - -* Standard [operators]({{rootUrl}}/appendix/operators.md#operators). - -* Reserved [symbols]({{rootUrl}}/appendix/operators.md#symbols). - -* Identifiers following the [variable] naming rules. - -* `$expr$` – any valid expression, statement or statement block. - -* `$block$` – any valid statement block (i.e. must be enclosed by `'{'` .. `'}'`). - -* `$ident$` – any [variable] name. - -### The First Symbol Must be an Identifier - -There is no specific limit on the combination and sequencing of each symbol type, -except the _first_ symbol which must be a custom keyword that follows the naming rules -of [variables]. - -The first symbol also cannot be a normal or reserved [keyword]. -In other words, any valid identifier that is not a [keyword] will work fine. - -### The First Symbol Must be Unique - -Rhai uses the _first_ symbol as a clue to parse custom syntax. - -Therefore, at any one time, there can only be _one_ custom syntax starting with each unique symbol. - -Any new custom syntax definition using the same first symbol simply _overwrites_ the previous one. - -### Example - -```rust -exec $ident$ <- $expr$ : $block$ -``` - -The above syntax is made up of a stream of symbols: - -| Position | Input | Symbol | Description | -| :------: | :---: | :-------: | -------------------------------------------------------------------------------------------------------- | -| 1 | | `exec` | custom keyword | -| 2 | 1 | `$ident$` | a variable name | -| 3 | | `<-` | the left-arrow symbol (which is a [reserved symbol]({{rootUrl}}/appendix/operators.md#symbols) in Rhai). | -| 4 | 2 | `$expr$` | an expression, which may be enclosed with `{` .. `}`, or not. | -| 5 | | `:` | the colon symbol | -| 6 | 3 | `$block$` | a statement block, which must be enclosed with `{` .. `}`. | - -This syntax matches the following sample code and generates three inputs (one for each non-keyword): - -```rust -// Assuming the 'exec' custom syntax implementation declares the variable 'hello': -let x = exec hello <- foo(1, 2) : { - hello += bar(hello); - baz(hello); - }; - -print(x); // variable 'x' has a value returned by the custom syntax - -print(hello); // variable declared by a custom syntax persists! -``` - - -Step Two – Implementation ------------------------------- - -Any custom syntax must include an _implementation_ of it. - -### Function Signature - -The function signature of an implementation is: - -> `Fn(context: &mut EvalContext, inputs: &[Expression]) -> Result>` - -where: - -| Parameter | Type | Description | -| -------------------------- | :-------------------------------------: | ---------------------------------------------------------------------------------------------------------------------- | -| `context` | `&mut EvalContext` | mutable reference to the current evaluation _context_ | -| • `scope()` | `&Scope` | reference to the current [`Scope`] | -| • `scope_mut()` | `&mut &mut Scope` | mutable reference to the current [`Scope`]; variables can be added to/removed from it | -| • `engine()` | `&Engine` | reference to the current [`Engine`] | -| • `source()` | `Option<&str>` | reference to the current source, if any | -| • `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| • `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| • `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | -| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any | -| • `call_level()` | `usize` | the current nesting level of function calls | -| `inputs` | `&[Expression]` | a list of input expression trees | - -### Return Value - -Return value is the result of evaluating the custom syntax expression. - -### Access Arguments - -The most important argument is `inputs` where the matched identifiers (`$ident$`), expressions/statements (`$expr$`) -and statement blocks (`$block$`) are provided. - -To access a particular argument, use the following patterns: - -| Argument type | Pattern (`n` = slot in `inputs`) | Result type | Description | -| :-----------: | ---------------------------------------- | :----------: | ------------------ | -| `$ident$` | `inputs[n].get_variable_name().unwrap()` | `&str` | name of a variable | -| `$expr$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree | -| `$block$` | `inputs.get(n).unwrap()` | `Expression` | an expression tree | - -### Evaluate an Expression Tree - -Use the `EvalContext::eval_expression_tree` method to evaluate an arbitrary expression tree -within the current evaluation context. - -```rust -let expression = inputs.get(0).unwrap(); -let result = context.eval_expression_tree(expression)?; -``` - -### Declare Variables - -New variables maybe declared (usually with a variable name that is passed in via `$ident$). - -It can simply be pushed into the [`Scope`]. - -However, beware that all new variables must be declared _prior_ to evaluating any expression tree. -In other words, any [`Scope`] calls that change the list of must come _before_ any -`EvalContext::eval_expression_tree` calls. - -```rust -let var_name = inputs[0].get_variable_name().unwrap(); -let expression = inputs.get(1).unwrap(); - -context.scope_mut().push(var_name, 0 as INT); // do this BEFORE 'context.eval_expression_tree'! - -let result = context.eval_expression_tree(expression)?; -``` - - -Step Three – Register the Custom Syntax --------------------------------------------- - -Use `Engine::register_custom_syntax` to register a custom syntax. - -Again, beware that the _first_ symbol must be unique. If there already exists a custom syntax starting -with that symbol, the previous syntax will be overwritten. - -The syntax is passed simply as a slice of `&str`. - -```rust -// Custom syntax implementation -fn implementation_func( - context: &mut EvalContext, - inputs: &[Expression] -) -> Result> { - let var_name = inputs[0].get_variable_name().unwrap().to_string(); - let stmt = inputs.get(1).unwrap(); - let condition = inputs.get(2).unwrap(); - - // Push one new variable into the scope BEFORE 'context.eval_expression_tree' - context.scope_mut().push(var_name, 0 as INT); - - loop { - // Evaluate the statement block - context.eval_expression_tree(stmt)?; - - // Evaluate the condition expression - let stop = !context.eval_expression_tree(condition)? - .as_bool().map_err(|err| Box::new( - EvalAltResult::ErrorMismatchDataType( - "bool".to_string(), - err.to_string(), - condition.position(), - ) - ))?; - - if stop { - break; - } - } - - Ok(Dynamic::UNIT) -} - -// Register the custom syntax (sample): exec |x| -> { x += 1 } while x < 0 -engine.register_custom_syntax( - &[ "exec", "|", "$ident$", "|", "->", "$block$", "while", "$expr$" ], // the custom syntax - 1, // the number of new variables declared within this custom syntax - implementation_func -)?; -``` - -Remember that a custom syntax acts as an _expression_, so it can show up practically anywhere: - -```rust -// Use as an expression: -let foo = (exec |x| -> { x += 1 } while x < 0) * 100; - -// Use as a function call argument: -do_something(exec |x| -> { x += 1 } while x < 0, 24, true); - -// Use as a statement: -exec |x| -> { x += 1 } while x < 0; -// ^ terminate statement with ';' -``` - - -Step Four – Disable Unneeded Statement Types -------------------------------------------------- - -When a DSL needs a custom syntax, most likely than not it is extremely specialized. -Therefore, many statement types actually may not make sense under the same usage scenario. - -So, while at it, better [disable][disable keywords and operators] those built-in keywords -and operators that should not be used by the user. The would leave only the bare minimum -language surface exposed, together with the custom syntax that is tailor-designed for -the scenario. - -A keyword or operator that is disabled can still be used in a custom syntax. - -In an extreme case, it is possible to disable _every_ keyword in the language, leaving only -custom syntax (plus possibly expressions). But again, Don't Do It™ – unless you are certain -of what you're doing. - - -Step Five – Document -------------------------- - -For custom syntax, documentation is crucial. - -Make sure there are _lots_ of examples for users to follow. - - -Step Six – Profit! ------------------------- - - -Really Advanced – Custom Parsers -------------------------------------- - -Sometimes it is desirable to have multiple custom syntax starting with the -same symbol. This is especially common for _command-style_ syntax where the -second symbol calls a particular command: - -```rust -// The following simulates a command-style syntax, all starting with 'perform'. -perform hello world; // A fixed sequence of symbols -perform action 42; // Perform a system action with a parameter -perform update system; // Update the system -perform check all; // Check all system settings -perform cleanup; // Clean up the system -perform add something; // Add something to the system -perform remove something; // Delete something from the system -``` - -Alternatively, a custom syntax may have variable length, with a termination symbol: - -```rust -// The following is a variable-length list terminated by '>' -tags < "foo", "bar", 123, ... , x+y, true > -``` - -For even more flexibility in order to handle these advanced use cases, there is a -_low level_ API for custom syntax that allows the registration of an entire mini-parser. - -Use `Engine::register_custom_syntax_raw` to register a custom syntax _parser_ -together with the implementation function. - -### How Custom Parsers Work - -A custom parser takes as input parameters two pieces of information: - -* The symbols parsed so far; `$ident$` is replaced with the actual identifier parsed, - while `$expr$` and `$block$` stay as they were. - - The custom parser can inspect this symbols stream to determine the next symbol to parse. - -* The _look-ahead_ symbol, which is the symbol that will be parsed _next_. - - If the look-ahead is an expected symbol, the customer parser just returns it to continue parsing, - or it can return `$ident$` to parse it as an identifier, or even `$expr$` to start parsing - an expression. - - If the look-ahead is '`{`', then the custom parser may also return `$block$` to start parsing a - statements block. - - If the look-ahead is unexpected, the custom parser should then return the symbol expected - and Rhai will fail with a parse error containing information about the expected symbol. - -A custom parser always returns the _next_ symbol expected, which can also be `$ident$`, -`$expr$` or `$block$`, or `None` if parsing should terminate (_without_ reading the -look-ahead symbol). - - -### Example - -```rust -engine.register_custom_syntax_raw( - "perform", - // The custom parser implementation - always returns the next symbol expected - // 'look_ahead' is the next symbol about to be read - |symbols, look_ahead| match symbols.len() { - // perform ... - 1 => Ok(Some("$ident$".to_string())), - // perform command ... - 2 => match symbols[1].as_str() { - "action" => Ok(Some("$expr$".into())), - "hello" => Ok(Some("world".into())), - "update" | "check" | "add" | "remove" => Ok(Some("$ident$".into())), - "cleanup" => Ok(None), - cmd => Err(ParseError(Box::new(ParseErrorType::BadInput( - LexError::ImproperSymbol(format!("Improper command: {}", cmd)) - )), Position::NONE)), - }, - // perform command arg ... - 3 => match (symbols[1].as_str(), symbols[2].as_str()) { - ("action", _) => Ok(None), - ("hello", "world") => Ok(None), - ("update", arg) if arg == "system" => Ok(None), - ("update", arg) if arg == "client" => Ok(None), - ("check", arg) => Ok(None), - ("add", arg) => Ok(None), - ("remove", arg) => Ok(None), - (cmd, arg) => Err(ParseError(Box::new(ParseErrorType::BadInput( - LexError::ImproperSymbol( - format!("Invalid argument for command {}: {}", cmd, arg) - ) - )), Position::NONE)), - }, - _ => unreachable!(), - }, - // Number of new variables declared by this custom syntax - 0, - // Implementation function - implementation_func -); -``` - -### Function Signature - -The custom syntax parser has the following signature: - -> `Fn(symbols: &[ImmutableString], look_ahead: &str) -> Result, ParseError>` - -where: - -| Parameter | Type | Description | -| ------------ | :------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `symbols` | `&[ImmutableString]` | a slice of symbols that have been parsed so far, possibly containing `$expr$` and/or `$block$`; `$ident$` is replaced by the actual identifier | -| `look_ahead` | `&str` | a string slice containing the next symbol that is about to be read | - -Most strings are [`ImmutableString`][string]'s so it is usually more efficient to just `clone` the appropriate one -(if any matches, or keep an internal cache for commonly-used symbols) as the return value. - -### Return Value - -The return value is `Result, ParseError>` where: - -| Value | Description | -| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Ok(None)` | parsing complete and there are no more symbols to match | -| `Ok(Some(symbol))` | the next symbol to match, which can also be `$expr$`, `$ident$` or `$block$` | -| `Err(ParseError)` | error that is reflected back to the [`Engine`] – normally `ParseError(ParseErrorType::BadInput(LexError::ImproperSymbol(message)), Position::NONE)` to indicate that there is a syntax error, but it can be any `ParseError`. | diff --git a/doc/src/engine/disable.md b/doc/src/engine/disable.md deleted file mode 100644 index 28e35f70..00000000 --- a/doc/src/engine/disable.md +++ /dev/null @@ -1,28 +0,0 @@ -Disable Certain Keywords and/or Operators -======================================== - -{{#include ../links.md}} - -For certain embedded usage, it is sometimes necessary to restrict the language to a strict subset of Rhai -to prevent usage of certain language features. - -Rhai supports surgically disabling a keyword or operator via the `Engine::disable_symbol` method. - -```rust -use rhai::Engine; - -let mut engine = Engine::new(); - -engine - .disable_symbol("if") // disable the 'if' keyword - .disable_symbol("+="); // disable the '+=' operator - -// The following all return parse errors. - -engine.compile("let x = if true { 42 } else { 0 };")?; -// ^ 'if' is rejected as a reserved keyword - -engine.compile("let x = 40 + 2; x += 1;")?; -// ^ '+=' is not recognized as an operator -// ^ other operators are not affected -``` diff --git a/doc/src/engine/dsl.md b/doc/src/engine/dsl.md deleted file mode 100644 index efb9ac81..00000000 --- a/doc/src/engine/dsl.md +++ /dev/null @@ -1,92 +0,0 @@ -Use Rhai as a Domain-Specific Language (DSL) -=========================================== - -{{#include ../links.md}} - -Rhai can be successfully used as a domain-specific language (DSL). - - -Expressions Only ----------------- - -In many DSL scenarios, only evaluation of expressions is needed. - -The [`Engine::eval_expression_XXX`][`eval_expression`] API can be used to restrict -a script to expressions only. - - -Unicode Standard Annex #31 Identifiers -------------------------------------- - -Variable names and other identifiers do not necessarily need to be ASCII-only. - -The [`unicode-xid-ident`] feature, when turned on, causes Rhai to allow variable names and identifiers -that follow [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/). - -This is sometimes useful in a non-English DSL. - - -Disable Keywords and/or Operators --------------------------------- - -In some DSL scenarios, it is necessary to further restrict the language to exclude certain -language features that are not necessary or dangerous to the application. - -For example, a DSL may disable the `while` loop while keeping all other statement types intact. - -It is possible, in Rhai, to surgically [disable keywords and operators]. - - -Custom Operators ----------------- - -On the other hand, some DSL scenarios require special operators that make sense only for -that specific environment. In such cases, it is possible to define [custom operators] in Rhai. - -For example: - -```rust -let animal = "rabbit"; -let food = "carrot"; - -animal eats food // custom operator 'eats' - -eats(animal, food) // <- the above really de-sugars to this -``` - -Although a [custom operator] always de-sugars to a simple function call, -nevertheless it makes the DSL syntax much simpler and expressive. - - -Custom Syntax -------------- - -For advanced DSL scenarios, it is possible to define entire expression [_syntax_][custom syntax] &ndash -essentially custom statement types. - -For example, the following is a SQL-like syntax for some obscure DSL operation: - -```rust -let table = [..., ..., ..., ...]; - -// Syntax = calculate $ident$ ( $expr$ -> $ident$ ) => $ident$ : $expr$ -let total = calculate sum(table->price) => row : row.weight > 50; - -// Note: There is nothing special about those symbols; to make it look exactly like SQL: -// Syntax = SELECT $ident$ ( $ident$ ) AS $ident$ FROM $expr$ WHERE $expr$ -let total = SELECT sum(price) AS row FROM table WHERE row.weight > 50; -``` - -After registering this custom syntax with Rhai, it can be used anywhere inside a script as -a normal expression. - -For its evaluation, the callback function will receive the following list of inputs: - -* `inputs[0] = "sum"` - math operator -* `inputs[1] = "price"` - field name -* `inputs[2] = "row"` - loop variable name -* `inputs[3] = Expression(table)` - data source -* `inputs[4] = Expression(row.wright > 50)` - filter predicate - -Other identifiers, such as `"calculate"`, `"FROM"`, as well as symbols such as `->` and `:` etc., -are parsed in the order defined within the custom syntax. diff --git a/doc/src/engine/expressions.md b/doc/src/engine/expressions.md deleted file mode 100644 index cb3ea9b2..00000000 --- a/doc/src/engine/expressions.md +++ /dev/null @@ -1,27 +0,0 @@ -Evaluate Expressions Only -======================== - -{{#include ../links.md}} - -Sometimes a use case does not require a full-blown scripting _language_, but only needs to evaluate _expressions_. - -In these cases, use the `Engine::compile_expression` and `Engine::eval_expression` methods or their `_with_scope` variants. - -```rust -let result = engine.eval_expression::("2 + (10 + 10) * 2")?; -``` - -When evaluating _expressions_, no full-blown statement (e.g. `if`, `while`, `for`, `fn`) – not even variable assignment – -is supported and will be considered parse errors when encountered. - -[Closures] and [anonymous functions] are also not supported because in the background they compile to functions. - -```rust -// The following are all syntax errors because the script is not an expression. - -engine.eval_expression::<()>("x = 42")?; - -let ast = engine.compile_expression("let x = 42")?; - -let result = engine.eval_expression_with_scope::(&mut scope, "if x { 42 } else { 123 }")?; -``` diff --git a/doc/src/engine/func.md b/doc/src/engine/func.md deleted file mode 100644 index d0ce6784..00000000 --- a/doc/src/engine/func.md +++ /dev/null @@ -1,43 +0,0 @@ -Create a Rust Closure from a Rhai Function -========================================= - -{{#include ../links.md}} - -It is possible to further encapsulate a script in Rust such that it becomes a normal Rust function. - -Such a _closure_ is very useful as call-back functions. - -Creating them is accomplished via the `Func` trait which contains `create_from_script` -(as well as its companion method `create_from_ast`): - -```rust -use rhai::{Engine, Func}; // use 'Func' for 'create_from_script' - -let engine = Engine::new(); // create a new 'Engine' just for this - -let script = "fn calc(x, y) { x + y.len < 42 }"; - -// Func takes two type parameters: -// 1) a tuple made up of the types of the script function's parameters -// 2) the return type of the script function -// -// 'func' will have type Box Result>> and is callable! -let func = Func::<(i64, String), bool>::create_from_script( -// ^^^^^^^^^^^^^ function parameter types in tuple - - engine, // the 'Engine' is consumed into the closure - script, // the script, notice number of parameters must match - "calc" // the entry-point function name -)?; - -func(123, "hello".to_string())? == false; // call the closure - -schedule_callback(func); // pass it as a callback to another function - -// Although there is nothing you can't do by manually writing out the closure yourself... -let engine = Engine::new(); -let ast = engine.compile(script)?; -schedule_callback(Box::new(move |x: i64, y: String| -> Result> { - engine.call_fn(&mut Scope::new(), &ast, "calc", (x, y)) -})); -``` diff --git a/doc/src/engine/hello-world.md b/doc/src/engine/hello-world.md deleted file mode 100644 index 241d282b..00000000 --- a/doc/src/engine/hello-world.md +++ /dev/null @@ -1,60 +0,0 @@ -Hello World in Rhai -=================== - -{{#include ../links.md}} - -To get going with Rhai is as simple as creating an instance of the scripting engine `rhai::Engine` via -`Engine::new`, then calling the `eval` method: - -```rust -use rhai::{Engine, EvalAltResult}; - -fn main() -> Result<(), Box> -{ - let engine = Engine::new(); - - let result = engine.eval::("40 + 2")?; - // ^^^^^^^ cast the result to an 'i64', this is required - - println!("Answer: {}", result); // prints 42 - - Ok(()) -} -``` - -Evaluate a script file directly: - -```rust -// 'eval_file' takes a 'PathBuf' -let result = engine.eval_file::("hello_world.rhai".into())?; -``` - - -Error Type ----------- - -`rhai::EvalAltResult` is the standard Rhai error type, which is a Rust `enum` containing all errors encountered -during the parsing or evaluation process. - - -Return Type ------------ - -The type parameter for `Engine::eval` is used to specify the type of the return value, -which _must_ match the actual type or an error is returned. Rhai is very strict here. - -There are two ways to specify the return type – _turbofish_ notation, or type inference. - -Use [`Dynamic`] for uncertain return types. - -```rust -let result = engine.eval::("40 + 2")?; // return type is i64, specified using 'turbofish' notation - -let result: i64 = engine.eval("40 + 2")?; // return type is inferred to be i64 - -result.is::() == true; - -let result: Dynamic = engine.eval("boo()")?; // use 'Dynamic' if you're not sure what type it'll be! - -let result = engine.eval::("40 + 2")?; // returns an error because the actual return type is i64, not String -``` diff --git a/doc/src/engine/index.md b/doc/src/engine/index.md deleted file mode 100644 index 8bf58504..00000000 --- a/doc/src/engine/index.md +++ /dev/null @@ -1,8 +0,0 @@ -Using the Engine -================ - -{{#include ../links.md}} - -Rhai's interpreter resides in the [`Engine`] type under the master `rhai` namespace. - -This section shows how to set up, configure and use this scripting engine. diff --git a/doc/src/engine/metadata/export_to_json.md b/doc/src/engine/metadata/export_to_json.md deleted file mode 100644 index 13d2da72..00000000 --- a/doc/src/engine/metadata/export_to_json.md +++ /dev/null @@ -1,107 +0,0 @@ -Export Functions Metadata to JSON -================================ - -{{#include ../../links.md}} - - -`Engine::gen_fn_metadata_to_json`
`Engine::gen_fn_metadata_with_ast_to_json` ------------------------------------------------------------------------------- - -As part of a _reflections_ API, `Engine::gen_fn_metadata_to_json` and the corresponding -`Engine::gen_fn_metadata_with_ast_to_json` export the full list of [functions metadata] -in JSON format. - -The [`metadata`] feature must be used to turn on this API, which requires -the [`serde_json`](https://crates.io/crates/serde_json) crate. - -### Sources - -Functions from the following sources are included: - -1) Script-defined functions in an [`AST`] (for `Engine::gen_fn_metadata_with_ast_to_json`) -2) Native Rust functions registered into the global namespace via the `Engine::register_XXX` API -3) _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) in static modules - registered via `Engine::register_static_module` -4) Native Rust functions in global modules registered via `Engine::register_global_module` (optional) - -Notice that if a function has been [overloaded][function overloading], only the overriding function's -metadata is included. - - -JSON Schema ------------ - -The JSON schema used to hold functions metadata is very simple, containing a nested structure of -`modules` and a list of `functions`. - -### Modules Schema - -```json -{ - "modules": - { - "sub_module_1": - { - "modules": - { - "sub_sub_module_A": - { - "functions": - [ - { ... function metadata ... }, - { ... function metadata ... }, - { ... function metadata ... }, - { ... function metadata ... }, - ... - ] - }, - "sub_sub_module_B": - { - ... - } - } - }, - "sub_module_2": - { - ... - }, - ... - }, - "functions": - [ - { ... function metadata ... }, - { ... function metadata ... }, - { ... function metadata ... }, - { ... function metadata ... }, - ... - ] -} -``` - -### Function Metadata Schema - -```json -{ - "namespace": "internal" | "global", - "access": "public" | "private", - "name": "fn_name", - "type": "native" | "script", - "numParams": 42, /* number of parameters */ - "params": /* omitted if no parameters */ - [ - { "name": "param_1", "type": "type_1" }, - { "name": "param_2" }, /* no type info */ - { "name": "_", "type": "type_3" }, - ... - ], - "returnType": "ret_type", /* omitted if unknown */ - "signature": "[private] fn_name(param_1: type_1, param_2, _: type_3) -> ret_type", - "docComments": /* omitted if none */ - [ - "/// doc-comment line 1", - "/// doc-comment line 2", - "/** doc-comment block */", - ... - ] -} -``` diff --git a/doc/src/engine/metadata/gen_fn_sig.md b/doc/src/engine/metadata/gen_fn_sig.md deleted file mode 100644 index fe1df178..00000000 --- a/doc/src/engine/metadata/gen_fn_sig.md +++ /dev/null @@ -1,91 +0,0 @@ -Generate Function Signatures -=========================== - -{{#include ../../links.md}} - - -`Engine::gen_fn_signatures` --------------------------- - -As part of a _reflections_ API, `Engine::gen_fn_signatures` returns a list of function _signatures_ -(as `Vec`), each corresponding to a particular function available to that [`Engine`] instance. - -> `fn_name ( param_1: type_1, param_2: type_2, ... , param_n : type_n ) -> return_type` - -### Sources - -Functions from the following sources are included, in order: - -1) Native Rust functions registered into the global namespace via the `Engine::register_XXX` API -2) _Public_ (i.e. non-[`private`]) functions (native Rust or Rhai scripted) in global sub-modules - registered via `Engine::register_static_module`. -3) Native Rust functions in global modules registered via `Engine::register_global_module` (optional) - - -Functions Metadata ------------------- - -Beware, however, that not all function signatures contain parameters and return value information. - -### `Engine::register_XXX` - -For instance, functions registered via `Engine::register_XXX` contain no information on -the names of parameter and their actual types because Rust simply does not make such metadata -available natively. The return type is also undetermined. - -A function registered under the name `foo` with three parameters and unknown return type: - -> `foo(_, _, _)` - -An operator function – again, unknown parameters and return type. -Notice that function names do not need to be valid identifiers. - -> `+(_, _)` - -A [property setter][getters/setters] – again, unknown parameters and return type. -Notice that function names do not need to be valid identifiers. -In this case, the first parameter should be `&mut T` of the custom type and the return value is `()`: - -> `set$prop(_, _, _)` - -### Script-Defined Functions - -Script-defined [function] signatures contain parameter names. Since all parameters, as well as -the return value, are [`Dynamic`] the types are simply not shown. - -A script-defined function always takes dynamic arguments, and the return type is also dynamic, -so no type information is needed: - -> `foo(x, y, z)` - -probably defined as: - -```rust -fn foo(x, y, z) { - ... -} -``` - -is the same as: - -> `foo(x: Dynamic, y: Dynamic, z: Dynamic) -> Result>` - -### Plugin Functions - -Functions defined in [plugin modules] are the best. They contain all the metadata -describing the functions. - -For example, a plugin function `merge`: - -> `merge(list: &mut MyStruct, num: usize, name: &str) -> Option` - -Notice that function names do not need to be valid identifiers. - -For example, an operator defined as a [fallible function] in a [plugin module] via -`#[rhai_fn(name="+=", return_raw)]` returns `Result>`: - -> `+=(list: &mut MyStruct, num: usize, name: &str) -> Result>` - -For example, a [property getter][getters/setters] defined in a [plugin module]: - -> `get$prop(obj: &mut MyStruct) -> String` diff --git a/doc/src/engine/metadata/index.md b/doc/src/engine/metadata/index.md deleted file mode 100644 index 227b1fcf..00000000 --- a/doc/src/engine/metadata/index.md +++ /dev/null @@ -1,28 +0,0 @@ -Functions Metadata -================== - -{{#include ../../links.md}} - -The _metadata_ of a [function] means all relevant information related to a function's -definition including: - -1. Its callable name - -2. Its access mode (public or [private][`private`]) - -3. Its parameters and types (if any) - -4. Its return value and type (if any) - -5. Its nature (i.e. native Rust-based or Rhai script-based) - -6. Its [namespace][function namespace] (module or global) - -7. Its purpose, in the form of [doc-comments] - -8. Usage notes, warnings, etc., in the form of [doc-comments] - -A function's _signature_ encapsulates the first four pieces of information in a single -concise line of definition: - -> `[private] fn_name ( param_1: type_1, param_2: type_2, ... , param_n : type_n ) -> return_type` diff --git a/doc/src/engine/optimize/disable.md b/doc/src/engine/optimize/disable.md deleted file mode 100644 index 8c02726c..00000000 --- a/doc/src/engine/optimize/disable.md +++ /dev/null @@ -1,24 +0,0 @@ -Turn Off Script Optimizations -============================ - -{{#include ../../links.md}} - -When scripts: - -* are known to be run only _once_, - -* are known to contain no dead code, - -* do not use constants in calculations - -the optimization pass may be a waste of time and resources. In that case, turn optimization off -by setting the optimization level to [`OptimizationLevel::None`]. - -Alternatively, turn off optimizations via the [`no_optimize`] feature. - -```rust -let engine = rhai::Engine::new(); - -// Turn off the optimizer -engine.set_optimization_level(rhai::OptimizationLevel::None); -``` diff --git a/doc/src/engine/optimize/eager.md b/doc/src/engine/optimize/eager.md deleted file mode 100644 index 2071154b..00000000 --- a/doc/src/engine/optimize/eager.md +++ /dev/null @@ -1,26 +0,0 @@ -Eager Function Evaluation When Using Full Optimization Level -========================================================== - -{{#include ../../links.md}} - -When the optimization level is [`OptimizationLevel::Full`], the [`Engine`] assumes all functions to be _pure_ -and will _eagerly_ evaluated all function calls with constant arguments, using the result to replace the call. - -This also applies to all operators (which are implemented as functions). - -For instance, the same example above: - -```rust -// When compiling the following with OptimizationLevel::Full... - -const DECISION = 1; - // this condition is now eliminated because 'sign(DECISION) > 0' -if DECISION.sign() > 0 { // is a call to the 'sign' and '>' functions, and they return 'true' - print("hello!"); // this block is promoted to the parent level -} else { - print("boo!"); // this block is eliminated because it is never reached -} - -print("hello!"); // <- the above is equivalent to this - // ('print' and 'debug' are handled specially) -``` diff --git a/doc/src/engine/optimize/index.md b/doc/src/engine/optimize/index.md deleted file mode 100644 index 6852604b..00000000 --- a/doc/src/engine/optimize/index.md +++ /dev/null @@ -1,146 +0,0 @@ -Script Optimization -=================== - -{{#include ../../links.md}} - -Rhai includes an _optimizer_ that tries to optimize a script after parsing. -This can reduce resource utilization and increase execution speed. - -Script optimization can be turned off via the [`no_optimize`] feature. - - -Dead Code Removal ----------------- - -For example, in the following: - -```rust -{ - let x = 999; // NOT eliminated: variable may be used later on (perhaps even an 'eval') - 123; // eliminated: no effect - "hello"; // eliminated: no effect - [1, 2, x, x*2, 5]; // eliminated: no effect - foo(42); // NOT eliminated: the function 'foo' may have side-effects - 666 // NOT eliminated: this is the return value of the block, - // and the block is the last one so this is the return value of the whole script -} -``` - -Rhai attempts to eliminate _dead code_ (i.e. code that does nothing, for example an expression by itself as a statement, -which is allowed in Rhai). - -The above script optimizes to: - -```rust -{ - let x = 999; - foo(42); - 666 -} -``` - - -Constants Propagation --------------------- - -Constants propagation is used to remove dead code: - -```rust -const ABC = true; - -if ABC || some_work() { print("done!"); } // 'ABC' is constant so it is replaced by 'true'... - -if true || some_work() { print("done!"); } // since '||' short-circuits, 'some_work' is never called - -if true { print("done!"); } // <- the line above is equivalent to this - -print("done!"); // <- the line above is further simplified to this - // because the condition is always true -``` - -These are quite effective for template-based machine-generated scripts where certain constant values -are spliced into the script text in order to turn on/off certain sections. - -For fixed script texts, the constant values can be provided in a user-defined [`Scope`] object -to the [`Engine`] for use in compilation and evaluation. - -### Caveat - -If the [constants] are modified later on (yes, it is possible, via Rust functions), -the modified values will not show up in the optimized script. -Only the initialization values of [constants] are ever retained. - -This is almost never a problem because real-world scripts seldom modify a constant, -but the possibility is always there. - - -Eager Operator Evaluations -------------------------- - -Beware, however, that most operators are actually function calls, and those functions can be overridden, -so whether they are optimized away depends on the situation: - -* If the operands are not _constant_ values, it is not optimized. - -* If the operator is [overloaded][operator overloading], it is not optimized because the overloading function may not be _pure_ - (i.e. may cause side-effects when called). - -* If the operator is not _binary_, it is not optimized. Only binary operators are built-in to Rhai. - -* If the operands are not of the same type, it is not optimized. - -* If the operator is not _built-in_ (see list of [built-in operators]), it is not optimized. - -* If the operator is a binary built-in operator for a [standard type][standard types], it is called and replaced by a constant result. - -Rhai guarantees that no external function will be run (in order not to trigger side-effects) during the -optimization process (unless the optimization level is set to [`OptimizationLevel::Full`]). - -```rust -// The following is most likely generated by machine. - -const DECISION = 1; // this is an integer, one of the standard types - -if DECISION == 1 { // this is optimized into 'true' - : -} else if DECISION == 2 { // this is optimized into 'false' - : -} else if DECISION == 3 { // this is optimized into 'false' - : -} else { - : -} -``` - -Because of the eager evaluation of operators for [standard types], many constant expressions will be evaluated -and replaced by the result. - -```rust -let x = (1+2) * 3-4 / 5%6; // will be replaced by 'let x = 9' - -let y = (1 > 2) || (3 < =4); // will be replaced by 'let y = true' -``` - -For operators that are not optimized away due to one of the above reasons, the function calls -are simply left behind: - -```rust -// Assume 'new_state' returns some custom type that is NOT one of the standard types. -// Also assume that the '==; operator is defined for that custom type. -const DECISION_1 = new_state(1); -const DECISION_2 = new_state(2); -const DECISION_3 = new_state(3); - -if DECISION == 1 { // NOT optimized away because the operator is not built-in - : // and may cause side-effects if called! - : -} else if DECISION == 2 { // same here, NOT optimized away - : -} else if DECISION == 3 { // same here, NOT optimized away - : -} else { - : -} -``` - -Alternatively, turn the optimizer to [`OptimizationLevel::Full`]. diff --git a/doc/src/engine/optimize/optimize-levels.md b/doc/src/engine/optimize/optimize-levels.md deleted file mode 100644 index c9e3015f..00000000 --- a/doc/src/engine/optimize/optimize-levels.md +++ /dev/null @@ -1,34 +0,0 @@ -Optimization Levels -================== - -{{#include ../../links.md}} - -There are three levels of optimization: `None`, `Simple` and `Full`. - -* `None` is obvious – no optimization on the AST is performed. - -* `Simple` (default) performs only relatively _safe_ optimizations without causing side-effects - (i.e. it only relies on static analysis and [built-in operators] for constant [standard types], - and will not perform any external function calls). - - However, it is important to bear in mind that _constants propagation_ is performed with the - caveat that, if [constants] are modified later on (yes, it is possible, via Rust functions), - the modified values will not show up in the optimized script. Only the initialization values - of [constants] are ever retained. - - Furthermore, overriding a [built-in operator][built-in operators] in the [`Engine`] afterwards - has no effect after the optimizer replaces an expression with its calculated value. - -* `Full` is _much_ more aggressive, _including_ calling external functions on constant arguments to determine their result. - One benefit to this is that many more optimization opportunities arise, especially with regards to comparison operators. - - -Set Optimization Level ---------------------- - -An [`Engine`]'s optimization level is set via a call to `Engine::set_optimization_level`: - -```rust -// Turn on aggressive optimizations -engine.set_optimization_level(rhai::OptimizationLevel::Full); -``` diff --git a/doc/src/engine/optimize/reoptimize.md b/doc/src/engine/optimize/reoptimize.md deleted file mode 100644 index 38726649..00000000 --- a/doc/src/engine/optimize/reoptimize.md +++ /dev/null @@ -1,38 +0,0 @@ -Re-Optimize an AST -================== - -{{#include ../../links.md}} - -Sometimes it is more efficient to store one single, large script with delimited code blocks guarded by -constant variables. This script is compiled once to an [`AST`]. - -Then, depending on the execution environment, constants are passed into the [`Engine`] and the [`AST`] -is _re_-optimized based on those constants via the `Engine::optimize_ast` method, -effectively pruning out unused code sections. - -The final, optimized [`AST`] is then used for evaluations. - -```rust -// Compile master script to AST -let master_ast = engine.compile( -r" - if SCENARIO == 1 { - do_work(); - } else if SCENARIO == 2 { - do_something(); - } else if SCENARIO == 3 { - do_something_else(); - } else { - do_nothing(); - } -")?; - -// Create a new 'Scope' - put constants in it to aid optimization -let mut scope = Scope::new(); -scope.push_constant("SCENARIO", 1_i64); - -// Re-optimize the AST -let new_ast = engine.optimize_ast(&scope, master_ast.clone(), OptimizationLevel::Simple); - -// 'new_ast' is essentially: 'do_work()' -``` diff --git a/doc/src/engine/optimize/semantics.md b/doc/src/engine/optimize/semantics.md deleted file mode 100644 index 86aa51b9..00000000 --- a/doc/src/engine/optimize/semantics.md +++ /dev/null @@ -1,43 +0,0 @@ -Subtle Semantic Changes After Optimization -========================================= - -{{#include ../../links.md}} - -Some optimizations can alter subtle semantics of the script. - -For example: - -```rust -if true { // condition always true - 123.456; // eliminated - hello; // eliminated, EVEN THOUGH the variable doesn't exist! - foo(42) // promoted up-level -} - -foo(42) // <- the above optimizes to this -``` - -If the original script were evaluated instead, it would have been an error – the variable `hello` does not exist, -so the script would have been terminated at that point with an error return. - -In fact, any errors inside a statement that has been eliminated will silently _disappear_: - -```rust -print("start!"); -if my_decision { /* do nothing... */ } // eliminated due to no effect -print("end!"); - -// The above optimizes to: - -print("start!"); -print("end!"); -``` - -In the script above, if `my_decision` holds anything other than a boolean value, -the script should have been terminated due to a type error. - -However, after optimization, the entire `if` statement is removed (because an access to `my_decision` produces -no side-effects), thus the script silently runs to completion without errors. - -It is usually a _Very Bad Idea™_ to depend on a script failing or such kind of subtleties, but if it turns out to be necessary -(why? I would never guess), turn script optimization off by setting the optimization level to [`OptimizationLevel::None`]. diff --git a/doc/src/engine/optimize/side-effects.md b/doc/src/engine/optimize/side-effects.md deleted file mode 100644 index fbacea0b..00000000 --- a/doc/src/engine/optimize/side-effects.md +++ /dev/null @@ -1,22 +0,0 @@ -Side-Effect Considerations for Full Optimization Level -==================================================== - -{{#include ../../links.md}} - -All of Rhai's built-in functions (and operators which are implemented as functions) are _pure_ -(i.e. they do not mutate state nor cause any side-effects, with the exception of `print` and `debug` -which are handled specially) so using [`OptimizationLevel::Full`] is usually quite safe _unless_ -custom types and functions are registered. - -If custom functions are registered, they _may_ be called (or maybe not, if the calls happen to lie -within a pruned code block). - -If custom functions are registered to overload built-in operators, they will also be called when -the operators are used (in an `if` statement, for example) causing side-effects. - -Therefore, the rule-of-thumb is: - -* _Always_ register custom types and functions _after_ compiling scripts if [`OptimizationLevel::Full`] is used. - -* _DO NOT_ depend on knowledge that the functions have no side-effects, because those functions can change later on and, - when that happens, existing scripts may break in subtle ways. diff --git a/doc/src/engine/optimize/volatility.md b/doc/src/engine/optimize/volatility.md deleted file mode 100644 index dcd1f487..00000000 --- a/doc/src/engine/optimize/volatility.md +++ /dev/null @@ -1,16 +0,0 @@ -Volatility Considerations for Full Optimization Level -=================================================== - -{{#include ../../links.md}} - -Even if a custom function does not mutate state nor cause side-effects, it may still be _volatile_, -i.e. it _depends_ on the external environment and is not _pure_. - -A perfect example is a function that gets the current time – obviously each run will return a different value! - -The optimizer, when using [`OptimizationLevel::Full`], will _merrily assume_ that all functions are _pure_, -so when it finds constant arguments (or none) it eagerly executes the function call and replaces it with the result. - -This causes the script to behave differently from the intended semantics. - -Therefore, **avoid using [`OptimizationLevel::Full`]** if non-_pure_ custom types and/or functions are involved. diff --git a/doc/src/engine/options.md b/doc/src/engine/options.md deleted file mode 100644 index 345a4b4c..00000000 --- a/doc/src/engine/options.md +++ /dev/null @@ -1,19 +0,0 @@ -Engine Configuration Options -=========================== - -{{#include ../links.md}} - -A number of other configuration options are available from the `Engine` to fine-tune behavior and safeguards. - -| Method | Not available under | Description | -| ------------------------ | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| `set_doc_comments` | | enables/disables [doc-comments] | -| `set_optimization_level` | [`no_optimize`] | sets the amount of script _optimizations_ performedSee [script optimization] | -| `set_max_expr_depths` | [`unchecked`] | sets the maximum nesting levels of an expression/statementSee [maximum statement depth] | -| `set_max_call_levels` | [`unchecked`] | sets the maximum number of function call levels (default 50) to avoid infinite recursionSee [maximum call stack depth] | -| `set_max_operations` | [`unchecked`] | sets the maximum number of _operations_ that a script is allowed to consumeSee [maximum number of operations] | -| `set_max_modules` | [`unchecked`] | sets the maximum number of [modules] that a script is allowed to loadSee [maximum number of modules] | -| `set_max_string_size` | [`unchecked`] | sets the maximum length (in UTF-8 bytes) for [strings]See [maximum length of strings] | -| `set_max_array_size` | [`unchecked`], [`no_index`] | sets the maximum size for [arrays]See [maximum size of arrays] | -| `set_max_map_size` | [`unchecked`], [`no_object`] | sets the maximum number of properties for [object maps]See [maximum size of object maps] | -| `disable_symbol` | | disables a certain keyword or operatorSee [disable keywords and operators] | diff --git a/doc/src/engine/raw.md b/doc/src/engine/raw.md deleted file mode 100644 index 017814a5..00000000 --- a/doc/src/engine/raw.md +++ /dev/null @@ -1,28 +0,0 @@ -Raw `Engine` -=========== - -{{#include ../links.md}} - -`Engine::new` creates a scripting [`Engine`] with common functionalities (e.g. printing to the console via `print`). - -In many controlled embedded environments, however, these may not be needed and unnecessarily occupy -application code storage space. - -Use `Engine::new_raw` to create a _raw_ `Engine`, in which only a minimal set of -basic arithmetic and logical operators are supported (see below). - -To add more functionalities to a _raw_ `Engine`, load [packages] into it. - - -Built-in Operators ------------------- - -| Operators | Assignment operators | Supported for types
(see [standard types]) | -| ------------------------- | ---------------------------- | ----------------------------------------------------------------------------- | -| `+`, | `+=` | `INT`, `FLOAT` (if not [`no_float`]), `char`, `ImmutableString` | -| `-`, `*`, `/`, `%`, `~`, | `-=`, `*=`, `/=`, `%=`, `~=` | `INT`, `FLOAT` (if not [`no_float`]) | -| `<<`, `>>` | `<<=`, `>>=` | `INT` | -| `&`, \|, `^` | `&=`, \|=, `^=` | `INT`, `bool` | -| `&&`, \|\| | | `bool` | -| `==`, `!=` | | `INT`, `FLOAT` (if not [`no_float`]), `bool`, `char`, `()`, `ImmutableString` | -| `>`, `>=`, `<`, `<=` | | `INT`, `FLOAT` (if not [`no_float`]), `char`, `()`, `ImmutableString` | diff --git a/doc/src/engine/scope.md b/doc/src/engine/scope.md deleted file mode 100644 index 067fe077..00000000 --- a/doc/src/engine/scope.md +++ /dev/null @@ -1,55 +0,0 @@ -`Scope` – Initializing and Maintaining State -================================================= - -{{#include ../links.md}} - -By default, Rhai treats each [`Engine`] invocation as a fresh one, persisting only the functions that have been defined -but no global state. This gives each evaluation a clean starting slate. - -In order to continue using the same global state from one invocation to the next, -such a state must be manually created and passed in. - -All `Scope` variables are [`Dynamic`], meaning they can store values of any type. - -Under [`sync`], however, only types that are `Send + Sync` are supported, and the entire `Scope` itself -will also be `Send + Sync`. This is extremely useful in multi-threaded applications. - -In this example, a global state object (a `Scope`) is created with a few initialized variables, -then the same state is threaded through multiple invocations: - -```rust -use rhai::{Engine, Scope, EvalAltResult}; - -let engine = Engine::new(); - -// First create the state -let mut scope = Scope::new(); - -// Then push (i.e. add) some initialized variables into the state. -// Remember the system number types in Rhai are i64 (i32 if 'only_i32') ond f64. -// Better stick to them or it gets hard working with the script. -scope - .push("y", 42_i64) - .push("z", 999_i64) - .push_constant("MY_NUMBER", 123_i64) // constants can also be added - .set_value("s", "hello, world!".to_string()); //'set_value' adds a variable when one doesn't exist - // remember to use 'String', not '&str' - -// First invocation -engine.eval_with_scope::<()>(&mut scope, r" - let x = 4 + 5 – y + z + MY_NUMBER + s.len; - y = 1; -")?; - -// Second invocation using the same state -let result = engine.eval_with_scope::(&mut scope, "x")?; - -println!("result: {}", result); // prints 1102 - -// Variable y is changed in the script – read it with 'get_value' -assert_eq!(scope.get_value::("y").expect("variable y should exist"), 1); - -// We can modify scope variables directly with 'set_value' -scope.set_value("y", 42_i64); -assert_eq!(scope.get_value::("y").expect("variable y should exist"), 42); -``` diff --git a/doc/src/engine/var.md b/doc/src/engine/var.md deleted file mode 100644 index c0fb5579..00000000 --- a/doc/src/engine/var.md +++ /dev/null @@ -1,93 +0,0 @@ -Variable Resolver -================= - -{{#include ../links.md}} - -By default, Rhai looks up access to variables from the enclosing block scope, -working its way outwards until it reaches the top (global) level, then it -searches the [`Scope`] that is passed into the `Engine::eval` call. - -There is a built-in facility for advanced users to _hook_ into the variable -resolution service and to override its default behavior. - -To do so, provide a closure to the [`Engine`] via the `Engine::on_var` method: - -```rust -let mut engine = Engine::new(); - -// Register a variable resolver. -engine.on_var(|name, index, context| { - match name { - "MYSTIC_NUMBER" => Ok(Some((42 as INT).into())), - // Override a variable - make it not found even if it exists! - "DO_NOT_USE" => Err(Box::new( - EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE) - )), - // Silently maps 'chameleon' into 'innocent'. - "chameleon" => context.scope().get_value("innocent").map(Some).ok_or_else(|| Box::new( - EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE) - )), - // Return Ok(None) to continue with the normal variable resolution process. - _ => Ok(None) - } -}); -``` - - -Returned Values are Constants ----------------------------- - -Variable values, if any returned, are treated as _constants_ by the script and cannot be assigned to. -This is to avoid needing a mutable reference to the underlying data provider which may not be possible to obtain. - -In order to change these variables, it is best to push them into a custom [`Scope`] instead of using -a variable resolver. Then these variables can be assigned to and their updated values read back after -the script is evaluated. - - -Benefits of Using a Variable Resolver ------------------------------------- - -1. Avoid having to maintain a custom [`Scope`] with all variables regardless of need (because a script may not use them all). - -2. _Short-circuit_ variable access, essentially overriding standard behavior. - -3. _Lazy-load_ variables when they are accessed, not up-front. This benefits when the number of variables is very large, when they are timing-dependent, or when they are expensive to load. - -4. Rename system variables on a script-by-script basis without having to construct different [`Scope`]'s. - - -Function Signature ------------------- - -The function signature passed to `Engine::on_var` takes the following form: - -> `Fn(name: &str, index: usize, context: &EvalContext)` -> `-> Result, Box> + 'static` - -where: - -| Parameter | Type | Description | -| -------------------------- | :-------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `name` | `&str` | variable name | -| `index` | `usize` | an offset from the bottom of the current [`Scope`] that the variable is supposed to reside.
Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`.
If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed. | -| `context` | `&EvalContext` | reference to the current evaluation _context_ | -| • `scope()` | `&Scope` | reference to the current [`Scope`] | -| • `engine()` | `&Engine` | reference to the current [`Engine`] | -| • `source()` | `Option<&str>` | reference to the current source, if any | -| • `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| • `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| • `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | -| • `this_ptr()` | `Option<&Dynamic>` | reference to the current bound [`this`] pointer, if any | -| • `call_level()` | `usize` | the current nesting level of function calls | - -### Return Value - -The return value is `Result, Box>` where: - -| Value | Description | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `Ok(None)` | normal variable resolution process should continue, i.e. continue searching through the [`Scope`] | -| `Ok(Some(Dynamic))` | value of the variable, treated as a constant | -| `Err(Box)` | error that is reflected back to the [`Engine`].
Normally this is `EvalAltResult::ErrorVariableNotFound(var_name, Position::NONE)` to indicate that the variable does not exist, but it can be any `EvalAltResult`. | diff --git a/doc/src/images/logo/favicon.png b/doc/src/images/logo/favicon.png deleted file mode 100644 index f5cf9cac4e07a5a5d65d6b6d0607e08fa1159451..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1238 zcmV;{1S$K8P)-T#jd)wBule_LyR5GvSE{HSOb$IxF6ItXj3t{cFw32}6OpM&VIK z)APcU!qcmH&Ejq0P9+sv7Csg3*X4r3x0W6+^NYpFGJjdDM?zy@YZG=Qt2kc8N=nZN z%gb?R(go%BKGsW|iR@fhVvl$?1|fn3a52R=WB3`AzW8N$@G&4OYUF!M`LpCCSCLtx zh|UU0Qsn6uwIJ0K5>?R?GSU>S{{QW(p$_@V)tv!ocrwkmUT|!|_oiun9-8L&5!fH$ zB3sGN9l-Fr=$jSIy$`MHaCTYI;yZA@0bLJTOplc$ySPnN;q?SsqR?>-O^fB8{qA#o z50N$bsw>#tgFZRmy7U8vFK6^uLqgdA000SaNLh0L01FcU01FcV0GgZ_0008{NklA=YA=RILiSwArXA;vWz)z31Hbxp;3TE|lIe!BxK1yJznG-p6;obKk%g zwy*){o7ri7`{MLQIPAY3tiF1F+RV-YNIKHm`Nli{n}F(z=ca*kNcDL$AsuN=yg9Up zp#@aSN5_HBFf-s90MaBNV4}7At?R?^wT2a-@KXvmdAhFf{fgMH9A7Hjl;hN}d_y^q zKc2c5^j&>S2ip7I`=G8rdjRZGv+ch2zIShwauzv|KRUdte(>LjfN*eM9c+kL#Zz4m z{}mvA`1Gz#6QCTYW8u(__G1@+SNPA0gmTQr!a<9LgQoCVbi&In zqI$d_d_J9@90wSkS`v{U)~!zGC-2A8{9sfIP$VasdK9>)DYu#zR?Yf*q($Jw*vUVO zTCgFk&27`#%iZ#s`v;U|;9sB|c_Zhyumym>0HzX~gBPaeB>(^b07*qoM6N<$f;Nv^ AzyJUM diff --git a/doc/src/images/logo/favicon.svg b/doc/src/images/logo/favicon.svg deleted file mode 100644 index 16aeb468..00000000 --- a/doc/src/images/logo/favicon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-banner-transparent-colour.png b/doc/src/images/logo/rhai-banner-transparent-colour.png deleted file mode 100644 index 8d478bdcffff7cd0c87693c238e8f97966811352..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22200 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 E9~PWf_y7O^ diff --git a/doc/src/images/logo/rhai-banner-transparent-colour.svg b/doc/src/images/logo/rhai-banner-transparent-colour.svg deleted file mode 100644 index 57ee1693..00000000 --- a/doc/src/images/logo/rhai-banner-transparent-colour.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-colour-black.png b/doc/src/images/logo/rhai-colour-black.png deleted file mode 100644 index b874a27eea61bded6e78b6167f48bfc8ec853724..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23348 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-colour-white.png b/doc/src/images/logo/rhai-colour-white.png deleted file mode 100644 index db83cee0cf6f646dd3900359aede760f5f221e34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23363 zcmeEu1y@yF7cRVr2na~GDAGtvi5!&f?(S}o=71vI&7r$Hg@d4UBi$g~-F+9|{TcT% zhGXj%8Ug|WhJ?7VA_4-^8w3Qzwio|_J4uKiGr&LmEQEyQ zofO3c-$;lEak24oaWSzovmqeRMSqPRW^6Yg>(=8+PI`fY5}4<}J~+Oz!pepgXwzpu z({iye4)wZ)Hq>gzmt=QzRv`Hxs;!seMaRVYaX5U@%Q(!hH_j*+K6U3m+`RVkNFPS3 z7uW11I@j$nKJ}m@vL6&9)Q&JqtzFgsagk(b&aoW)f^&a0;v?gtTd8K<@V(VwKdR8T zCedXDk+IXZ*tW3}_rVpLWm#%`EdmJs!PNTqwuXe)ET^HJz3e_3rDB3c`c}9u)FnK+ zosyEnFZ%l(%tn#dFCmjsslj{N>V}bS+|S>Be`e3t$zyay9M^JX;&#OLhS74(Q|h{A zjY=(ABPVDGO+s;Po3QT91TK!s2rm05UfILren}SQb>Bo9qPZLUV1ur`^`Fap3+U_Q zjZ5rlie*Zz-eL0JNARr_{J~#XWxMt+8Y3%w_AQ7ySenw2@l^1iGAhgG&os0DI$+3z zuBYE0IC)`3b6yuSPA~XDc$b>akOElD&eVhiXMj~u?Zq{m5D?IDpZ*{sB&QM~AiP14 z5dNa=JJdJ@_>=8v;WGA|af_o}E2i5pGDHy$2WH)VKPG;JWq_5glCKn7vR3 z7X)6R-%ozkL;N2BxO^UZRrz$+F~AoYT%tJs|F8akHT}Qo5_8lGl1+I9C?ICM3H~Fn z_Hkxpx}|2iCuRqM5{C-zn1MU@$Tpgv2c^t=<)W()5HiVLRqA`LjNxNjgol9uGRaPA zEa*m%$L7-cC6gNz6i0cA_4pfWpb%%oMx$&6MNJlDuy^2uz zo+8T~;yJGQrzbra2U5Cjg?cqf#zbYWJtiLEA3VrtT(?+YGu@!#%b#K*AP|EUGIF#m zM$)oU%zL%*xvlie+U*7_xLEQ<8vZ8(*9-N(4O^Tmb=IseAZ}>ans#z1D#Iv_j5?1aV8!|{u$YrAH z6(oO)e*lvIO#y4`Wocb6@EJGlR0im@96nxOcK1ArCUK*LtKqhOOLhhO`vmrf>&)2d z$;a6URg=WFx`eO%a(EfRMO|AY1z)}QVUg~-iAr|ndXgeD_Elx(<>_{xoFsh+Ul7AF zqe*-0HoN902kKMRpZ|^gKDJc*pVsieTi2Z#S(?+57af)4H*|;#?moT=ouQA;h(p&> zKJ(l#7c7DP_rG^?fOm3_l{FvH)=CWMz{sD&B&d(s^_tfTR=U(^0%wdm@DkZ0XF?t$ zUMBmxgPl#&fVbC4H?gbiR~zaSIV1ArQ7UWiyvE!LLbusqeG*`r06dZ=-86eefE}%v z%Smq{q@rvqa^b5Ss$eP^bN1X{1Vg-i`vIZabGvY1NTdrmOT-)fFD$uQ*J*QY^Z1=L zszm}A6m5!Qn$@13$3BD~Kc)wf&=l(oe|dT~2FTpNwr#npwH=%nqlj8`+ZxmTk|gp; zJUUdZ_0JXATJC?!Y7JU+(4=iR)l0`Qc`rncxrU)#{Wdj9H_nfn`6720GRo!$U7Ls? z5KuYP|9WnzLT?EyJ>VVlDwZ;pZoz*UbwzU(l~jwG%F9x91-|S zKr9R$nPwLbxRu9Kb?Tk5NLQn5TqYFQ;CO?coePq?w8i|aksy3Q*emn5vYSutDeiUg ztg$C}<0G@Qy35vvM(j!^&nkDfh%fjDX$RDZ71>*z+F{^M96XYG3L+sO7zDp6etimW z&BU;anau6syfZemQIbot!9jOlOL)Zd*U8WbeSR?e&}&>l)8Jlj^&RiQWRZKjubB#a zZvZZX4ouKVGlqarc@N^ZxU2txqRgFsF-rqaVJ2xk5j{uAM!dS>{x(EiX%L~9cnu40 zL=uwF6Njn6a5JLn0Hezf4xSudrM^r^LI6o-|0UQ+m5NURz7Hj(+Ni9sLm)E4LG!;^ z?w_um=!xwy50;Uq6X}m%>dv=+8`EF1gfI_f*Xz`WaaRr8xvZ1j{Ht(>0#NZ69RyU} z>=8}tZ3&Om_TMW8j~}eiNtU(raiaifVdXKseRo7o>Fh5?I$e~WVLt35r9{=t*c)re zCQM##|0$fV+?p>~ncS#?I8yrzHa1=zv-E(vEtnJ$6aJZh>EoCDa^?TVkUhgDO%Fmy zXlBM_x+I?m6IUp57&j@8N}ltCza}uywWqbwoh-8h_{0O?lS09P!-tSrZV?QT*q<;# z^(5RHrIr5<{AnDSgsf0z8yPMBs@Glm$lG|2yT+}Q=4Iy%o_Y@3)s7c7RY5U`)T8li=Bcx{lqpqfXzzOC z5@rQxp|%RUJZ=`0`T4FE>#+-WG+s#m(Z3;huE*H=oiaMvd5A~B1~f!$H~aR zFx2J+t2W1rOv; zZ;%N>jz%?T^6BtxG~PkO7TNk;24<rQBo>NBTbP448~% zbwkbN=z*Gxd<&OUfWWV{Z_GZ}z`^=~gH23VCr`ClvWGBLQQrQ0z59LtZW}4gChLHY zNB&IyEyo0=^hHb5^TXM7gYify8ohzuH=g7iFO|NUe1!b4#V)_-n+j2I!;JQJ3Ou({ zJPmoT_W}XoO!I}hJkymQZBD|Lu)`^GE1T@R8-Ma=%3EW-L0{v;$DWw-up5Wowa_Bd zs1mcO@?sr-0ii-i&a3yDy(vo!m+(t7GcphZXR_c$Hob5*d6LN|)N*Gbd`)J307j8ZS@m5)I5*BNx{q-)%65O!?aBMU0Pp{8rJJ3= zsb#ewag6)D8l`9nEg5g(Ozxtw(CVuic@agTmz(KUV0^xVhgdw zj+m+LH}XtGg!*@256Ea*ZVRLesVAf_2*hCHDU_Z?#~Etv7yYj0mRpOKD;CS5MG&n# zL0z{o*N@cM;fL~`N-ahpn-qgs;g95Q5z-FopHm^z_L}+G&+P({s7;?ee#3b&woa5j zdu`9TV`N(@5^MH80kd6fv_4FFPrqk(iJ|)l>>dqR8Go8pfEk}VL@x-rV|>V0qAc0D z*fWaNRZ`}Ye+=UG0ByHn@trSK3Wy+g;jMILOPY4KwAD<-WY8F{bA%8VfmbSp< zlPr`ZQPBaL%5{05Iww`_!k*+Ttjeh7ez)Wv8Z>aE$iLqC5Nwbg>c$Tk&hLx=5YatI z2;CO69MGRro*=6~RQ_z%3FhobMl{hRiyKeMDXRbWAtj=q{DQH(Z}ebrWt7d-Qd8JJ z!7&oByJE!u2+nHrsk6kC84{ydH8?(pL&oc0PmtmNxONC| z4S{@D%tdc@Fqr8EuA_ng)+Vykz$eKJj8Hv^=64AVSc6h)H8GMv>I99*>nW;Wnq$Jo z6km;*ZX%jY3v8t_j#^+*bJfLyLdXcdub&iOX5*JeaI!GR%dAgJshCSQTitb_CX|cA zX}#1Jro3NCIDr|oQGS=4KNxf%1DBBHnYjC|$*pQy2%@V7L~22uZ7tS}fBYAdjGox& z&{brf$&1ne31yB6t^H2Euv_syP|dj(DInBkKbW+UhEkDX@pnNXYbZ=}3fu>a3cad)gEUmL zsyx^AD%bf>7j{iF#dTPWFr05rft6n5-nGYuDs5zVL6)9RZ~ZiuqJ|>9fRh>(TS2Qu z>PO?l6aK#bgY(u|$J0q$f1IC2KQB9Y-Z(&;w~>~cx|B3|PW)s0Jo9;Bj@pR~ZgVY- z=}^P-l3%>TB_KqgV8gp;Ozsa8>EknmS-JePNZls%HfCXM1}8=BA=o7eS@V*C=G41q zLVTz;fja`$m`L>UyG`@u&k+zBK_-{3FYVn|`taZ4`=Dz43R69F=t2hl~~vF_A} zFEBBI>#zHqtT=Jr%JI1K@R*kScCONQHu;3OmkYms8Y2Z3JcGfx*hC8@heTZ0aJBl@ zoisKx1L)HTBzUjf&#?HDC&Ow2gC@2_o6O*Jn!JXxQ!|d3zO(e+gB0#BsCzF7c{f9# zd;1Yzv-3LzjL1ACB&1x8Mr+1sEyPThLw%4!ek{i8>5V47zQ`J^94wC++RS+*5MdWa zGWM*HAa$!msR7|AE>!8Fj>R;gq2(?@Cm`JnX%!Jd&9J&8J)g3np`r`M$dn-)hf@2M zwrFQq9%RB{$=}ej#-puE* zD>566w080Oa+`Opk9fE6+ZeWnyKYDCzs<{B(0T*5B9+Exr3os{XOVfHw!m+m>?U1H zGwJb%-(6d(=np)wSrCug{I5bQ;|%c^xGrjw3`?^>WVCg-?uSsc@>{hXUa_S;hP#AL z^jj8AV{S>uX}&M5r=+7c3$1_y#bNzNVB9$nK787@3HPC{Yfo1|85xK4RYO0`?#cOY zXPZQhZQw6ZNCeiGE>lMa3}w?pt)VzlE)?g7FBfudk(N0tjy-*LE8{^5R7L^7p5T6% zw6SPz;(%|@LXS1joxZmAe(|UJ*==!ZfiV{etk}uSwf-~Yr%5K&VXD(7Sir&H%6&Y(@MEA%Qu`Ua#^CShs z)LM&|Zd6@VMmmZGDRiSb2Y$>@qq6i^|4 z_#!Xp6SO6hqO;s(*p~gBcqz~Knn-nNJ~ys0uoZ@`vL_VJKh5c}DdO{Q-DeOIrg-IN z=JvREF%-`VUC{mb8z2Y``c0RN3&$#Js9Qd(M# zvgj6VF2$EsG?763pNCaXePHWs_@nqBV>9*=j$v6lE!Eut(fM1Uog&q>!dbDK*dn#h zw1FFnVIOi5PH;GVF2fByy&uO=$-(Sn54sri`19-LTB_(P61Klw*&w%X6f%N*9>|o8 zL4r_24kt6x4Z(sc zbp{Lma@^`enxn3AE9ha_#>TF*9k+YI1tNO2LvSCV6uskI8!MZ_tts@7UiTQU zh-61V`wB^6AiQmt`;)rfhs46@ z$I(2jt|t@!93A=%Bg?Uta`$wYJCDn8BZRb|>q39j`JH74@->l0Q;v=|eM?q5PN=Ij z2{-48-nkVK7H;}SGw{^tDkcP0Uy;fg(7Tmvw)0UHPNsXSler;kYmxhvGCGOyEnVR& z!aK(lI3*jl#Yw|4F|&s~OFVB(Ov3cW`I^QIe|W)#?Ck%-B~=uWbYb`LDnYaN(cSEd7~{ zSrS>L7h)6@5Gbp5Hhn(q>Q#R&kQDxV%qAsm9-Z=6@xa>!g;As_Q}0HXmLnkrZYebk z!)`S1v_)1D>vwt3-zPX!zDuLybz8d7@iKbgnR1}KVGnL|HMIRfE$AyfS)unhxAah7 zVm6q>X7um(w{;?{GlP(0fw8|TOeN@YUV}8xAGv=y#w!*rSO>KsQa>8h1PiB9FI}p+ z9M0OmV@YWutYI2Oqn)4{dyopB)%>6D6P9PTC77pn5?$9()A_=MXtsYt`pP!j9QI#<>9RtN$#biI>kB zEXOA>d9MrBY{Sp0_`&=WZUr}%V7Fk44mlug%VTNBDabuhJ+9TZbdlUW(6Ajs#LnBIVD9{_*yQ(H z4THzWY%hB;Mp1HB-o#@{J+LaFQ*djX=Kw@v34rUuKMMEI7*xXZMQ3#Xi#qFo1L&?? zoW;9RuD;skS;~$Y@s%n8%u9xcMB6DA-9bjZe-n@6!+N6oS{)pbWE2Ai;%fl~9fP&g z*|aZxC3fAgDA+=~R#LA3u=pL3k_KvIzfBkcVaXlJHtHX^NJyHq`r3^hzOZCpkGE~kWQb=K7_`F!IQ(Wau0|mQc4h z<(jLam;D)a&o`J<=SVEi&7!z)?G|6R=nn*h2~6ON%V(B}II$lTluyvVuVj6ySwfGt zDWk`txqg#1pF^WkvgQ~j!4#6ME>s-{QCX%kU2F?UMH>@zBwE&8X^^~l6Mm~i7tLw1 zP7oXfyGdxvi3mx`wsGIn7oTUo#{mfs7bHAG$uzqz2?~}sECtMTPwF=Ub&ftv&eHn_D_5afvqIy90T94NRYPn zr_+tPlsM8rSULJ_F(t3vnG_|q9P}e9B|8HJNIAQOS?h}4c4Jj%($?E-- z-G0$&{f-ijRurY#@tl+EF>h2QNefqDBuo65Fy4Ma24|i)4LR}ve zUC_dlG#IZPymm&j9MsI&m#ed?bJ!BcACMUMpg2N;6z>623ZNG35hf^LTo(+PYZalV zQIxFGslmP7p+bdIIz$TybH+@X-Y}9=-06ONz%$i~DCfLI??by`oqlz0{ZFY+FKEv= zI?~XV64w|FPMGuRh7X5b0lN;RBT#KQ|$cT$;}0VPZOqHetnK?nhM#o^@c2y!32SR ziu}8QSolvXmvu2xW}3czjXbd!5`2Jt8K1rH5xroK3Klz~R-?4<2{(@mSrK$=maUhh zb@fW68g=5GCHONZZ-Qwbxy^=qt&3HigWtLR_tH5^>s7LRyfDVQ9@;Vsq+pJP z40Yw*BjeE+tPVjhBYBgpI3_R@_`HSpuM9Z#sW8aOpNC~8BN9VWb+0m^_p)psPxqtY z@Se<;aMkb5$WbCTHv2u%?>s&5Ds=!eDL3L)=pf5ixN~89`~6k)(rjm(8MX45KtH+F zO$k)UyyuyS@M@%Ne)_Q0#_?$Dmg}RqcI73Sm5m{hApw2!s#Lc$%8OPWBANg%EXA=% z$!HhvvLJEl-oOZDikn=LDm!(YeM}W2j#w701}A+(j5wWX_COI1t*6}jgFUo4u;*YW8aR>n1~VH?q#%0N*WWMNQ}s+&NQ;( z52>sWjlDD66pF#}k->PKu@vZ#bLM~T057kET6R@*HZlBP8*c?vk`xO4FjRPpxAASQ zR^C>*Jt;X-yDz+gAiXt4bF%x_g3g>X@qx86J8fu3_eTf~b1(a9IjOeOU!S58l#M%L zx}ona2vX1A3zV(P9pP#M(c}M`<5e4|H3(3JQ6^kYW0}6V4Xl?I>B1Lfy1V=IBB zT{%(jL+!P6_?7)2t*t7CQ6Hz9VAjZ_#ggirT1b$kWy{PCnf`{W}?lx zajI}OQ*vwOes^X*kuZy!kEp#iE$qPLeq9t$#rf!{5M1{4?)RR9h|P?55VoIOetJoO?EA;URl6|Z0ZH#bXcWnq z+SBjLVGGh|*Q!5M{n=*R1tDGI(gz1g=nZ&Bg=pL zwig!C;mz`LjXaCT^Z1~gb#ZZl&!}oWU1_k|6}~%Fp$B)_-JOGpFbj^ImyiBb^_m^R3h)I8f&HPV?v3wa)ZrcwT z-h;`U7#J9Q`?X^r0@pWf%*_ico_-FO1e7>F`7S;O6`HNL*DmTkDZHkX$Q4ETq=-9S znz!Vr2Ce*ecVC$An`}h@r<#i(6mU^%?yTxYk z{NU$m#5E>PrU$S(m#wJ?#LH|nSWd@q zD6frL$g_p8F?`G;ZB$NcBPk#fSVo2f7D}O?0>!?dLlizI zy|i|xNt2V4?x!2~>nuKv7qeERq@;WwORK6JCQCJhoqr>uI71N{%`GiGj{cyqG#|B< zy=3v@JNVh2JK+T6x;q_S^1fVfYIZYC;kJYBRdw6K_v^bUe43>jegb74{<_qqY}!b+ zf}FyJ_iBbA>qCiUWo0@yo0C^JQ?0rYe?Bj%;*ah9z3sU`StCWix=<6=971KYD7U8( zci~n3l(;EcJa4{gcyaV1cQ-4q%d6DUi2CxcuM3l0yt>=O-i4DhMJ`J@R=HNgLF?mf zE0)0B(f#GpW6IK2JinBhM(*&2unG>i!;2Q7O#PU`WQR8K;qv0hdZ87%dwF)=Y=L9YIt zZI88{<+1dB{at+0MQWGoeK8YA0lnIrsbRE-qci{fH?Ab7^V8k{`9Q^bvDw`$!~3Ee zcwwI~<92aLISHT3o{sB69WWKz63H9aCtMPy3e6zKt`E|-45pYVIbvAGga_NE8e);1 zIIs?BwS;eC!d0C!U8rp9BkLAMV02y$Yu)s&BirX2gDI}S_!;(Xs1?61H02`mY6Y|G zH`81XfQeie-OZ>EZ-I^gjlAD3$S7Zvshhl9a9vvKjb*$uP?8n6KLgL*0zDu8VMB1H z0H7Nuy;VuUAHMW$dPp-^vb0a_0F#K>Lnw$%7-MXZZ;j-`E9|0g?-=-%X%vIWlN{wx ze$Wt-RVTi6h3?fo08fxj|8%_^NO7?J&AAYmVz{GdWcMV<+QB063V)B3XZx7E9Qd{9%y zMsme-vQAbnxOEC}e?xO}`^bt>==Pf(3*}0DXLgXoYSiCcN$`}jFD=V63#egA$Cccn z1Dl^es?5U1=GSrnDX`7=bn-6xg4AmLKi?gfOeTs|KnnXqov5vNK>BqNCX31>j=e22WZnTi*wnIj z**~rZ%joFgZFuzHYo0L?)Nuth0puk<0 z^weQKC_ib?o9(9@AcyrVv;Rpg!lBRk#5x~zxQUHYX0DJ1-VT;9K-5!UdtULOel7_; z&zUc^uu&K-PZ_|3w$s*Su!CM?#4Dwg#7JO!V(!!VxDtQMR=rH39`t%bO>bc=C&+7+ zbcwE8IAZc9KgG6bJ3qy-)iEL+1Q$?MeSJO97DCfgVKc~(YMZ6#NBAdI-BwJ%U2y=b z5{)-V_9k$apq6C8UlN0*kPbFy5XYxAvA3Jja38A{9~38=ls;v#Fpi~d`^c^7)HJ+e&mj7Hq8y_=vX~*Dh zJ{{uY)wMrf=~Oux&^PnC-__HrG8B=E{4W#z3A)ZH`DTA~r6g4~&QWl5|4ctyovt=m zw#OqOo8^CEKdBH(AFJurSM)~rk(rx`HvY%knRTgCD{{rSFb$|><>gPHs^XfkCPH_R z*-x9|CT~E{4eeUu|DB!=@_}Z$g0Zgjozf2jDYNLR9u(w9#yJmV7SHPH)i`e=P1+(Zi!URa2T(fRSG83RI$9prl;A5x{&@niJ7T= zoWa+gi&+q^TVPVaws3*d_hTu3xKxFD%*1A~2yOZ8JePnFG&QdmAbFZaduBNA6cs@C zj3`Li3_CFS_E?R3q6D)lUG`@|lyHH14SA z{dx~4pi*#Kju$Ss2V#+OS#SN#IzK2Jl?HF@Y$ZM^#VMnB-YJ(S~sP8yAsOs02KUqUg5KFp8`GfT;hAU zS|ueRX>y7#$bjAeWVJtp-xWa)==DHOB*dd(!9|JT-bZq0XGb)Qh|N%Vyz&w_p6B&? zq7QJmCFt!w?9g+!tRdZPCHVg4yx$AiHw1WwHBWK{J2^Xkv<1tn$x5$@`k5fnSjjV~ z1{ye-U~&GPpK^A9#2(E2G~@P7X?tl+1K^uu>?Y1 zBN{<=y>I8^d2_a%BN|Tf(RnNLi{IMP%0RQjY8SBE3U2Q{WN&WcM(xF~l zK{6bGT7Yf=*tnZ9%isqa;&s|^-kfyW9P(a|SA*P)>^&0t!wx}e9w?AY;o9e0x*mE$ zalj>*)716!9!DafXaD@LAV5V=(8fBFZve)zImo?~%5EYV;DpHVk`s)S=1~I&XgKm? ziu7X>J}KUQXQG^Jw#|YTXgwY_p61m0RF@c_;Tx^3B-;7Bxx6b9b{PqM1nf?%&MF^a z=`oEdWi=FfwmjIfWux4tlfq@ASPHZ#@Kb3MBcoMPyXNTqdBC)QZ}7DTtLb^40~gX!ik<6w zc_>5@Ki7@#{_h*g?A+Wb$@9kM}q^VYa;88RSXO&^Onq*J+$I9)#l4hOxRTYCM; z&0Y@6*vj_jascr1b;lwqi6NfVFvf~z_EY?Hz#pt>0WyaG?8DM}cVYtq7368xlhP;3 z03x)cq@>?vEP~AYY($LwtFqc~GN0=KNOGs-sGoU(u&Nh_w?6|t9c-c|xAm^W>h_8* z9(g0{t?8Ctg^DsRatrh=i&*)ukF+!%P1)_ZKE{=w#T?6CbV$nRT_4YBw6jOlvIF+Q z1z6b=<&jXFc+_$p=D%E4|8i{xzXIw^d?ePSrS^>{98%R>{n*M`A;RQ;%%c(9o3}l*sr*kGx=lfo+R2mW@>QMYB zob8Q=rBq)k8zd-p43H+&3w#o4bwsH%tC-t&OS08BrON7WUh+@QRvBWqiB~tDs92hK z2vl<4|Ne?i;}fa557niYZ>i-auJy{hE3AnW9iRL2Kr%;hxk$sgmYa!+jh2t5WKIKY zfE&2gJ0-FV@3TcyNzllqf&@(aKUyh)Z)_ybjg7GgKP} zCp~l#0aZcepvz{Rw+ma6+Bm$KZ)xmWB+ntgM$V$+= zK8JTg^ygKP-lZjGfX-Ie|?ZZ3GIHSF|_*=YL4BhMP659p~{lOH{>tCDh+t$DCG%W3^ zQn=?T#2XPTTbeq&705biGqMHW8^dX9i-q3>JHii|c8hBWh5BG-=^FXljH|v#m_05l z0)PN|iN&yk?#lL9f!xy=&Gl{e%Rw+s{ht>|w`FV1i-iQ^;G60VwC-kaz#N^3Mzc+L zqixsooY4ByDNPMU`~ph8yeleydtYj3W(v`qoOuyX2mhPjlOOxaWaZvzU~RU$r|LL@jl3HwO05it3$AUA+IQ>A@lo3nrAW4DToT*T&*ohq$_x_n!#B z{l#2Gf!GK=@rGKHF=!GI>NqO|1R&R#4mJVy?pd7Z9RW({#Dr3EN=iQ)j<47G&7-5> z@DWBgelRi%n_N!ZoS596!JeONwy;igO0z-h+e|)PY|e^}!IDs0s_Gy)Q!aSWQh+KB zlv!qG!PMIRcupYHCLQKJIA_59S>WqhId%R)2co0?8d70C73!%Al<_tG6tv2d=Xb$y zN2KIjnwPkXJ?p#eP8*WGrk%K)SlN#jjJGd0)RM;AZp|`WN`G?3L5FdTA$(P?+>Z~tZGTT`Qd((0V~?eg>1$a3a!uy3m4*LPYNNM#2TOgR8MN3y z>#ah&@#NR#qE@Z>$b6#{1$YF=d!S7KPI)svwW6vwlH11Ig}q?Als7j*z3zhW-C4QF3{#pK;JCmX1w6FcWpnZ zv#Qq6bhSxnuOfxl(Vx*gsU?ryGJu6X-R{*iE)~u~cs@&j?-DSmDSnLsyhUdyQs@yWz}>=Qs}`*$$<#O|EapVPz`i~HUlAx zZZp6;Q+hu40O>z0975G#x0Fv&59ksrZs0oGZNxl&U{K7DB$x)ZA=5BfES16?yQEEf zw=lz3^;#PBxTsnhA3j*f+Hdh(vf)&foobiPVXvt1zK9U*aY_~7&~ zHd>yHb$^NWHFu*B3>FmE`{5v&E89Oc7avT%iu`+&|KWa;UuYZ1YD4YCM0+Q9f7g6b$xCz7Wuqs;&%AnHP?}Em@kXPsvcHH~9}2{+(%x zRZ2CI@v(qk4ckg41dpDpY(RyMGjaKQaBoI$Ry4gBuCjFQe2_Y9)U8!|%TuqhjXn=A z)M=k+kBk7eWx909|9T+!z^aOZNgFngqGCP8Epq7TiR}4hu4&=EZE7cWxcZ>w;7`A9 zzM+%gf-68us@8!W*24@5occDiwcCK|`2Z>gnsN_Qx}IfT-2ZKrJh4_nO=~h##Ev>C z`Cu3`rDCb@JX@^9a_=AcueP`WhAy0PZ+)W*JJ4o=;uK4#JNerEiD*E-WCG{T17;cmu+Sm_o&q?%H-8bZQfL|#_qML8TMU+ne0=@I7<@aSy&?ILdnd`hmw`=R|f)@*Vr8lVTrFRb< z3WrG5KD$;hO)m)^k#E7h{F#Kq$5#)S5VNF`{Nj9ZF~ZAB98PHkPX5M-Gy?}2nzz>@ z+T)?cQ#vcCC9sdh^Kui7fzF~Kq*_D;Ru%?74)C*O{5H+Nt}EX7S8?pGat)LGj`Izv0o1c`w&Z@^V0c~*~VeNpI<}SKKp(=O!HIOziqDIv^FwW$4SiaSv3o8#Q%*x7oGROVxWyRY51!#LpE)JPn zS;4^o0uxZMT*m*MN>yb?s|24;*Cc4bnP#?!%nqj_&dA>34BW_Jd z!fm$jdSHiPv;s}5`82b2)eHCXf%)*b&Wes8?>hJi;t;p?`kB}3Kx|>e=mm}-2vmf_ z%<-h6!L&4lKXGa|>@|N=o2#{@Wz*THlpN^0qAd{u|9q_Sd#TMOiT~Dr364YU{wegv znKH!Bk3aN2o?iF!S?4w-63j_Q?b)ps?~;+Ls_L=ZbmyCq34Ri;z;`AWCng&KlZF+q zL!Q6)Guk4rXhXh_ioe2XyGvjki22f|rx%v+Jf7WW? zJj%j9BwWIH%4j+}O1&2q9R~T#5LDjxnkk`X^~Q2e8(V#jZSPf7cKHh~ zgAVx}=w#?s@#RZ{-Y}?o3!ozoYRu!LmYp}~`E3Vp5{Cr(Ti6TT&BzycSwB&ry zS7~P4N2=J|PlT62+VG3&Q?vW2xmz_CPR@7XlyN%`THmy?sXV3wNh3L8SQL?` zhH}Gqh=o)j9)7G6zr%U^JMcM-OOaP7RD%)rR#AyFEA)$^;X{$}c$6Alge`R8%Z7mr1}z8HRTT(#%RNJ71Rybxu$(#$wf70J*#y}rdU%PZ!H z9wtiju+OaP6+&q_&BY|y9~z2|c39ASTDyi6{AcJR1alr$CBld^L!apL(}1T@+j6$n zBIEIH6QIk-1(&&}ap+9)2<`}Ac~Sjt2*ns+c40zOIQ=z>GST|3oVU-;V>RPsHy~Ga zA~OGGgfl09eDBi4Qddd+COE8ZgAKxj6)XAwD-TC_R#U+yG&M%uCEo+VPv z*>*-_XEG8nX*$o@G<@Ae<6iPQMWsz;1y0=@&@liSXuZ3Z2r9?`QY>eiufGmGZIy|4 zOB7njOhy`#xwzB5Z8tmKxqd6q8=z%saQ_y35G(ui{{m?F5JhRbRhNWI^e`KoE5%BV z|2?kDXcWRA*XxR0wIwSv?c-KzMcxXbO?RU_ZG0MBfH6UWQ7wCNa{TKGD7}iwR-8y=aEHx+YP8 z|DQ6_(=nfen;1!iY}Ef6dzo5~rLGHeFDm;A8TZclqU?cB;xn zWs3M$JaZlCHWo-+9tm1hLRt;jSb|gpx0F)VngeY4Y0NmTO zWSG@rs%sa{F8HZ3Olx-+^qrC{r;9Ge8Wdz&PcTy& zg=b@J-nH?3bwdH8B16yz(cw1%0kfIv6v3cHY~ti}iUmFLW7i?e>;_DI%0D}gM>%iu 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 diff --git a/doc/src/images/logo/rhai-colour-white.svg b/doc/src/images/logo/rhai-colour-white.svg deleted file mode 100644 index 9008b4dd..00000000 --- a/doc/src/images/logo/rhai-colour-white.svg +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-icon-colour-black.png b/doc/src/images/logo/rhai-icon-colour-black.png deleted file mode 100644 index 55c7d7149a6115e5cc42a7e90086d1bb8a499316..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17621 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 bdVlJlu;0C$y6MLTP=I*4`njxgN@xNAVnwNU diff --git a/doc/src/images/logo/rhai-icon-colour-black.svg b/doc/src/images/logo/rhai-icon-colour-black.svg deleted file mode 100644 index 05db75f0..00000000 --- a/doc/src/images/logo/rhai-icon-colour-black.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-icon-colour-white.png b/doc/src/images/logo/rhai-icon-colour-white.png deleted file mode 100644 index 4af8351fff70c4d330db9c0e079885b55b51b574..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17375 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 diff --git a/doc/src/images/logo/rhai-icon-colour-white.svg b/doc/src/images/logo/rhai-icon-colour-white.svg deleted file mode 100644 index fde472a9..00000000 --- a/doc/src/images/logo/rhai-icon-colour-white.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-icon-transparent-black.png b/doc/src/images/logo/rhai-icon-transparent-black.png deleted file mode 100644 index c1d0c712e945159cbb8a1b52e5949c2df52a1455..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3991 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 - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-icon-transparent-colour.png b/doc/src/images/logo/rhai-icon-transparent-colour.png deleted file mode 100644 index c7a54fc49a5121c237acb9dde87244a2e1cb92a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15548 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 - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-icon-transparent-white.png b/doc/src/images/logo/rhai-icon-transparent-white.png deleted file mode 100644 index cd63ff1e92bad6b3173690e05f814d36d1336918..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4496 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 D7&1Kh diff --git a/doc/src/images/logo/rhai-icon-transparent-white.svg b/doc/src/images/logo/rhai-icon-transparent-white.svg deleted file mode 100644 index 6648a7ae..00000000 --- a/doc/src/images/logo/rhai-icon-transparent-white.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-logo-transparent-colour-black.png b/doc/src/images/logo/rhai-logo-transparent-colour-black.png deleted file mode 100644 index 9d2f9efb848b96081f741ae875d9bdacf0dd1981..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20505 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-logo-transparent-colour-white.png b/doc/src/images/logo/rhai-logo-transparent-colour-white.png deleted file mode 100644 index 028f6ad66753e8720657f8eab00b3f2bcf6f9fe5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20664 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 IM6N<$f*$V!761SM diff --git a/doc/src/images/logo/rhai-logo-transparent-colour-white.svg b/doc/src/images/logo/rhai-logo-transparent-colour-white.svg deleted file mode 100644 index 3055938d..00000000 --- a/doc/src/images/logo/rhai-logo-transparent-colour-white.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-logo-transparent-sil-black.png b/doc/src/images/logo/rhai-logo-transparent-sil-black.png deleted file mode 100644 index 97b7d1227dbbd34e4bec6258ad3342d91dcb3b02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7392 zcmbVxXH*kk&^{s5gcf=if=Ckq>4YW(3?djQqSPP?(j-Xl2{j1PR6x2&Zw3`m5Qre6 zAR;|fLs0}m69^sN=hydQS&o|)%9JG*mtW_E5O()=h5ea-Gh?-A-yb z*-VU#38lUl`-bP{6qP^;-aY8?Hp=vHWcXoZ(;NGz)x{sXUIL>4Ha}~)(=#5&DEnS= zDqJsXyi-`-zZIghzPKMATF?({MA&}e-*NnWXDd{iAKiDE&pyR1@69|amXdw@p7LxW zlj`bxik93=aE)z4|FLIZFS8-G*?9K4(a=`MI$wXvVk9Zi{{ z3R_8CUoJ-7s<~|7g7V}Fl&scp?7DKLpQ*Rk*KLsg=dSLkX~JUyTKbuVsah}VW#`97tY$G-+F=j1~Rc&SmJ9C8{y)#9^kq-$X$DKx?265 zZNFzEA8;@DVqcRZ+Uvt^nR}#Y&aYhv@ysmL?n}Q2VWZ`DE>B-8d+iE3@YcW_4BZBB zV7I-R`t)qeTQlp~9Xi|M@4l>NNk0pY*ZjiS(^dDY#^4UG`c1b)dXIB#`2=&ghGv+m9HR&kvY0|b`FKn!TXKp%bS zy%>we_L>-UIY#lefU~hz1q(>p@H!c)Ec-{=fezj*edRHflSwREpH>_|i%kn%Ox+dr z^LzL6Nzl{Q-SsW)6#(~4D@79@<+j>Nu@$3{z$#V3#G%l^X#~lY#Kvs_g=Qq$Y6JwT z#y!E|&W^nmTJH{^oy_&0TE&C|RVf|527)tNf4BC&Tog zVByRI@IS3xE;pUmPNl=Rbg?Rpvjy6U6v`09pxY zH;n-H%7OcZnbc<(V6!(q;9#DP1lIiAewK(s(7AEwo#zFBIfZvy^mF^W&q1N$5!ouU zDqO^P74e-j7Yg%mIJ(zD_&k+atH;oi8-T;c?Jv}cibL2egpj$ajDd#|KEU!HY{>XX zAS@!z((GYcGnjw)yOb0ZdP(Gxol`L~CsA@&za~UD$vKKCF&qEzj}B z#9{k?#z4Lq!r{$R`ftGpvZ%t~@{T&fLz>0woman&TpSq@6+INDAdBi3HsG2oLNzIE@WE;kedyen>vx2 z3&G*;ywLfxIU`W9)`W2bj?{Gx(YdHMng70RUSEA4IJ?{u4s!rAj9FW zc$A9_$bN5x!(PhrH91cbhgxVFu~)Rz+j+jb$#8T*-+}%K&dU5N2BefeyF{aE zw{sPf1CoYR<^|5RP6^IIVG8=_*y*!uTL6hQSIflmr&4mrB2x#&$$CTpGgH|dpS^H zMQRQrL;90&MX^zolUwFcM07KdtWg7){)241e(5CwNPH7Wn`QrtY z`2AdmsqW4969a&QsjL`azG1BcUs1o%?boznu!4V_Hu?d#n=pYvx-+83!u>Dgft0{C zKOZg37_hMS!?%b6`mgJY!PIr~jfmUknwS_^&c({^5Rm{fhaAH5XRh+Q7t>1X!f~1B6UxjezGnkHH_G3KWd1c1^nw*!;g)l>XhZ9Vb!(Y8 zsynR}P2h5kx4qVjiNSc<)(ipc!7M%vh5^C!dnWl&J}`=AU1~&@<-N$}<4gki-03X{ zBe?sSsSam40rPmm#|*Zuz4kxTE>AL9@M-b{Hvk&8DgJ~35| zr&}?O@N51>IyQDJhN?8kN>t<+8(WCnTR7{UA7du%@hO5ZCVU9ZfIl@xHmH3^RK<8a z%JVRjsCfVN`TqK=5tB>Mz6U~=8g^^!Ar0wPKH?)-V{<6C7x%@4R8o?%MHE;u76tU z11zBb71%JAw;UzxT`dOP4+aK*evuZWFVC2%F=89-Fm*b(Gjq0_zECP8>g zxYj(e-h86ND4&!skX@s>lgNTBA9B4V`P7`>^n}@u}X&nY( z5E=A7?X3ch0$?3LVRV&ROTr;$c{GbW?$b9iiXw;!moXyP6;8?}c!^aH2a@I*00vY) zr$JdIT=jxe(};NwCz2+q-Y(J)D!OGtqCs8%=<*O}W$=s^M7oRmQKuK*$e&AT6YHpl z!)4380Q7;?s}hhDD)a+WHw02yV*f+JW2BTILVW$4LzM1B0qLD?&jOr@Z$01cXp=j< z+CK)Iz~6e)59kj%bXn~$?6@CiGhj>jMQ9}Ufab9SgzP%K(FsnJF6CL@`e^9Mj-0;R zuri{i1~9^W#7D{SVv+(>(~e}`76c`CUeHx=QFz9;DY^WG&`x_u6GkJkvgcODx^ddi zZ~=Is+jTN?2MS{dJEsHQb3@6IeXn(RwZN1n{{m?j_$^-|p{NxogRxckRgV%%^z$-qkhZ|}`4oE$eu z0WA9rjF>YN5TchalG{s*PrnPr(;pmSS}XO^a_TRj5jMbV#v^Wx!uPI_cKSW6Vg7D( zt>4(vu(|K=C*>}iuqNBX{t7omJl6)SNgle}dQ17ZM~-*ET(_(zE>V8Nz^ zapItihxy-SuLvRJr|h@_Q(>czwI4Bl`*edzGe`YLn_QI|NsRnseh8oL%r*m@iqYBX zu@(yS^j2#O)4%Xxc!)wcQ*Rf=#kE^{_b$6M=1|15)ZW}=PJ{n2;7A6Am}?6b1lcF+ z9FA-FI)y6p+R2i+Dq(|39|%EM)6ZM4SNhU#{`SdgmZ+^T(C_oBQ5~z#TqtGT)22M^ z*!vie70SX3VAkb&@O4>lJa9N>w9E_r$FtI6i;DMY=I) z%*G<A+>B-*eIRXD^UetF8TS!Dvr*QN>~tJcznGSLS@%9mCsyur5W`$ zKHn${t<5pnL%1-ZLv2(Ot~<$F7VWWYKHLi{Qv0xW##GxVF8&@mD-$B=*mlYytC$w$im0Dw)n<`)0pxb!m zl)=GUFz_(atwTpmli@84>8)N+{cLQa?RtMvRM=dQV}j9ISXAJL)3E9uk6$z1GL6Rb z@&q5eb#qq0;i+Yf>&(?$)^NaNZ$-hR-YSv%n3}t2cfAE>J2n>dBOIBJKz8-5<7v-g z`_v+|^-p<$p6cT-Pu|wLvN_W(i~k9saTvuk15ek@0IF!axK&0u^weoN2A{B=1f*=m@*a$31(IHVI}Qi#$pU>Ah&X2l)hyWV4pX=8 z=$$jjd_n?kUa)cxKQe*i7tB(BXZj@mcrfK%^QB~r7BEcjQ?D_x?UwjKXs(N%r&iu! zu%23o%oB%tn(bw3ggUs1!`LE3l}megk(L-Y=B<30qM0d2Lcvby%};W7^yRw(v8>No z_aZU6FFT^ZiDzJx^|9FL>rJjss5r~Qb

A13D|I4Zgwl2KzFMVEi$dXZg@Vzjpk7 zx2R(|r)-hqxuZYko`80i@4M_UiZ6d8Z0;oU?O}ZW%JBMK;v%V1ky?l7oV~iQU3DHX z!f;fR8X2NWKfD~s+ekLM@|<@0JL32ZHtzlI&c~r(a>(3I!ipKioq5y7{~6}^`^MhY z*77kv*&;2hkV#Xwxd5#Pw{zqpiWf+_r9BGy-g3zXhtbko79d(JttkuYv=t&@fKn4nAQTuuei@=5ZU2^9Wd+LQ&mLVGe(@X7ptON{eC+*3riks-8>sagzTucsZtCb^lwZt0rY6YpniRo(%c>wRVfhg8KlTtq<#EMBa~1 z&?$wYivkRJbW^4|>QmLf&vktD=;;z5crvGi$!=7+w0aAB?%dTxE2{-W3i2|P1K4-> z4%=c{KjwAl?0FRn&N)b{*Bc|JC%1@fsY=mR_arK2sVna!vLVjHTJ%!u)d|)=q4S#2 zw(y(*%f76zCCk^VZoVxi=cwKmjY>ML=`eOMSt(p(%saID46zF0!ukNgnCf~-bv5X* z;Sx84vvOC;CyK`{nj_qs*WFdWU5KgCubOcxFUoVkBA#9Rmv-FPHdM)y)O{owr#wtDL5II?RQXWXA)kt@?=rla)Y|h)TfW!mpp#?=X+%K z-d?K9%lzP}x&rJpZB*y;8v{DCNJD^ixf&VkQk9Sb9M8b}B$^5~EFIoeJ@Zx}Knhc|1pn}A;z05U%RU%=$ z%>vai6}-knOs^9x8y}ByBP{~do%@e_&L<3T5r70!f<}U^i-<>wO1x@kIc0HZ(?O_S zRPa*bo#nY<5gch|SmgI$qS;Vnf?+L`ei-iMUU`cs|E}-Lijr~9c>b}4zR6STS&Ha_ zax`r_MsOY}5v%6K*jwgtSUVfdU&al< zHu5#?-9gfouNEzW#G=*l){qC+<1x1EcGeL-=kwyvl1(dRib{I4GZVi|%T>a@ce

tidudLF<5vDUg~Pn2w)V% zE1{Vie-(7d03J~Zs}!UE*c(lCa(Xp~;P}j2-#Axi7bX@cNS0zUWKCPYyRn#B1{Eck zdvQNq>3uGNSqEM&Tf<2gl}y|yS<^TADM$?qo)~Y-Ab2vhaK9a<6Tld%#PF7FvKMjj zIfgTxc%y7hpWU#Y$LJx4c`x=dzSdN<N9bam5Z>tvHFH2oM&-5=cx#Mb zLCQq3If?$L@rNidIjBm~Ledbk4%c;+;x%YrA3d2dXiXH&?|B-e9|7FUaB2NO}L6^Jqg$9$a<~3ZT<0jr)Mv)kqQz9UEc0tud?k;~+o@MP2 z-m|~gd`EDzj;=eI8e!?xT-IC&@{rUJsSWWzVaks11GS;bZz2S~`pS73=^~J;CR%y} z9_ykLV;0u$-Ea@G^n=2tnwdfAUeY3N?OMp$>0`|{b!9tzQ=SVRGABOiyOSW81z?8_ zyN~KJr;3;f070a{4)dJ1%(?vH(60H-qov3M!9H8ChRp2d3mH#+KzOEN=ejv*2(bJR zA^i7)3~%^(Oh}IHPA&Ti*kMA4V4BB(yA0Ish;OoQ#pWBsN3JYgywVl17a6&Uhs;J5 zGSJQQ{uT9cRE043s;NKucaJD?Y_3JoQ>t;J8pl0m$)-B9hJ0}y25>S#Pu-zvlknCb zTc;kmt|fBkU)FE!du}Y@>YU0qni4)$LRF*siyzcTLfy5OkS>gK^25#G4Iz|O$^6|H zAON*49M$f&g=WNeGkK^q=9~ZayvMlViMm6Yzf%bU{1lKaaF+Tz)ynM}32fdF>e1O) z+|E1c@IGT=Gr~r?o0VhH&9=8!tlQSs5?MuZ4mZAzvTREw1WhLO)vFryGseS46d_R(CYbDQ8OdUWY6)m{Ah@cO)X<3!2rK=uloYY z5!P<*TP3lxb@0`R(b2a`GNT2&alF|qftElkqs1E2R`eeWjxw?VzI{B0ntu4`69bG= z{oSK!;n&=jsXc(FaLi3N%YTvq_fd`gElA_@yR|xpT30~h1wnbQ z26c)W{VJMdD3bTU4>cz6ha;jY0C?4}usuerYb*Y$sq(r9TP$i&xu+B7bzeTa{{rux z&e?qxrBiO3W1wK|$K}o!vGYfVlv@dd7|0iCN9mj)-84ODYIl*RhAEF5&O&)@In5IC zd(3EU$yS{+&?1Ud|I)9!L-9JvJH?PERs$~xj21z~CVVdISAJ@=5RK%E)*jSo3TRB! z7i_N~QOez+L0Y4nG8u9hWh(BH4dC(|j7tgDfC;5(=NqFjf8ODvcUh5tkD7Gp31@^? z61n@n5S1&TZ$&kPf8-0kvI0x5d!H?%DSS{P<$1uQ<}%nj^5iHh`!mfAn)R+3m!1(> zk{4O?R4DO~(`dJ0ug<^j*oY+ZO_jb8(DuuI=&*%PrkI`}N-$a2jaiK(-z9NjC8=1m zUCe>VMuy9(II(rQhkU~S0ZyKIz1Z`~6eIN4ig8)e3Q!8^cELo)|L9ZnPRe3sJ>IS7$_uu zf5$7Sk0TdS6lm=gYj!)Er>L)BIl-I zed%v?Hgt^Hdg=WERQ+V;!2paLUd`HS?OpntR!pQlGs!7pu3z3DdwblVIe>4Ou@cK1|vjBeKMQlNOd!XE`V#20VE^3$M^KklzLr`a6g zC27XAS!pN5HLk0IUL(N}$cM73DB7Ed1F*mKB$PCy(taixhp2o+Z_b#Rb`tIIw2@mw z$c~5Fq-VhEZb)o@v-%wY_72`awQ%~35q8C(&P(C^Bac zj+_fR+^RS4&SoP2wpwu{-72?D!i(ih*7mJ8ks5!~0DR%$7pVU1v8WSUPc%1<% G`hNhR0o;)Q diff --git a/doc/src/images/logo/rhai-logo-transparent-sil-black.svg b/doc/src/images/logo/rhai-logo-transparent-sil-black.svg deleted file mode 100644 index 565c24ba..00000000 --- a/doc/src/images/logo/rhai-logo-transparent-sil-black.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-logo-transparent-sil-white.png b/doc/src/images/logo/rhai-logo-transparent-sil-white.png deleted file mode 100644 index 99049d1817d225b9e5867ce9a7220ada8446cd5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8310 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 RX5L%_;Mc5->#n*#{2vnw - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-sil-black.png b/doc/src/images/logo/rhai-sil-black.png deleted file mode 100644 index 92b0b7e6f8acb6e0c8a9be82404a2c8beaa3373b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11249 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/images/logo/rhai-sil-white.png b/doc/src/images/logo/rhai-sil-white.png deleted file mode 100644 index c1466588a3ce31c7b8b0415d6e79dabdf862e87e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12297 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/src/language/arrays.md b/doc/src/language/arrays.md deleted file mode 100644 index 492800b9..00000000 --- a/doc/src/language/arrays.md +++ /dev/null @@ -1,218 +0,0 @@ -Arrays -====== - -{{#include ../links.md}} - -Arrays are first-class citizens in Rhai. Like C, arrays are accessed with zero-based, non-negative integer indices: - -> _array_ `[` _index_ `]` - -Array literals are built within square brackets '`[`' ... '`]`' and separated by commas '`,`': - -> `[` _value_ `,` _value_ `,` `...` `,` _value_ `]` -> -> `[` _value_ `,` _value_ `,` `...` `,` _value_ `,` `]` `// trailing comma is OK` - -All elements stored in an array are [`Dynamic`], and the array can freely grow or shrink with elements added or removed. - -The Rust type of a Rhai array is `rhai::Array`. - -[`type_of()`] an array returns `"array"`. - -Arrays are disabled via the [`no_index`] feature. - -The maximum allowed size of an array can be controlled via `Engine::set_max_array_size` -(see [maximum size of arrays]. - - -Built-in Functions ------------------ - -The following methods (mostly defined in the [`BasicArrayPackage`][packages] but excluded if using a [raw `Engine`]) operate on arrays: - -| Function | Parameter(s) | Description | -| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `push` | element to insert | inserts an element at the end | -| `append` | array to append | concatenates the second array to the end of the first | -| `+=` operator | 1) array
2) element to insert (not another array) | inserts an element at the end | -| `+=` operator | 1) array
2) array to append | concatenates the second array to the end of the first | -| `+` operator | 1) first array
2) second array | concatenates the first array with the second | -| `==` operator | 1) first array
2) second array | are the two arrays the same (elements compared with the `==` operator, if defined)? | -| `!=` operator | 1) first array
2) second array | are the two arrays different (elements compared with the `==` operator, if defined)? | -| `in` operator | item to find | does the array contain the item (compared with the `==` operator, if defined)? | -| `insert` | 1) element to insert
2) position, beginning if < 0, end if > length | inserts an element at a certain index | -| `pop` | _none_ | removes the last element and returns it ([`()`] if empty) | -| `shift` | _none_ | removes the first element and returns it ([`()`] if empty) | -| `extract` | 1) start position, beginning if < 0, end if > length
2) _(optional)_ number of items to extract, none if < 0 | extracts a portion of the array into a new array | -| `remove` | index | removes an element at a particular index and returns it ([`()`] if the index is not valid) | -| `reverse` | _none_ | reverses the array | -| `len` method and property | _none_ | returns the number of elements | -| `pad` | 1) target length
2) element to pad | pads the array with an element to at least a specified length | -| `clear` | _none_ | empties the array | -| `truncate` | target length | cuts off the array at exactly a specified length (discarding all subsequent elements) | -| `chop` | target length | cuts off the head of the array, leaving the tail at exactly a specified length | -| `drain` | 1) [function pointer] to predicate (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `drain` | 1) start position, beginning if < 0, end if > length
2) number of items to remove, none if < 0 | removes a portion of the array, returning the removed items (not in original order) | -| `retain` | 1) [function pointer] to predicate (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | removes all items (returning them) that do not return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `retain` | 1) start position, beginning if < 0, end if > length
2) number of items to retain, none if < 0 | retains a portion of the array, removes all other items and returning them (not in original order) | -| `splice` | 1) start position, beginning if < 0, end if > length
2) number of items to remove, none if < 0
3) array to insert | replaces a portion of the array with another (not necessarily of the same length as the replaced portion) | -| `filter` | [function pointer] to predicate (usually a [closure]) | constructs a new array with all items that return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `index_of` | [function pointer] to predicate (usually a [closure]) | returns the index of the first item in the array that returns `true` when called with the predicate function, or -1 if not found:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `map` | [function pointer] to conversion function (usually a [closure]) | constructs a new array with all items mapped to the result of applying the conversion function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `reduce` | 1) [function pointer] to accumulator function (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially)
2nd parameter: array item
3rd parameter: _(optional)_ offset index | -| `reduce_rev` | 1) [function pointer] to accumulator function (usually a [closure])
2) _(optional)_ [function pointer] to function (usually a [closure]) that provides the initial value | reduces the array (in reverse order) into a single value via the accumulator function:
1st parameter: accumulated value ([`()`] initially)
2nd parameter: array item
3rd parameter: _(optional)_ offset index | -| `some` | [function pointer] to predicate (usually a [closure]) | returns `true` if any item returns `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `all` | [function pointer] to predicate (usually a [closure]) | returns `true` if all items return `true` when called with the predicate function:
1st parameter: array item
2nd parameter: _(optional)_ offset index | -| `sort` | [function pointer] to a comparison function (usually a [closure]) | sorts the array with a comparison function:
1st parameter: first item
2nd parameter: second item
return value: `INT` < 0 if first < second, > 0 if first > second, 0 if first == second | - - -Use Custom Types With Arrays ---------------------------- - -To use a [custom type] with arrays, a number of array functions need to be manually implemented, -in particular `push`, `insert`, `pad` and the `+=` operator. In addition, the `==` operator must be -implemented for the [custom type] in order to support the `in` operator which uses `==` to -compare elements. - -See the section on [custom types] for more details. - - -Examples --------- - -```rust -let y = [2, 3]; // y == [2, 3] - -let y = [2, 3,]; // y == [2, 3] - -y.insert(0, 1); // y == [1, 2, 3] - -y.insert(999, 4); // y == [1, 2, 3, 4] - -y.len == 4; - -y[0] == 1; -y[1] == 2; -y[2] == 3; -y[3] == 4; - -(1 in y) == true; // use 'in' to test if an item exists in the array -(42 in y) == false; // 'in' uses the '==' operator (which users can override) - // to check if the target item exists in the array - -y[1] = 42; // y == [1, 42, 3, 4] - -(42 in y) == true; - -y.remove(2) == 3; // y == [1, 42, 4] - -y.len == 3; - -y[2] == 4; // elements after the removed element are shifted - -ts.list = y; // arrays can be assigned completely (by value copy) - -ts.list[1] == 42; - -[1, 2, 3][0] == 1; // indexing on array literal - -fn abc() { - [42, 43, 44] // a function returning an array -} - -abc()[0] == 42; - -y.push(4); // y == [1, 42, 4, 4] - -y += 5; // y == [1, 42, 4, 4, 5] - -y.len == 5; - -y.shift() == 1; // y == [42, 4, 4, 5] - -y.chop(3); // y == [4, 4, 5] - -y.len == 3; - -y.pop() == 5; // y == [4, 4] - -y.len == 2; - -for item in y { // arrays can be iterated with a 'for' statement - print(item); -} - -y.pad(6, "hello"); // y == [4, 4, "hello", "hello", "hello", "hello"] - -y.len == 6; - -y.truncate(4); // y == [4, 4, "hello", "hello"] - -y.len == 4; - -y.clear(); // y == [] - -y.len == 0; - -let a = [42, 123, 99]; - -a.map(|v| v + 1); // returns [43, 124, 100] - -a.map(|v, i| v + i); // returns [42, 124, 101] - -a.filter(|v| v > 50); // returns [123, 99] - -a.filter(|v, i| i == 1); // returns [123] - -// Use a closure to provide the initial value -a.reduce(|sum, v| sum + v, || 0) == 264; - -// Detect the initial value of '()' -a.reduce( - |sum, v| if sum.type_of() == "()" { v } else { sum + v } -) == 264; - -// Detect the initial value via index -a.reduce(|sum, v, i| - if i == 0 { v } else { sum + v } -) == 264; - -// Use a closure to provide the initial value -a.reduce_rev(|sum, v| sum + v, || 0) == 264; - -// Detect the initial value of '()' -a.reduce_rev( - |sum, v| if sum.type_of() == "()" { v } else { sum + v } -) == 264; - -// Detect the initial value via index -a.reduce_rev(|sum, v, i| - if i == 2 { v } else { sum + v } -) == 264; - -a.some(|v| v > 50); // returns true - -a.some(|v, i| v < i); // returns false - -a.none(|v| v != 0); // returns false - -a.none(|v, i| v == i); // returns true - -a.all(|v| v > 50); // returns false - -a.all(|v, i| v > i); // returns true - -a.splice(1, 1, [1, 3, 2]); // a == [42, 1, 3, 2, 99] - -a.extract(1, 3); // returns [1, 3, 2] - -a.sort(|x, y| x - y); // a == [1, 2, 3, 42, 99] - -a.drain(|v| v <= 1); // a == [2, 3, 42, 99] - -a.drain(|v, i| i >= 3); // a == [2, 3, 42] - -a.retain(|v| v > 10); // a == [42] - -a.retain(|v, i| i > 0); // a == [] -``` diff --git a/doc/src/language/assignment-op.md b/doc/src/language/assignment-op.md deleted file mode 100644 index 5cfd73c5..00000000 --- a/doc/src/language/assignment-op.md +++ /dev/null @@ -1,66 +0,0 @@ -Compound Assignment Operators -============================= - -{{#include ../links.md}} - - -```rust -let number = 9; - -number += 8; // number = number + 8 - -number -= 7; // number = number - 7 - -number *= 6; // number = number * 6 - -number /= 5; // number = number / 5 - -number %= 4; // number = number % 4 - -number ~= 3; // number = number ~ 3 - -number <<= 2; // number = number << 2 - -number >>= 1; // number = number >> 1 - -number &= 0x00ff; // number = number & 0x00ff; - -number |= 0x00ff; // number = number | 0x00ff; - -number ^= 0x00ff; // number = number ^ 0x00ff; -``` - - -The Flexible `+=` ----------------- - -The the `+` and `+=` operators are often [overloaded][function overloading] to perform -build-up operations for different data types. - -For example, it is used to build [strings]: - -```rust -let my_str = "abc"; -my_str += "ABC"; -my_str += 12345; - -my_str == "abcABC12345" -``` - -to concatenate [arrays]: - -```rust -let my_array = [1, 2, 3]; -my_array += [4, 5]; - -my_array == [1, 2, 3, 4, 5]; -``` - -and mix two [object maps] together: - -```rust -let my_obj = #{a:1, b:2}; -my_obj += #{c:3, d:4, e:5}; - -my_obj.len() == 5; -``` diff --git a/doc/src/language/comments.md b/doc/src/language/comments.md deleted file mode 100644 index 111e370c..00000000 --- a/doc/src/language/comments.md +++ /dev/null @@ -1,24 +0,0 @@ -Comments -======== - -{{#include ../links.md}} - -Comments are C-style, including '`/*` ... `*/`' pairs for block comments -and '`//`' for comments to the end of the line. - -Comments can be nested. - -```rust -let /* intruder comment */ name = "Bob"; - -// This is a very important one-line comment - -/* This comment spans - multiple lines, so it - only makes sense that - it is even more important */ - -/* Fear not, Rhai satisfies all nesting needs with nested comments: - /*/*/*/*/**/*/*/*/*/ -*/ -``` diff --git a/doc/src/language/constants.md b/doc/src/language/constants.md deleted file mode 100644 index 31398f42..00000000 --- a/doc/src/language/constants.md +++ /dev/null @@ -1,97 +0,0 @@ -Constants -========= - -{{#include ../links.md}} - -Constants can be defined using the `const` keyword and are immutable. - -Constants follow the same naming rules as [variables]. - -```rust -const x = 42; - -print(x * 2); // prints 84 - -x = 123; // <- syntax error: cannot assign to constant -``` - -```rust -const x; // 'x' is a constant '()' - -const x = 40 + 2; // 'x' is a constant 42 -``` - - -Manually Add Constant into Custom Scope --------------------------------------- - -It is possible to add a constant into a custom [`Scope`] so it'll be available to scripts -running with that [`Scope`]. - -When added to a custom [`Scope`], a constant can hold any value, not just a literal value. - -It is very useful to have a constant value hold a [custom type], which essentially acts -as a [_singleton_](../patterns/singleton.md). - -```rust -use rhai::{Engine, Scope, RegisterFn}; - -#[derive(Debug, Clone)] -struct TestStruct(i64); // custom type - -let mut engine = Engine::new(); - -engine - .register_type_with_name::("TestStruct") // register custom type - .register_get("value", |obj: &mut TestStruct| obj.0), // property getter - .register_fn("update_value", - |obj: &mut TestStruct, value: i64| obj.0 = value // mutating method - ); - -let mut scope = Scope::new(); // create custom scope - -scope.push_constant("MY_NUMBER", TestStruct(123_i64)); // add constant variable - -// Beware: constant objects can still be modified via a method call! -engine.consume_with_scope(&mut scope, -r" - MY_NUMBER.update_value(42); - print(MY_NUMBER.value); // prints 42 -")?; -``` - - -Caveat – Constants Can be Modified via Rust ------------------------------------------------- - -A custom type stored as a constant cannot be modified via script, but _can_ be modified via -a registered Rust function that takes a first `&mut` parameter – because there is no way for -Rhai to know whether the Rust function modifies its argument! - -```rust -const x = 42; // a constant - -x.increment(); // call 'increment' defined in Rust with '&mut' first parameter - -x == 43; // value of 'x' is changed! - -fn double() { - this *= 2; // function doubles 'this' -} - -let y = 1; // 'y' is not constant and mutable - -y.double(); // double it... - -y == 2; // value of 'y' is changed as expected - -x.double(); // <- error: cannot modify constant 'this' - -x == 43; // value of 'x' is unchanged by script -``` - -This is important to keep in mind because the script [optimizer][script optimization] -by default does _constant propagation_ as a operation. - -If a constant is eventually modified by a Rust function, the optimizer will not see -the updated value and will propagate the original initialization value instead. diff --git a/doc/src/language/convert.md b/doc/src/language/convert.md deleted file mode 100644 index a14feed3..00000000 --- a/doc/src/language/convert.md +++ /dev/null @@ -1,56 +0,0 @@ -Value Conversions -================= - -{{#include ../links.md}} - - -Convert Between Integer and Floating-Point ------------------------------------------ - -The `to_float` function converts a supported number to `FLOAT` (defaults to `f64`). - -The `to_int` function converts a supported number to `INT` (`i32` or `i64` depending on [`only_i32`]). - -That's it; for other conversions, register custom conversion functions. - -```rust -let x = 42; - -let y = x * 100.0; // <- error: cannot multiply i64 with f64 - -let y = x.to_float() * 100.0; // works - -let z = y.to_int() + x; // works - -let c = 'X'; // character - -print("c is '" + c + "' and its code is " + c.to_int()); // prints "c is 'X' and its code is 88" -``` - - -Parse String into Number ------------------------- - -The `parse_float` function converts a [string] into a `FLOAT` (defaults to `f64`). - -The `parse_int` function converts a [string] into an `INT` (`i32` or `i64` depending on [`only_i32`]). -An optional radix (2-36) can be provided to parse the [string] into a number of the specified radix. - -```rust -let x = parse_float("123.4"); // parse as floating-point -x == 123.4; -type_of(x) == "f64"; - -let dec = parse_int("42"); // parse as decimal -let dec = parse_int("42", 10); // radix = 10 is the default -dec == 42; -type_of(dec) == "i64"; - -let bin = parse_int("110", 2); // parse as binary (radix = 2) -bin == 0b110; -type_of(bin) == "i64"; - -let hex = parse_int("ab", 16); // parse as hex (radix = 16) -hex == 0xab; -type_of(hex) == "i64"; -``` diff --git a/doc/src/language/do.md b/doc/src/language/do.md deleted file mode 100644 index c1129944..00000000 --- a/doc/src/language/do.md +++ /dev/null @@ -1,28 +0,0 @@ -`do` Loop -========= - -{{#include ../links.md}} - -`do` loops have two opposite variants: `do` ... `while` and `do` ... `until`. - -Like the `while` loop, `continue` can be used to skip to the next iteration, by-passing all following statements; -`break` can be used to break out of the loop unconditionally. - -```rust -let x = 10; - -do { - x -= 1; - if x < 6 { continue; } // skip to the next iteration - print(x); - if x == 5 { break; } // break out of do loop -} while x > 0; - - -do { - x -= 1; - if x < 6 { continue; } // skip to the next iteration - print(x); - if x == 5 { break; } // break out of do loop -} until x == 0; -``` diff --git a/doc/src/language/doc-comments.md b/doc/src/language/doc-comments.md deleted file mode 100644 index a3fdcf91..00000000 --- a/doc/src/language/doc-comments.md +++ /dev/null @@ -1,77 +0,0 @@ -Doc-Comments -============ - -{{#include ../links.md}} - -Similar to Rust, comments starting with `///` (three slashes) or `/**` (two asterisks) are -_doc-comments_. - -Doc-comments can only appear in front of [function] definitions, not any other elements: - -```rust -/// This is a valid one-line doc-comment -fn foo() {} - -/** This is a - ** valid block - ** doc-comment - **/ -fn bar(x) { - /// Syntax error - this doc-comment is invalid - x + 1 -} - -/** Syntax error - this doc-comment is invalid */ -let x = 42; - -/// Syntax error - this doc-comment is also invalid -{ - let x = 42; -} -``` - - -Special Cases -------------- - -Long streams of `//////...` and `/*****...` do _NOT_ form doc-comments. -This is consistent with popular comment block styles for C-like languages. - -```rust -/////////////////////////////// <- this is not a doc-comment -// This is not a doc-comment // <- this is a normal comment -/////////////////////////////// <- this is not a doc-comment - -// However, watch out for comment lines starting with '///' - -////////////////////////////////////////// <- this is not a doc-comment -/// This, however, IS a doc-comment!!! /// <- this starts with '///' -////////////////////////////////////////// <- this is not a doc-comment - -/**************************************** - * * - * This is also not a doc-comment block * - * so we don't have to put this in * - * front of a function. * - * * - ****************************************/ -``` - - -Using Doc-Comments ------------------- - -Doc-comments are stored within the script's [`AST`] after compilation. - -The `AST::iter_functions` method provides a `ScriptFnMetadata` instance -for each function defined within the script, which includes doc-comments. - -Doc-comments never affect the evaluation of a script nor do they incur -significant performance overhead. However, third party tools can take advantage -of this information to auto-generate documentation for Rhai script functions. - - -Disabling Doc-Comments ----------------------- - -Doc-comments can be disabled via the `Engine::set_doc_comments` method. diff --git a/doc/src/language/dynamic.md b/doc/src/language/dynamic.md deleted file mode 100644 index 8c10d9f8..00000000 --- a/doc/src/language/dynamic.md +++ /dev/null @@ -1,100 +0,0 @@ -Dynamic Values -============== - -{{#include ../links.md}} - -A `Dynamic` value can be _any_ type. However, under [`sync`], all types must be `Send + Sync`. - - -Use `type_of()` to Get Value Type --------------------------------- - -Because [`type_of()`] a `Dynamic` value returns the type of the actual value, -it is usually used to perform type-specific actions based on the actual value's type. - -```c -let mystery = get_some_dynamic_value(); - -switch type_of(mystery) { - "i64" => print("Hey, I got an integer here!"), - "f64" => print("Hey, I got a float here!"), - "string" => print("Hey, I got a string here!"), - "bool" => print("Hey, I got a boolean here!"), - "array" => print("Hey, I got an array here!"), - "map" => print("Hey, I got an object map here!"), - "Fn" => print("Hey, I got a function pointer here!"), - "TestStruct" => print("Hey, I got the TestStruct custom type here!"), - _ => print("I don't know what this is: " + type_of(mystery)) -} -``` - - -Functions Returning `Dynamic` ----------------------------- - -In Rust, sometimes a `Dynamic` forms part of a returned value – a good example is an [array] -which contains `Dynamic` elements, or an [object map] which contains `Dynamic` property values. - -To get the _real_ values, the actual value types _must_ be known in advance. -There is no easy way for Rust to decide, at run-time, what type the `Dynamic` value is -(short of using the `type_name` function and match against the name). - - -Type Checking and Casting ------------------------- - -A `Dynamic` value's actual type can be checked via the `is` method. - -The `cast` method then converts the value into a specific, known type. - -Alternatively, use the `try_cast` method which does not panic but returns `None` when the cast fails. - -```rust -let list: Array = engine.eval("...")?; // return type is 'Array' -let item = list[0]; // an element in an 'Array' is 'Dynamic' - -item.is::() == true; // 'is' returns whether a 'Dynamic' value is of a particular type - -let value = item.cast::(); // if the element is 'i64', this succeeds; otherwise it panics -let value: i64 = item.cast(); // type can also be inferred - -let value = item.try_cast::()?; // 'try_cast' does not panic when the cast fails, but returns 'None' -``` - -Type Name ---------- - -The `type_name` method gets the name of the actual type as a static string slice, -which can be `match`-ed against. - -```rust -let list: Array = engine.eval("...")?; // return type is 'Array' -let item = list[0]; // an element in an 'Array' is 'Dynamic' - -match item.type_name() { // 'type_name' returns the name of the actual Rust type - "i64" => ... - "alloc::string::String" => ... - "bool" => ... - "crate::path::to::module::TestStruct" => ... -} -``` - -**Note:** `type_name` always returns the _full_ Rust path name of the type, even when the type -has been registered with a friendly name via `Engine::register_type_with_name`. This behavior -is different from that of the [`type_of`][`type_of()`] function in Rhai. - - -Conversion Traits ----------------- - -The following conversion traits are implemented for `Dynamic`: - -* `From` (`i32` if [`only_i32`]) -* `From` (if not [`no_float`]) -* `From` -* `From` -* `From` -* `From` -* `From>` (into an [array]) -* `From>` (into an [object map]) -* `From` (into a [timestamp] if not [`no_std`]) diff --git a/doc/src/language/eval.md b/doc/src/language/eval.md deleted file mode 100644 index 7e9bdd4d..00000000 --- a/doc/src/language/eval.md +++ /dev/null @@ -1,83 +0,0 @@ -`eval` Function -=============== - -{{#include ../links.md}} - -Or "How to Shoot Yourself in the Foot even Easier" ------------------------------------------------- - -Saving the best for last, there is the ever-dreaded... `eval` function! - -```rust -let x = 10; - -fn foo(x) { x += 12; x } - -let script = "let y = x;"; // build a script -script += "y += foo(y);"; -script += "x + y"; - -let result = eval(script); // <- look, JavaScript, we can also do this! - -result == 42; - -x == 10; // prints 10: functions call arguments are passed by value -y == 32; // prints 32: variables defined in 'eval' persist! - -eval("{ let z = y }"); // to keep a variable local, use a statement block - -print(z); // <- error: variable 'z' not found - -"print(42)".eval(); // <- nope... method-call style doesn't work with 'eval' -``` - -Script segments passed to `eval` execute inside the current [`Scope`], so they can access and modify _everything_, -including all variables that are visible at that position in code! It is almost as if the script segments were -physically pasted in at the position of the `eval` call. - - -Cannot Define New Functions --------------------------- - -New functions cannot be defined within an `eval` call, since functions can only be defined at the _global_ level, -not inside another function call! - -```rust -let script = "x += 32"; -let x = 10; -eval(script); // variable 'x' in the current scope is visible! -print(x); // prints 42 - -// The above is equivalent to: -let script = "x += 32"; -let x = 10; -x += 32; -print(x); -``` - - -`eval` is Evil --------------- - -For those who subscribe to the (very sensible) motto of ["`eval` is evil"](http://linterrors.com/js/eval-is-evil), -disable `eval` using [`Engine::disable_symbol`][disable keywords and operators]: - -```rust -engine.disable_symbol("eval"); // disable usage of 'eval' -``` - -`eval` can also be disabled by overloading it, probably with something that throws: - -```rust -fn eval(script) { throw "eval is evil! I refuse to run " + script } - -let x = eval("40 + 2"); // throws "eval is evil! I refuse to run 40 + 2" -``` - -Or overload it from Rust: - -```rust -engine.register_result_fn("eval", |script: String| -> Result<(), Box> { - Err(format!("eval is evil! I refuse to run {}", script).into()) -}); -``` diff --git a/doc/src/language/fn-anon.md b/doc/src/language/fn-anon.md deleted file mode 100644 index a2e45706..00000000 --- a/doc/src/language/fn-anon.md +++ /dev/null @@ -1,60 +0,0 @@ -Anonymous Functions -=================== - -{{#include ../links.md}} - -Sometimes it gets tedious to define separate functions only to dispatch them via single [function pointers]. -This scenario is especially common when simulating object-oriented programming ([OOP]). - -```rust -// Define object -let obj = #{ - data: 42, - increment: Fn("inc_obj"), // use function pointers to - decrement: Fn("dec_obj"), // refer to method functions - print: Fn("print_obj") -}; - -// Define method functions one-by-one -fn inc_obj(x) { this.data += x; } -fn dec_obj(x) { this.data -= x; } -fn print_obj() { print(this.data); } -``` - -The above can be replaced by using _anonymous functions_ which have the same syntax as Rust's closures -(but they are **NOT** real closures, merely syntactic sugar): - -```rust -let obj = #{ - data: 42, - increment: |x| this.data += x, // one-liner - decrement: |x| this.data -= x, - print_obj: || { print(this.data); } // full function body -}; -``` - -The anonymous functions will be hoisted into separate functions in the global namespace. -The above is equivalent to: - -```rust -let obj = #{ - data: 42, - increment: Fn("anon_fn_1000"), - decrement: Fn("anon_fn_1001"), - print: Fn("anon_fn_1002") -}; - -fn anon_fn_1000(x) { this.data += x; } -fn anon_fn_1001(x) { this.data -= x; } -fn anon_fn_1002() { print this.data; } -``` - - -WARNING – NOT Real Closures --------------------------------- - -Remember: anonymous functions, though having the same syntax as Rust _closures_, are themselves -**not** real closures. - -In particular, they capture their execution environment via [automatic currying] -(disabled via [`no_closure`]). diff --git a/doc/src/language/fn-capture.md b/doc/src/language/fn-capture.md deleted file mode 100644 index 599b211d..00000000 --- a/doc/src/language/fn-capture.md +++ /dev/null @@ -1,71 +0,0 @@ -Capture The Calling Scope for Function Call -========================================== - -{{#include ../links.md}} - - -Peeking Out of The Pure Box ---------------------------- - -Rhai functions are _pure_, meaning that they depend on on their arguments and have no -access to the calling environment. - -When a function accesses a variable that is not defined within that function's scope, -it raises an evaluation error. - -It is possible, through a special syntax, to capture the calling scope – i.e. the scope -that makes the function call – and access variables defined there. - -```rust -fn foo(y) { // function accesses 'x' and 'y', but 'x' is not defined - x += y; // 'x' is modified in this function - x -} - -let x = 1; - -foo(41); // error: variable 'x' not found - -// Calling a function with a '!' causes it to capture the calling scope - -foo!(41) == 42; // the function can access the value of 'x', but cannot change it - -x == 1; // 'x' is still the original value - -x.method!(); // <- syntax error: capturing is not allowed in method-call style - -// Capturing also works for function pointers - -let f = Fn("foo"); - -call!(f, 41) == 42; // must use function-call style - -f.call!(41); // <- syntax error: capturing is not allowed in method-call style - -// Capturing is not available for module functions - -import "hello" as h; - -h::greet!(); // <- syntax error: capturing is not allowed in namespace-qualified calls -``` - - -No Mutations ------------- - -Variables in the calling scope are captured as cloned copies. -Changes to them do **not** reflect back to the calling scope. - -Rhai functions remain _pure_ in the sense that they can never mutate their environment. - - -Caveat Emptor -------------- - -Functions relying on the calling scope is often a _Very Bad Idea™_ because it makes code -almost impossible to reason and maintain, as their behaviors are volatile and unpredictable. - -They behave more like macros that are expanded inline than actual function calls, thus the -syntax is also similar to Rust's macro invocations. - -This usage should be at the last resort. YOU HAVE BEEN WARNED. diff --git a/doc/src/language/fn-closure.md b/doc/src/language/fn-closure.md deleted file mode 100644 index 985a67f3..00000000 --- a/doc/src/language/fn-closure.md +++ /dev/null @@ -1,192 +0,0 @@ -Simulating Closures -=================== - -{{#include ../links.md}} - -Capture External Variables via Automatic Currying ------------------------------------------------- - -Since [anonymous functions] de-sugar to standard function definitions, they retain all the behaviors of -Rhai functions, including being _pure_, having no access to external variables. - -The anonymous function syntax, however, automatically _captures_ variables that are not defined within -the current scope, but are defined in the external scope – i.e. the scope where the anonymous function -is created. - -Variables that are accessible during the time the [anonymous function] is created can be captured, -as long as they are not shadowed by local variables defined within the function's scope. - -The captured variables are automatically converted into **reference-counted shared values** -(`Rc>` in normal builds, `Arc>` in [`sync`] builds). - -Therefore, similar to closures in many languages, these captured shared values persist through -reference counting, and may be read or modified even after the variables that hold them -go out of scope and no longer exist. - -Use the `Dynamic::is_shared` function to check whether a particular value is a shared value. - -Automatic currying can be turned off via the [`no_closure`] feature. - - -Examples --------- - -```rust -let x = 1; // a normal variable - -x.is_shared() == false; - -let f = |y| x + y; // variable 'x' is auto-curried (captured) into 'f' - -x.is_shared() == true; // 'x' is now a shared value! - -f.call(2) == 3; // 1 + 2 == 3 - -x = 40; // changing 'x'... - -f.call(2) == 42; // the value of 'x' is 40 because 'x' is shared - -// The above de-sugars into this: -fn anon$1001(x, y) { x + y } // parameter 'x' is inserted - -$make_shared(x); // convert variable 'x' into a shared value - -let f = Fn("anon$1001").curry(x); // shared 'x' is curried - -f.call(2) == 42; -``` - - -Beware: Captured Variables are Truly Shared ------------------------------------------- - -The example below is a typical tutorial sample for many languages to illustrate the traps -that may accompany capturing external scope variables in closures. - -It prints `9`, `9`, `9`, ... `9`, `9`, not `0`, `1`, `2`, ... `8`, `9`, because there is -ever only _one_ captured variable, and all ten closures capture the _same_ variable. - -```rust -let funcs = []; - -for i in range(0, 10) { - funcs.push(|| print(i)); // the for loop variable 'i' is captured -} - -funcs.len() == 10; // 10 closures stored in the array - -funcs[0].type_of() == "Fn"; // make sure these are closures - -for f in funcs { - f.call(); // all references to 'i' are the same variable! -} -``` - - -Therefore – Be Careful to Prevent Data Races -------------------------------------------------- - -Rust does not have data races, but that doesn't mean Rhai doesn't. - -Avoid performing a method call on a captured shared variable (which essentially takes a -mutable reference to the shared object) while using that same variable as a parameter -in the method call – this is a sure-fire way to generate a data race error. - -If a shared value is used as the `this` pointer in a method call to a closure function, -then the same shared value _must not_ be captured inside that function, or a data race -will occur and the script will terminate with an error. - -```rust -let x = 20; - -x.is_shared() == false; // 'x' is not shared, so no data race is possible - -let f = |a| this += x + a; // 'x' is captured in this closure - -x.is_shared() == true; // now 'x' is shared - -x.call(f, 2); // <- error: data race detected on 'x' -``` - - -Data Races in `sync` Builds Can Become Deadlocks ------------------------------------------------ - -Under the [`sync`] feature, shared values are guarded with a `RwLock`, meaning that data race -conditions no longer raise an error. - -Instead, they wait endlessly for the `RwLock` to be freed, and thus can become deadlocks. - -On the other hand, since the same thread (i.e. the [`Engine`] thread) that is holding the lock -is attempting to read it again, this may also [panic](https://doc.rust-lang.org/std/sync/struct.RwLock.html#panics-1) -depending on the O/S. - -```rust -let x = 20; - -let f = |a| this += x + a; // 'x' is captured in this closure - -// Under `sync`, the following may wait forever, or may panic, -// because 'x' is locked as the `this` pointer but also accessed -// via a captured shared value. -x.call(f, 2); -``` - - -TL;DR ------ - -### Q: How is it actually implemented? - -The actual implementation of closures de-sugars to: - -1. Keeping track of what variables are accessed inside the anonymous function, - -2. If a variable is not defined within the anonymous function's scope, it is looked up _outside_ the function and - in the current execution scope – where the anonymous function is created. - -3. The variable is added to the parameters list of the anonymous function, at the front. - -4. The variable is then converted into a **reference-counted shared value**. - - An [anonymous function] which captures an external variable is the only way to create a reference-counted shared value in Rhai. - -5. The shared value is then [curried][currying] into the [function pointer] itself, essentially carrying a reference to that shared value - and inserting it into future calls of the function. - - This process is called _Automatic Currying_, and is the mechanism through which Rhai simulates normal closures. - -### Q: Why are closures implemented as automatic currying? - -In concept, a closure _closes_ over captured variables from the outer scope – that's why -they are called _closures_. When this happen, a typical language implementation hoists -those variables that are captured away from the stack frame and into heap-allocated storage. -This is because those variables may be needed after the stack frame goes away. - -These heap-allocated captured variables only go away when all the closures that need them -are finished with them. A garbage collector makes this trivial to implement – they are -automatically collected as soon as all closures needing them are destroyed. - -In Rust, this can be done by reference counting instead, with the potential pitfall of creating -reference loops that will prevent those variables from being deallocated forever. -Rhai avoids this by clone-copying most data values, so reference loops are hard to create. - -Rhai does the hoisting of captured variables into the heap by converting those values -into reference-counted locked values, also allocated on the heap. The process is identical. - -Closures are usually implemented as a data structure containing two items: - -1) A function pointer to the function body of the closure, -2) A data structure containing references to the captured shared variables on the heap. - -Usually a language implementation passes the structure containing references to captured -shared variables into the function pointer, the function body taking this data structure -as an additional parameter. - -This is essentially what Rhai does, except that Rhai passes each variable individually -as separate parameters to the function, instead of creating a structure and passing that -structure as a single parameter. This is the only difference. - -Therefore, in most languages, essentially all closures are implemented as automatic currying of -shared variables hoisted into the heap, automatically passing those variables as parameters into -the function. Rhai just brings this directly up to the front. diff --git a/doc/src/language/fn-curry.md b/doc/src/language/fn-curry.md deleted file mode 100644 index c223d8cd..00000000 --- a/doc/src/language/fn-curry.md +++ /dev/null @@ -1,39 +0,0 @@ -Function Pointer Currying -======================== - -{{#include ../links.md}} - -It is possible to _curry_ a [function pointer] by providing partial (or all) arguments. - -Currying is done via the `curry` keyword and produces a new [function pointer] which carries -the curried arguments. - -When the curried [function pointer] is called, the curried arguments are inserted starting from the left. -The actual call arguments should be reduced by the number of curried arguments. - -```rust -fn mul(x, y) { // function with two parameters - x * y -} - -let func = Fn("mul"); - -func.call(21, 2) == 42; // two arguments are required for 'mul' - -let curried = func.curry(21); // currying produces a new function pointer which - // carries 21 as the first argument - -let curried = curry(func, 21); // function-call style also works - -curried.call(2) == 42; // <- de-sugars to 'func.call(21, 2)' - // only one argument is now required -``` - - -Automatic Currying ------------------- - -[Anonymous functions] defined via a closure syntax _capture_ external variables -that are not shadowed inside the function's scope. - -This is accomplished via [automatic currying]. diff --git a/doc/src/language/fn-namespaces.md b/doc/src/language/fn-namespaces.md deleted file mode 100644 index 47489acf..00000000 --- a/doc/src/language/fn-namespaces.md +++ /dev/null @@ -1,119 +0,0 @@ -Function Namespaces -================== - -{{#include ../links.md}} - -Each Function is a Separate Compilation Unit -------------------------------------------- - -[Functions] in Rhai are _pure_ and they form individual _compilation units_. -This means that individual functions can be separated, exported, re-grouped, imported, -and generally mix-'n-match-ed with other completely unrelated scripts. - -For example, the `AST::merge` and `AST::combine` methods (or the equivalent `+` and `+=` operators) -allow combining all functions in one [`AST`] into another, forming a new, unified, group of functions. - -In general, there are two types of _namespaces_ where functions are looked up: - -| Namespace | How Many | Source | Lookup | Sub-modules? | Variables? | -| --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | :----------: | :--------: | -| Global | One | 1) [`AST`] being evaluated
2) `Engine::register_XXX` API
3) global [modules] registered via `Engine::register_global_module`
4) functions in static [modules] registered via `Engine::register_static_module` and marked _global_ | simple name | ignored | ignored | -| Module | Many | 1) [Module] registered via `Engine::register_static_module`
2) [Module] loaded via [`import`] statement | namespace-qualified name | yes | yes | - - -Module Namespaces ------------------ - -There can be multiple module namespaces at any time during a script evaluation, usually loaded via the -[`import`] statement. - -_Static_ module namespaces can also be registered into an [`Engine`] via `Engine::register_static_module`. - -Functions and variables in module namespaces are isolated and encapsulated within their own environments. - -They must be called or accessed in a _namespace-qualified_ manner. - -```rust -import "my_module" as m; // new module namespace 'm' created via 'import' - -let x = m::calc_result(); // namespace-qualified function call - -let y = m::MY_NUMBER; // namespace-qualified variable (constant) access - -let x = calc_result(); // <- error: function 'calc_result' not found - // in global namespace! -``` - - -Global Namespace ----------------- - -There is one _global_ namespace for every [`Engine`], which includes (in the following search order): - -* All functions defined in the [`AST`] currently being evaluated. - -* All native Rust functions and iterators registered via the `Engine::register_XXX` API. - -* All functions and iterators defined in global [modules] that are registered into the [`Engine`] via - `Engine::register_global_module`. - -* Functions defined in [modules] registered via `Engine::register_static_module` that are specifically - marked for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]). - -Anywhere in a Rhai script, when a function call is made, the function is searched within the -global namespace, in the above search order. - -Therefore, function calls in Rhai are _late_ bound – meaning that the function called cannot be -determined or guaranteed and there is no way to _lock down_ the function being called. -This aspect is very similar to JavaScript before ES6 modules. - -```rust -// Compile a script into AST -let ast1 = engine.compile( - r#" - fn get_message() { - "Hello!" // greeting message - } - - fn say_hello() { - print(get_message()); // prints message - } - - say_hello(); - "# -)?; - -// Compile another script with an overriding function -let ast2 = engine.compile(r#"fn get_message() { "Boo!" }"#)?; - -// Combine the two AST's -ast1 += ast2; // 'message' will be overwritten - -engine.consume_ast(&ast1)?; // prints 'Boo!' -``` - -Therefore, care must be taken when _cross-calling_ functions to make sure that the correct -functions are called. - -The only practical way to ensure that a function is a correct one is to use [modules] - -i.e. define the function in a separate module and then [`import`] it: - -```rust ----------------- -| message.rhai | ----------------- - -fn get_message() { "Hello!" } - - ---------------- -| script.rhai | ---------------- - -import "message" as msg; - -fn say_hello() { - print(msg::get_message()); -} -say_hello(); -``` diff --git a/doc/src/language/fn-ptr.md b/doc/src/language/fn-ptr.md deleted file mode 100644 index 4717504a..00000000 --- a/doc/src/language/fn-ptr.md +++ /dev/null @@ -1,271 +0,0 @@ -Function Pointers -================= - -{{#include ../links.md}} - -It is possible to store a _function pointer_ in a variable just like a normal value. -In fact, internally a function pointer simply stores the _name_ of the function as a string. - -A function pointer is created via the `Fn` function, which takes a [string] parameter. - -Call a function pointer using the `call` method. - - -Built-in methods ----------------- - -The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if -using a [raw `Engine`]) operate on function pointers: - -| Function | Parameter(s) | Description | -| ---------------------------------- | ------------ | ------------------------------------------------------------------------------------------------ | -| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer | -| `is_anonymous` method and property | _none_ | does the function pointer refer to an [anonymous function]? Not available under [`no_function`]. | -| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ | - - -Examples --------- - -```rust -fn foo(x) { 41 + x } - -let func = Fn("foo"); // use the 'Fn' function to create a function pointer - -print(func); // prints 'Fn(foo)' - -let func = fn_name.Fn(); // <- error: 'Fn' cannot be called in method-call style - -func.type_of() == "Fn"; // type_of() as function pointer is 'Fn' - -func.name == "foo"; - -func.call(1) == 42; // call a function pointer with the 'call' method - -foo(1) == 42; // <- the above de-sugars to this - -call(func, 1); // normal function call style also works for 'call' - -let len = Fn("len"); // 'Fn' also works with registered native Rust functions - -len.call("hello") == 5; - -let add = Fn("+"); // 'Fn' works with built-in operators also - -add.call(40, 2) == 42; - -let fn_name = "hello"; // the function name does not have to exist yet - -let hello = Fn(fn_name + "_world"); - -hello.call(0); // error: function not found - 'hello_world (i64)' -``` - - -Global Namespace Only --------------------- - -Because of their dynamic nature, function pointers cannot refer to functions in [`import`]-ed [modules]. -They can only refer to functions within the global [namespace][function namespace]. -See _[Function Namespaces]_ for more details. - -```rust -import "foo" as f; // assume there is 'f::do_work()' - -f::do_work(); // works! - -let p = Fn("f::do_work"); // error: invalid function name - -fn do_work_now() { // call it from a local function - f::do_work(); -} - -let p = Fn("do_work_now"); - -p.call(); // works! -``` - - -Dynamic Dispatch ----------------- - -The purpose of function pointers is to enable rudimentary _dynamic dispatch_, meaning to determine, -at runtime, which function to call among a group. - -Although it is possible to simulate dynamic dispatch via a number and a large `if-then-else-if` statement, -using function pointers significantly simplifies the code. - -```rust -let x = some_calculation(); - -// These are the functions to call depending on the value of 'x' -fn method1(x) { ... } -fn method2(x) { ... } -fn method3(x) { ... } - -// Traditional - using decision variable -let func = sign(x); - -// Dispatch with if-statement -if func == -1 { - method1(42); -} else if func == 0 { - method2(42); -} else if func == 1 { - method3(42); -} - -// Using pure function pointer -let func = if x < 0 { - Fn("method1") -} else if x == 0 { - Fn("method2") -} else if x > 0 { - Fn("method3") -} - -// Dynamic dispatch -func.call(42); - -// Using functions map -let map = [ Fn("method1"), Fn("method2"), Fn("method3") ]; - -let func = sign(x) + 1; - -// Dynamic dispatch -map[func].call(42); -``` - - -Bind the `this` Pointer ----------------------- - -When `call` is called as a _method_ but not on a function pointer, it is possible to dynamically dispatch -to a function call while binding the object in the method call to the `this` pointer of the function. - -To achieve this, pass the function pointer as the _first_ argument to `call`: - -```rust -fn add(x) { // define function which uses 'this' - this += x; -} - -let func = Fn("add"); // function pointer to 'add' - -func.call(1); // error: 'this' pointer is not bound - -let x = 41; - -func.call(x, 1); // error: function 'add (i64, i64)' not found - -call(func, x, 1); // error: function 'add (i64, i64)' not found - -x.call(func, 1); // 'this' is bound to 'x', dispatched to 'func' - -x == 42; -``` - -Beware that this only works for _method-call_ style. Normal function-call style cannot bind -the `this` pointer (for syntactic reasons). - -Therefore, obviously, binding the `this` pointer is unsupported under [`no_object`]. - - -Call a Function Pointer in Rust ------------------------------- - -It is completely normal to register a Rust function with an [`Engine`] that takes parameters -whose types are function pointers. The Rust type in question is `rhai::FnPtr`. - -A function pointer in Rhai is essentially syntactic sugar wrapping the _name_ of a function -to call in script. Therefore, the script's [`AST`] is required to call a function pointer, -as well as the entire _execution context_ that the script is running in. - -For a rust function taking a function pointer as parameter, the [Low-Level API](../rust/register-raw.md) -must be used to register the function. - -Essentially, use the low-level `Engine::register_raw_fn` method to register the function. -`FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the -current _native call context_, the `this` pointer, and other necessary arguments. - -```rust -use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext}; - -let mut engine = Engine::new(); - -// Define Rust function in required low-level API signature -fn call_fn_ptr_with_value(context: NativeCallContext, args: &mut [&mut Dynamic]) - -> Result> -{ - // 'args' is guaranteed to contain enough arguments of the correct types - let fp = std::mem::take(args[1]).cast::(); // 2nd argument - function pointer - let value = args[2].clone(); // 3rd argument - function argument - let this_ptr = args.get_mut(0).unwrap(); // 1st argument - this pointer - - // Use 'FnPtr::call_dynamic' to call the function pointer. - // Beware, private script-defined functions will not be found. - fp.call_dynamic(context, Some(this_ptr), [value]) -} - -// Register a Rust function using the low-level API -engine.register_raw_fn("super_call", - &[ // parameter types - std::any::TypeId::of::(), - std::any::TypeId::of::(), - std::any::TypeId::of::() - ], - call_fn_ptr_with_value -); -``` - - -`NativeCallContext` ------------------- - -`FnPtr::call_dynamic` takes a parameter of type `NativeCallContext` which holds the _native call context_ -of the particular call to a registered Rust function. It is a type that exposes the following: - -| Field | Type | Description | -| ------------------- | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. | -| `source()` | `Option<&str>` | reference to the current source, if any | -| `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | - - -This type is normally provided by the [`Engine`] (e.g. when using [`Engine::register_fn_raw`](../rust/register-raw.md)). -However, it may also be manually constructed from a tuple: - -```rust -use rhai::{Engine, FnPtr, NativeCallContext}; - -let engine = Engine::new(); - -// Compile script to AST -let mut ast = engine.compile( - r#" - let test = "hello"; - |x| test + x // this creates an closure - "#, -)?; - -// Save the closure together with captured variables -let fn_ptr = engine.eval_ast::(&ast)?; - -// Get rid of the script, retaining only functions -ast.retain_functions(|_, _, _| true); - -// Create function namespace from the 'AST' -let lib = [ast.as_ref()]; - -// Create native call context -let context = NativeCallContext::new(&engine, &lib); - -// 'f' captures: the engine, the AST, and the closure -let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]); - -// 'f' can be called like a normal function -let result = f(42)?; -``` diff --git a/doc/src/language/for.md b/doc/src/language/for.md deleted file mode 100644 index 6af5a422..00000000 --- a/doc/src/language/for.md +++ /dev/null @@ -1,103 +0,0 @@ -`for` Loop -========== - -{{#include ../links.md}} - -Iterating through a range or an [array], or any type with a registered [type iterator], -is provided by the `for` ... `in` loop. - -Like C, `continue` can be used to skip to the next iteration, by-passing all following statements; -`break` can be used to break out of the loop unconditionally. - -To loop through a number sequence (with or without steps), use the `range` function to -return a numeric iterator. - - -Iterate Through Strings ------------------------ - -Iterating through a [string] yields characters. - -```rust -let s = "hello, world!"; - -for ch in s { - if ch > 'z' { continue; } // skip to the next iteration - - print(ch); - - if x == '@' { break; } // break out of for loop -} -``` - - -Iterate Through Arrays ----------------------- - -Iterating through an [array] yields cloned _copies_ of each element. - -```rust -let array = [1, 3, 5, 7, 9, 42]; - -for x in array { - if x > 10 { continue; } // skip to the next iteration - - print(x); - - if x == 42 { break; } // break out of for loop -} -``` - - -Iterate Through Numeric Ranges ------------------------------ - -The `range` function allows iterating through a range of numbers -(not including the last number). - -```rust -// Iterate starting from 0 and stopping at 49. -for x in range(0, 50) { - if x > 10 { continue; } // skip to the next iteration - - print(x); - - if x == 42 { break; } // break out of for loop -} - -// The 'range' function also takes a step. -for x in range(0, 50, 3) { // step by 3 - if x > 10 { continue; } // skip to the next iteration - - print(x); - - if x == 42 { break; } // break out of for loop -} -``` - - -Iterate Through Object Maps --------------------------- - -Two methods, `keys` and `values`, return [arrays] containing cloned _copies_ -of all property names and values of an [object map], respectively. - -These [arrays] can be iterated. - -```rust -let map = #{a:1, b:3, c:5, d:7, e:9}; - -// Property names are returned in unsorted, random order -for x in map.keys() { - if x > 10 { continue; } // skip to the next iteration - - print(x); - - if x == 42 { break; } // break out of for loop -} - -// Property values are returned in unsorted, random order -for val in map.values() { - print(val); -} -``` diff --git a/doc/src/language/functions.md b/doc/src/language/functions.md deleted file mode 100644 index d7f9917d..00000000 --- a/doc/src/language/functions.md +++ /dev/null @@ -1,190 +0,0 @@ -Functions -========= - -{{#include ../links.md}} - -Rhai supports defining functions in script (unless disabled with [`no_function`]): - -```rust -fn add(x, y) { - return x + y; -} - -fn sub(x, y,) { // trailing comma in parameters list is OK - return x - y; -} - -add(2, 3) == 5; - -sub(2, 3,) == -1; // trailing comma in arguments list is OK -``` - - -Implicit Return ---------------- - -Just like in Rust, an implicit return can be used. In fact, the last statement of a block is _always_ the block's return value -regardless of whether it is terminated with a semicolon `';'`. This is different from Rust. - -```rust -fn add(x, y) { // implicit return: - x + y; // value of the last statement (no need for ending semicolon) - // is used as the return value -} - -fn add2(x) { - return x + 2; // explicit return -} - -add(2, 3) == 5; - -add2(42) == 44; -``` - - -Global Definitions Only ----------------------- - -Functions can only be defined at the global level, never inside a block or another function. - -```rust -// Global level is OK -fn add(x, y) { - x + y -} - -// The following will not compile -fn do_addition(x) { - fn add_y(n) { // <- syntax error: functions cannot be defined inside another function - n + y - } - - add_y(x) -} -``` - - -No Access to External Scope --------------------------- - -Functions are not _closures_. They do not capture the calling environment -and can only access their own parameters. -They cannot access variables external to the function itself. - -```rust -let x = 42; - -fn foo() { x } // <- syntax error: variable 'x' doesn't exist -``` - - -But Can Call Other Functions ---------------------------- - -All functions in the same [`AST`] can call each other. - -```rust -fn foo(x) { x + 1 } // function defined in the global namespace - -fn bar(x) { foo(x) } // OK! function 'foo' can be called -``` - - -Use Before Definition Allowed ----------------------------- - -Unlike C/C++, functions in Rhai can be defined _anywhere_ at global level. - -A function does not need to be defined prior to being used in a script; -a statement in the script can freely call a function defined afterwards. - -This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword. - - -Arguments are Passed by Value ----------------------------- - -Functions defined in script always take [`Dynamic`] parameters (i.e. they can be of any types). -Therefore, functions with the same name and same _number_ of parameters are equivalent. - -All arguments are passed by _value_, so all Rhai script-defined functions are _pure_ -(i.e. they never modify their arguments). - -Any update to an argument will **not** be reflected back to the caller. - -```rust -fn change(s) { // 's' is passed by value - s = 42; // only a COPY of 's' is changed -} - -let x = 500; - -change(x); - -x == 500; // 'x' is NOT changed! -``` - - -`this` – Simulating an Object Method ------------------------------------------ - -Script-defined functions can also be called in method-call style. -When this happens, the keyword '`this`' binds to the object in the method call and can be changed. - -```rust -fn change() { // not that the object does not need a parameter - this = 42; // 'this' binds to the object in method-call -} - -let x = 500; - -x.change(); // call 'change' in method-call style, 'this' binds to 'x' - -x == 42; // 'x' is changed! - -change(); // <- error: `this` is unbound -``` - - -`is_def_fn` ------------ - -Use `is_def_fn` to detect if a Rhai function is defined (and therefore callable), -based on its name and the number of parameters. - -```rust -fn foo(x) { x + 1 } - -is_def_fn("foo", 1) == true; - -is_def_fn("foo", 0) == false; - -is_def_fn("foo", 2) == false; - -is_def_fn("bar", 1) == false; -``` - - -Metadata --------- - -The function `get_fn_metadata_list` is a _reflection_ API that returns an array of the metadata -of all script-defined functions in scope. - -Functions from the following sources are returned, in order: - -1) Encapsulated script environment (e.g. when loading a [module] from a script file), -2) Current script, -3) [Modules] imported via the [`import`] statement (latest imports first), -4) [Modules] added via [`Engine::register_static_module`]({{rootUrl}}/rust/modules/create.md) (latest registrations first) - -The return value is an [array] of [object maps] (so `get_fn_metadata_list` is not available under -[`no_index`] or [`no_object`]), containing the following fields: - -| Field | Type | Optional? | Description | -| -------------- | :------------------: | :-------: | ---------------------------------------------------------------------- | -| `namespace` | [string] | yes | the module _namespace_ if the function is defined within a module | -| `access` | [string] | no | `"public"` if the function is public,
`"private"` if it is private | -| `name` | [string] | no | function name | -| `params` | [array] of [strings] | no | parameter names | -| `is_anonymous` | `bool` | no | is this function an anonymous function? | diff --git a/doc/src/language/if.md b/doc/src/language/if.md deleted file mode 100644 index b9c63dab..00000000 --- a/doc/src/language/if.md +++ /dev/null @@ -1,51 +0,0 @@ -`if` Statement -============== - -{{#include ../links.md}} - -`if` statements follow C syntax: - -```rust -if foo(x) { - print("It's true!"); -} else if bar == baz { - print("It's true again!"); -} else if baz.is_foo() { - print("Yet again true."); -} else if foo(bar - baz) { - print("True again... this is getting boring."); -} else { - print("It's finally false!"); -} -``` - -Braces Are Mandatory --------------------- - -Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but -all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`', -even when there is only one statement inside the branch. - -Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to. - -```rust -// Rhai is not C! -if (decision) print("I've decided!"); -// ^ syntax error, expecting '{' in statement block -``` - - -`if`-Expressions ---------------- - -Like Rust, `if` statements can also be used as _expressions_, replacing the `? :` conditional operators -in other C-like languages. - -```rust -// The following is equivalent to C: int x = 1 + (decision ? 42 : 123) / 2; -let x = 1 + if decision { 42 } else { 123 } / 2; -x == 22; - -let x = if decision { 42 }; // no else branch defaults to '()' -x == (); -``` diff --git a/doc/src/language/index.md b/doc/src/language/index.md deleted file mode 100644 index ac4e4fb6..00000000 --- a/doc/src/language/index.md +++ /dev/null @@ -1,7 +0,0 @@ -Rhai Language Reference -====================== - -{{#include ../links.md}} - -This section outlines the Rhai language. - diff --git a/doc/src/language/iterator.md b/doc/src/language/iterator.md deleted file mode 100644 index e885efba..00000000 --- a/doc/src/language/iterator.md +++ /dev/null @@ -1,45 +0,0 @@ -Iterators for Custom Types -========================== - -{{#include ../links.md}} - -If a [custom type] is iterable, the [`for`](for.md) loop can be used to iterate through -its items in sequence. - -In order to use a [`for`](for.md) statement, a _type iterator_ must be registered for -the [custom type] in question. - -`Engine::register_iterator` allows registration of a _type iterator_ for any type -that implements `IntoIterator`: - -```rust -// Custom type -#[derive(Debug, Clone)] -struct TestStruct { ... } - -// Implement 'IntoIterator' trait -impl IntoIterator for TestStruct { - type Item = ...; - type IntoIter = SomeIterType; - - fn into_iter(self) -> Self::IntoIter { - ... - } -} - -engine - .register_type_with_name::("TestStruct") - .register_fn("new_ts", || TestStruct { ... }) - .register_iterator::(); // register type iterator -``` - -With a type iterator registered, the [custom type] can be iterated through: - -```rust -let ts = new_ts(); - -// Use 'for' statement to loop through items in 'ts' -for item in ts { - ... -} -``` diff --git a/doc/src/language/json.md b/doc/src/language/json.md deleted file mode 100644 index 26e9f81f..00000000 --- a/doc/src/language/json.md +++ /dev/null @@ -1,95 +0,0 @@ -Parse an Object Map from JSON -============================ - -{{#include ../links.md}} - -The syntax for an [object map] is extremely similar to the JSON representation of a object hash, -with the exception of `null` values which can technically be mapped to [`()`]. - -A valid JSON string does not start with a hash character `#` while a Rhai [object map] does – that's the major difference! - -Use the `Engine::parse_json` method to parse a piece of JSON into an object map. -The JSON text must represent a single object hash (i.e. must be wrapped within "`{ .. }`") -otherwise it returns a syntax error. - -```rust -// JSON string - notice that JSON property names are always quoted -// notice also that comments are acceptable within the JSON string -let json = r#"{ - "a": 1, // <- this is an integer number - "b": true, - "c": 123.0, // <- this is a floating-point number - "$d e f!": "hello", // <- any text can be a property name - "^^^!!!": [1,42,"999"], // <- value can be array or another hash - "z": null // <- JSON 'null' value - } -"#; - -// Parse the JSON expression as an object map -// Set the second boolean parameter to true in order to map 'null' to '()' -let map = engine.parse_json(json, true)?; - -map.len() == 6; // 'map' contains all properties in the JSON string - -// Put the object map into a 'Scope' -let mut scope = Scope::new(); -scope.push("map", map); - -let result = engine.eval_with_scope::(r#"map["^^^!!!"].len()"#)?; - -result == 3; // the object map is successfully used in the script -``` - -Representation of Numbers ------------------------- - -JSON numbers are all floating-point while Rhai supports integers (`INT`) and floating-point (`FLOAT`) if -the [`no_float`] feature is not used. - -Most common generators of JSON data distinguish between integer and floating-point values by always -serializing a floating-point number with a decimal point (i.e. `123.0` instead of `123` which is -assumed to be an integer). - -This style can be used successfully with Rhai [object maps]. - - -Parse JSON with Sub-Objects --------------------------- - -`Engine::parse_json` depends on the fact that the [object map] literal syntax in Rhai is _almost_ -the same as a JSON object. However, it is _almost_ because the syntax for a sub-object in JSON -(i.e. "`{ ... }`") is different from a Rhai [object map] literal (i.e. "`#{ ... }`"). - -When `Engine::parse_json` encounters JSON with sub-objects, it fails with a syntax error. - -If it is certain that no text string in the JSON will ever contain the character '`{`', -then it is possible to parse it by first replacing all occupance of '`{`' with "`#{`". - -A JSON object hash starting with `#{` is handled transparently by `Engine::parse_json`. - -```rust -// JSON with sub-object 'b'. -let json = r#"{"a":1, "b":{"x":true, "y":false}}"#; - -// Our JSON text does not contain the '{' character, so off we go! -let new_json = json.replace("{", "#{"); - -// The leading '{' will also be replaced to '#{', but 'parse_json' handles this just fine. -let map = engine.parse_json(&new_json, false)?; - -map.len() == 2; // 'map' contains two properties: 'a' and 'b' -``` - - -Use `serde` to Serialize/Deserialize to/from JSON ------------------------------------------------- - -Remember, `Engine::parse_json` is nothing more than a _cheap_ alternative to true JSON parsing. - -If correctness is needed, or for more configuration possibilities, turn on the [`serde`][features] -feature to pull in the [`serde`](https://crates.io/crates/serde) crate which enables -serialization and deserialization to/from multiple formats, including JSON. - -Beware, though... the [`serde`](https://crates.io/crates/serde) crate is quite heavy. - -See _[Serialization/Deserialization of `Dynamic` with `serde`][`serde`]_ for more details. diff --git a/doc/src/language/keywords.md b/doc/src/language/keywords.md deleted file mode 100644 index 53f3ca65..00000000 --- a/doc/src/language/keywords.md +++ /dev/null @@ -1,26 +0,0 @@ -Keywords -======== - -{{#include ../links.md}} - -The following are reserved keywords in Rhai: - -| Active keywords | Reserved keywords | Usage | Inactive under feature | -| ---------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------- | :--------------------: | -| `true`, `false` | | constants | | -| `let`, `const` | `var`, `static` | variables | | -| | `begin`, `end` | block scopes | | -| `is_shared` | | shared values | [`no_closure`] | -| `if`, `else` | `then`, `unless`, `goto`, `exit` | control flow | | -| `switch` | `match`, `case` | switching and matching | | -| `do`, `while`, `loop`, `until`, `for`, `in`, `continue`, `break` | `each` | looping | | -| `fn`, `private` | `public`, `new` | functions | [`no_function`] | -| `return` | | return values | | -| `throw`, `try`, `catch` | | throw/catch exceptions | | -| `import`, `export`, `as` | `use`, `with`, `module`, `package` | modules/packages | [`no_module`] | -| `Fn`, `call`, `curry` | | function pointers | | -| | `spawn`, `thread`, `go`, `sync`, `async`, `await`, `yield` | threading/async | | -| `type_of`, `print`, `debug`, `eval` | | special functions | | -| | `default`, `void`, `null`, `nil` | special values | | - -Keywords cannot become the name of a [function] or [variable], even when they are disabled. diff --git a/doc/src/language/logic.md b/doc/src/language/logic.md deleted file mode 100644 index 9f6ebbcf..00000000 --- a/doc/src/language/logic.md +++ /dev/null @@ -1,78 +0,0 @@ -Logic Operators -============== - -{{#include ../links.md}} - -Comparison Operators -------------------- - -| Operator | Description | -| :------: | ------------------------- | -| `==` | equals to | -| `!=` | not equals to | -| `>` | greater than | -| `>=` | greater than or equals to | -| `<` | less than | -| `<=` | less than or equals to | - -Comparing most values of the same data type work out-of-the-box for all [standard types] supported by the system. - -However, if using a [raw `Engine`] without loading any [packages], comparisons can only be made between a limited -set of types (see [built-in operators]). - -```rust -42 == 42; // true - -42 > 42; // false - -"hello" > "foo"; // true - -"42" == 42; // false -``` - -Comparing two values of _different_ data types, or of unknown data types, always results in `false`, -except for '`!=`' (not equals) which results in `true`. This is in line with intuition. - -```rust -42 == 42.0; // false - i64 cannot be compared with f64 - -42 != 42.0; // true - i64 cannot be compared with f64 - -42 > "42"; // false - i64 cannot be compared with string - -42 <= "42"; // false - i64 cannot be compared with string - -let ts = new_ts(); // custom type - -ts == 42; // false - types cannot be compared - -ts != 42; // true - types cannot be compared -``` - -Boolean operators ------------------ - -| Operator | Description | Short-Circuits? | -| :---------------: | ------------- | :-------------: | -| `!` (prefix) | boolean _NOT_ | no | -| `&&` | boolean _AND_ | yes | -| `&` | boolean _AND_ | no | -| \|\| | boolean _OR_ | yes | -| \| | boolean _OR_ | no | - -Double boolean operators `&&` and `||` _short-circuit_ – meaning that the second operand will not be evaluated -if the first one already proves the condition wrong. - -Single boolean operators `&` and `|` always evaluate both operands. - -```rust -a() || b(); // b() is not evaluated if a() is true - -a() && b(); // b() is not evaluated if a() is false - -a() | b(); // both a() and b() are evaluated - -a() & b(); // both a() and b() are evaluated -``` - -All boolean operators are [built in][built-in operators] for the `bool` data type. diff --git a/doc/src/language/loop.md b/doc/src/language/loop.md deleted file mode 100644 index 3fd9b5fb..00000000 --- a/doc/src/language/loop.md +++ /dev/null @@ -1,26 +0,0 @@ -Infinite `loop` -=============== - -{{#include ../links.md}} - -Infinite loops follow Rust syntax. - -Like Rust, `continue` can be used to skip to the next iteration, by-passing all following statements; -`break` can be used to break out of the loop unconditionally. - -```rust -let x = 10; - -loop { - x -= 1; - - if x > 5 { continue; } // skip to the next iteration - - print(x); - - if x == 0 { break; } // break out of loop -} -``` - -Beware: a `loop` statement without a `break` statement inside its loop block is infinite - -there is no way for the loop to stop iterating. diff --git a/doc/src/language/method.md b/doc/src/language/method.md deleted file mode 100644 index 5843faef..00000000 --- a/doc/src/language/method.md +++ /dev/null @@ -1,95 +0,0 @@ -Call Method as Function -====================== - -{{#include ../links.md}} - - -First `&mut` Parameter ----------------------- - -Property [getters/setters] and [methods][custom types] in a Rust custom type registered with the [`Engine`] can be called -just like a regular function. In fact, like Rust, property getters/setters and object methods -are registered as regular [functions] in Rhai that take a first `&mut` parameter. - -Unlike functions defined in script (for which all arguments are passed by _value_), -native Rust functions may mutate the object (or the first argument if called in normal function call style). - -However, sometimes it is not as straight-forward, and methods called in function-call style may end up -not muting the object – see the example below. Therefore, it is best to always use method-call style. - -Custom types, properties and methods can be disabled via the [`no_object`] feature. - -```rust -let a = new_ts(); // constructor function -a.field = 500; // property setter -a.update(); // method call, 'a' can be modified - -update(a); // <- this de-sugars to 'a.update()' thus if 'a' is a simple variable - // unlike scripted functions, 'a' can be modified and is not a copy - -let array = [ a ]; - -update(array[0]); // <- 'array[0]' is an expression returning a calculated value, - // a transient (i.e. a copy), so this statement has no effect - // except waste a lot of time cloning - -array[0].update(); // <- call in method-call style will update 'a' -``` - -**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** - - -Number of Parameters in Methods ------------------------------- - -Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than -an equivalent method coded in script, where the object is accessed via the `this` pointer instead. - -The following table illustrates the differences: - -| Function type | Parameters | Object reference | Function signature | -| :-----------: | :--------: | :-----------------------: | :---------------------------: | -| Native Rust | _N_ + 1 | first `&mut T` parameter | `Fn(obj: &mut T, x: U, y: V)` | -| Rhai script | _N_ | `this` (of type `&mut T`) | `Fn(x: U, y: V)` | - - -`&mut` is Efficient, Except for `&mut ImmutableString` ----------------------------------------------------- - -Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone, -even when the intention is not to mutate that argument, because it avoids cloning that argument value. - -Even when a function is never intended to be a method – for example an operator, -it is still sometimes beneficial to make it method-like (i.e. with a first `&mut` parameter) -if the first parameter is not modified. - -For types that are expensive to clone (remember, all function calls are passed cloned -copies of argument values), this may result in a significant performance boost. - -For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`, -this is not necessary. - -```rust -// This is a type that is very expensive to clone. -#[derive(Debug, Clone)] -struct VeryComplexType { ... } - -// Calculate some value by adding 'VeryComplexType' with an integer number. -fn do_add(obj: &VeryComplexType, offset: i64) -> i64 { - ... -} - -engine - .register_type::() - .register_fn("+", add_pure /* or add_method*/); - -// Very expensive to call, as the 'VeryComplexType' is cloned before each call. -fn add_pure(obj: VeryComplexType, offset: i64) -> i64 { - do_add(obj, offset) -} - -// Efficient to call, as only a reference to the 'VeryComplexType' is passed. -fn add_method(obj: &mut VeryComplexType, offset: i64) -> i64 { - do_add(obj, offset) -} -``` diff --git a/doc/src/language/modules/export.md b/doc/src/language/modules/export.md deleted file mode 100644 index 362ca111..00000000 --- a/doc/src/language/modules/export.md +++ /dev/null @@ -1,98 +0,0 @@ -Export Variables, Functions and Sub-Modules in Module -=================================================== - -{{#include ../../links.md}} - - -The easiest way to expose a collection of functions as a self-contained [module] is to do it via a Rhai script itself. - -See the section on [_Creating a Module from AST_]({{rootUrl}}/rust/modules/ast.md) for more details. - -The script text is evaluated, variables are then selectively exposed via the [`export`] statement. -Functions defined by the script are automatically exported. - -Modules loaded within this module at the global level become _sub-modules_ and are also automatically exported. - - -Export Global Variables ----------------------- - -The `export` statement, which can only be at global level, exposes selected variables as members of a module. - -Variables not exported are _private_ and hidden. They are merely used to initialize the module, -but cannot be accessed from outside. - -Everything exported from a module is **constant** (i.e. read-only). - -```rust -// This is a module script. - -let hidden = 123; // variable not exported - default hidden -let x = 42; // this will be exported below - -export x; // the variable 'x' is exported under its own name - -export let x = 42; // convenient short-hand to declare a variable and export it - // under its own name - -export x as answer; // the variable 'x' is exported under the alias 'answer' - // another script can load this module and access 'x' as 'module::answer' - -{ - let inner = 0; // local variable - it disappears when the statement block ends, - // therefore it is not 'global' and cannot be exported - - export inner; // <- syntax error: cannot export a local variable -} -``` - -### Multiple Exports - -One `export` statement can export multiple variables, even under multiple names. - -```rust -// The following exports three variables: -// - 'x' (as 'x' and 'hello') -// - 'y' (as 'foo' and 'bar') -// - 'z' (as 'z') -export x, x as hello, x as world, y as foo, y as bar, z; -``` - - -Export Functions ----------------- - -All functions are automatically exported, _unless_ it is explicitly opt-out with the [`private`] prefix. - -Functions declared [`private`] are hidden to the outside. - -```rust -// This is a module script. - -fn inc(x) { x + 1 } // script-defined function - default public - -private fn foo() {} // private function - hidden -``` - -[`private`] functions are commonly called to initialize the module. -They cannot be called apart from this. - - -Sub-Modules ------------ - -All loaded modules are automatically exported as sub-modules. - -To prevent a module from being exported, load it inside a block statement so that it goes away at the -end of the block. - -```rust -// This is a module script. - -import "hello" as foo; // exported as sub-module 'foo' - -{ - import "world" as bar; // not exported - the module disappears at the end - // of the statement block and is not 'global' -} -``` diff --git a/doc/src/language/modules/import.md b/doc/src/language/modules/import.md deleted file mode 100644 index d335beeb..00000000 --- a/doc/src/language/modules/import.md +++ /dev/null @@ -1,113 +0,0 @@ -Import a Module -=============== - -{{#include ../../links.md}} - - -Before a module can be used (via an `import` statement) in a script, there must be a [module resolver] -registered into the [`Engine`], the default being the `FileModuleResolver`. - -See the section on [_Module Resolvers_][module resolver] for more details. - - -`import` Statement ------------------ - -A module can be _imported_ via the `import` statement, and be given a name. -Its members can be accessed via '`::`' similar to C++. - -A module that is only `import`-ed but not under any module name is commonly used for initialization purposes, -where the module script contains initialization statements that puts the functions registered with the -[`Engine`] into a particular state. - -```rust -import "crypto_init"; // run the script file 'crypto_init.rhai' without creating an imported module - -import "crypto" as lock; // run the script file 'crypto.rhai' and import it as a module named 'lock' - -const SECRET_NUMBER = 42; - -let mod_file = "crypto_" + SECRET_NUMBER; - -import mod_file as my_mod; // load the script file "crypto_42.rhai" and import it as a module named 'my_mod' - // notice that module path names can be dynamically constructed! - // any expression that evaluates to a string is acceptable after the 'import' keyword - -lock::encrypt(secret); // use functions defined under the module via '::' - -lock::hash::sha256(key); // sub-modules are also supported - -print(lock::status); // module variables are constants - -lock::status = "off"; // <- runtime error - cannot modify a constant -``` - - -Scoped Imports --------------- - -`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported. - -They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are -group at the beginning of a script. It is not advised to deviate from this common practice unless -there is a _Very Good Reason™_. - -Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module -during every iteration of the loop! - -```rust -let mod = "crypto"; - -if secured { // new block scope - import mod as c; // import module (the path needs not be a constant string) - - c::encrypt(key); // use a function in the module -} // the module disappears at the end of the block scope - -c::encrypt(others); // <- this causes a run-time error because the 'crypto' module - // is no longer available! - -for x in range(0, 1000) { - import "crypto" as c; // <- importing a module inside a loop is a Very Bad Idea™ - - c.encrypt(something); -} -``` - - -Recursive Imports ----------------- - -Beware of _import cycles_ – i.e. recursively loading the same module. This is a sure-fire way to -cause a stack overflow in the [`Engine`], unless stopped by setting a limit for [maximum number of modules]. - -For instance, importing itself always causes an infinite recursion: - -```rust --------------- -| hello.rhai | --------------- - -import "hello" as foo; // import itself - infinite recursion! - -foo::do_something(); -``` - -Modules cross-referencing also cause infinite recursion: - -```rust --------------- -| hello.rhai | --------------- - -import "world" as foo; -foo::do_something(); - - --------------- -| world.rhai | --------------- - -import "hello" as bar; -bar::do_something_else(); -``` diff --git a/doc/src/language/modules/index.md b/doc/src/language/modules/index.md deleted file mode 100644 index dd8c928a..00000000 --- a/doc/src/language/modules/index.md +++ /dev/null @@ -1,14 +0,0 @@ -Modules -======= - -{{#include ../../links.md}} - -Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_. -Modules can be disabled via the [`no_module`] feature. - -A module is of the type `Module` and holds a collection of functions, variables, [type iterators] and sub-modules. -It may be created entirely from Rust functions, or it may encapsulate a Rhai script together with the functions -and variables defined by that script. - -Other scripts can then load this module and use the functions and variables exported -as if they were defined inside the same script. diff --git a/doc/src/language/num-fn.md b/doc/src/language/num-fn.md deleted file mode 100644 index 599b03c1..00000000 --- a/doc/src/language/num-fn.md +++ /dev/null @@ -1,46 +0,0 @@ -Numeric Functions -================ - -{{#include ../links.md}} - -Integer Functions ----------------- - -The following standard functions (defined in the [`BasicMathPackage`][packages] but excluded if using a [raw `Engine`]) -operate on `i8`, `i16`, `i32`, `i64`, `f32` and `f64` only: - -| Function | No available under | Description | -| -------- | :----------------: | ----------------------------------------------------------------------- | -| `abs` | | absolute value | -| `sign` | | returns -1 (`INT`) if the number is negative, +1 if positive, 0 if zero | - - -Floating-Point Functions ------------------------ - -The following standard functions (defined in the [`BasicMathPackage`][packages] but excluded if using a [raw `Engine`]) -operate on `f64` only: - -| Category | Functions | -| ---------------- | --------------------------------------------------------------------- | -| Trigonometry | `sin`, `cos`, `tan`, `sinh`, `cosh`, `tanh` in degrees | -| Arc-trigonometry | `asin`, `acos`, `atan`, `asinh`, `acosh`, `atanh` in degrees | -| Square root | `sqrt` | -| Exponential | `exp` (base _e_) | -| Logarithmic | `ln` (base _e_), `log10` (base 10), `log` (any base) | -| Rounding | `floor`, `ceiling`, `round`, `int`, `fraction` methods and properties | -| Conversion | [`to_int`] | -| Testing | `is_nan`, `is_finite`, `is_infinite` methods and properties | - - -Conversion Functions -------------------- - -The following standard functions (defined in the [`BasicMathPackage`][packages] but excluded if using a [raw `Engine`]) -parse numbers: - -| Function | No available under | Description | -| --------------- | :----------------: | --------------------------------------------------- | -| [`to_float`] | [`no_float`] | converts an integer type to `FLOAT` | -| [`parse_int`] | | converts a [string] to `INT` with an optional radix | -| [`parse_float`] | [`no_float`] | converts a [string] to `FLOAT` | diff --git a/doc/src/language/num-op.md b/doc/src/language/num-op.md deleted file mode 100644 index a897c7ae..00000000 --- a/doc/src/language/num-op.md +++ /dev/null @@ -1,51 +0,0 @@ -Numeric Operators -================= - -{{#include ../links.md}} - -Numeric operators generally follow C styles. - -Unary Operators ---------------- - -| Operator | Description | -| -------- | ----------- | -| `+` | positive | -| `-` | negative | - -```rust -let number = -5; - -number = -5 - +5; -``` - -Binary Operators ----------------- - -| Operator | Description | Integers only | -| --------------- | ---------------------------------------------------- | :-----------: | -| `+` | plus | | -| `-` | minus | | -| `*` | multiply | | -| `/` | divide (integer division if acting on integer types) | | -| `%` | modulo (remainder) | | -| `~` | power | | -| `&` | bit-wise _And_ | Yes | -| \| | bit-wise _Or_ | Yes | -| `^` | bit-wise _Xor_ | Yes | -| `<<` | left bit-shift | Yes | -| `>>` | right bit-shift | Yes | - -```rust -let x = (1 + 2) * (6 - 4) / 2; // arithmetic, with parentheses - -let reminder = 42 % 10; // modulo - -let power = 42 ~ 2; // power (i64 and f64 only) - -let left_shifted = 42 << 3; // left shift - -let right_shifted = 42 >> 3; // right shift - -let bit_op = 42 | 99; // bit masking -``` diff --git a/doc/src/language/numbers.md b/doc/src/language/numbers.md deleted file mode 100644 index 78a4f236..00000000 --- a/doc/src/language/numbers.md +++ /dev/null @@ -1,22 +0,0 @@ -Numbers -======= - -{{#include ../links.md}} - -Integer numbers follow C-style format with support for decimal, binary ('`0b`'), octal ('`0o`') and hex ('`0x`') notations. - -The default system integer type (also aliased to `INT`) is `i64`. It can be turned into `i32` via the [`only_i32`] feature. - -Floating-point numbers are also supported if not disabled with [`no_float`]. The default system floating-point type is `i64` -(also aliased to `FLOAT`). It can be turned into `f32` via the [`f32_float`] feature. - -'`_`' separators can be added freely and are ignored within a number – except at the very beginning or right after -a decimal point ('`.`'). - -| Format | Type | -| --------------------- | ---------------- | -| `123_345`, `-42` | `INT` in decimal | -| `0o07_76` | `INT` in octal | -| `0xabcd_ef` | `INT` in hex | -| `0b0101_1001` | `INT` in binary | -| `123_456.789`, `-42.` | `FLOAT` | diff --git a/doc/src/language/object-maps-oop.md b/doc/src/language/object-maps-oop.md deleted file mode 100644 index f96fda04..00000000 --- a/doc/src/language/object-maps-oop.md +++ /dev/null @@ -1,39 +0,0 @@ -Special Support for OOP via Object Maps -====================================== - -{{#include ../links.md}} - -[Object maps] can be used to simulate [object-oriented programming (OOP)][OOP] by storing data -as properties and methods as properties holding [function pointers]. - -If an [object map]'s property holds a [function pointer], the property can simply be called like -a normal method in method-call syntax. This is a _short-hand_ to avoid the more verbose syntax -of using the `call` function keyword. - -When a property holding a [function pointer] or a [closure] is called like a method, -what happens next depends on whether the target function is a native Rust function or -a script-defined function. - -* If it is a registered native Rust function, it is called directly in _method-call_ style with the [object map] inserted as the first argument. - -* If it is a script-defined function, the `this` variable within the function body is bound to the [object map] before the function is called. - -```rust -let obj = #{ - data: 40, - action: || this.data += x // 'action' holds a closure - }; - -obj.action(2); // calls the function pointer with `this` bound to 'obj' - -obj.call(obj.action, 2); // <- the above de-sugars to this - -obj.data == 42; - -// To achieve the above with normal function pointer call will fail. -fn do_action(map, x) { map.data += x; } // 'map' is a copy - -obj.action = Fn("do_action"); - -obj.action.call(obj, 2); // 'obj' is passed as a copy by value -``` diff --git a/doc/src/language/object-maps.md b/doc/src/language/object-maps.md deleted file mode 100644 index 8dcdbef5..00000000 --- a/doc/src/language/object-maps.md +++ /dev/null @@ -1,169 +0,0 @@ -Object Maps -=========== - -{{#include ../links.md}} - -Object maps are hash dictionaries. Properties are all [`Dynamic`] and can be freely added and retrieved. - -The Rust type of a Rhai object map is `rhai::Map`. - -[`type_of()`] an object map returns `"map"`. - -Object maps are disabled via the [`no_object`] feature. - -The maximum allowed size of an object map can be controlled via `Engine::set_max_map_size` -(see [maximum size of object maps]). - - -Object Map Literals ------------------- - -Object map literals are built within braces '`#{`' ... '`}`' (_name_ `:` _value_ syntax similar to Rust) -and separated by commas '`,`': - -> `#{` _property_ `:` _value_ `,` `...` `,` _property_ `:` _value_ `}` -> -> `#{` _property_ `:` _value_ `,` `...` `,` _property_ `:` _value_ `,` `}` `// trailing comma is OK` - -The property _name_ can be a simple variable name following the same -naming rules as [variables], or an arbitrary [string] literal. - - -Access Properties ------------------ - -### Dot Notation - -The _dot notation_ allows only property names that follow the same naming rules as [variables]. - -> _object_ `.` _property_ - -### Index Notation - -The _index notation_ allows setting/getting properties of arbitrary names (even the empty [string]). - -> _object_ `[` _property_ `]` - -### Non-Existence - -Trying to read a non-existing property returns [`()`] instead of causing an error. - -This is similar to JavaScript where accessing a non-existing property returns `undefined`. - - -Built-in Functions ------------------ - -The following methods (defined in the [`BasicMapPackage`][packages] but excluded if using a [raw `Engine`]) -operate on object maps: - -| Function | Parameter(s) | Description | -| ---------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| `has`, `in` operator | property name | does the object map contain a property of a particular name? | -| `len` | _none_ | returns the number of properties | -| `clear` | _none_ | empties the object map | -| `remove` | property name | removes a certain property and returns it ([`()`] if the property does not exist) | -| `+=` operator, `mixin` | second object map | mixes in all the properties of the second object map to the first (values of properties with the same names replace the existing values) | -| `+` operator | 1) first object map
2) second object map | merges the first object map with the second | -| `==` operator | 1) first object map
2) second object map | are the two object map the same (elements compared with the `==` operator, if defined)? | -| `!=` operator | 1) first object map
2) second object map | are the two object map different (elements compared with the `==` operator, if defined)? | -| `fill_with` | second object map | adds in all properties of the second object map that do not exist in the object map | -| `keys` | _none_ | returns an [array] of all the property names (in random order), not available under [`no_index`] | -| `values` | _none_ | returns an [array] of all the property values (in random order), not available under [`no_index`] | - - -Examples --------- - -```rust -let y = #{ // object map literal with 3 properties - a: 1, - bar: "hello", - "baz!$@": 123.456, // like JavaScript, you can use any string as property names... - "": false, // even the empty string! - - a: 42 // <- syntax error: duplicated property name -}; - -y.a = 42; // access via dot notation -y.baz!$@ = 42; // <- syntax error: only proper variable names allowed in dot notation -y."baz!$@" = 42; // <- syntax error: strings not allowed in dot notation - -y.a == 42; - -y["baz!$@"] == 123.456; // access via index notation - -"baz!$@" in y == true; // use 'in' to test if a property exists in the object map -("z" in y) == false; - -ts.obj = y; // object maps can be assigned completely (by value copy) -let foo = ts.list.a; -foo == 42; - -let foo = #{ a:1,}; // trailing comma is OK - -let foo = #{ a:1, b:2, c:3 }["a"]; -foo == 1; - -fn abc() { - ##{ a:1, b:2, c:3 } // a function returning an object map -} - -let foo = abc().b; -foo == 2; - -let foo = y["a"]; -foo == 42; - -y.has("a") == true; -y.has("xyz") == false; - -y.xyz == (); // a non-existing property returns '()' -y["xyz"] == (); - -y.len() == 3; - -y.remove("a") == 1; // remove property - -y.len() == 2; -y.has("a") == false; - -for name in y.keys() { // get an array of all the property names via 'keys' - print(name); -} - -for val in y.values() { // get an array of all the property values via 'values' - print(val); -} - -y.clear(); // empty the object map - -y.len() == 0; -``` - - -No Support for Property Getters ------------------------------- - -In order not to affect the speed of accessing properties in an object map, new property -[getters][getters/setters] cannot be registered because they conflict with the syntax of -property access. - -A property [getter][getters/setters] function registered via `Engine::register_get`, for example, -for a `Map` will never be found – instead, the property will be looked up in the object map. - -Therefore, _method-call_ notation must be used for built-in properties: - -```rust -map.len // access property 'len', returns '()' if not found - -map.len() // returns the number of properties - -map.keys // access property 'keys', returns '()' if not found - -map.keys() // returns array of all property names - -map.values // access property 'values', returns '()' if not found - -map.values() // returns array of all property values -``` diff --git a/doc/src/language/overload.md b/doc/src/language/overload.md deleted file mode 100644 index 2ec2fd4e..00000000 --- a/doc/src/language/overload.md +++ /dev/null @@ -1,29 +0,0 @@ -Function Overloading -=================== - -{{#include ../links.md}} - -[Functions] defined in script can be _overloaded_ by _arity_ (i.e. they are resolved purely upon the function's _name_ -and _number_ of parameters, but not parameter _types_ since all parameters are the same type – [`Dynamic`]). - -New definitions _overwrite_ previous definitions of the same name and number of parameters. - -```rust -fn foo(x,y,z) { print("Three!!! " + x + "," + y + "," + z); } - -fn foo(x) { print("One! " + x); } - -fn foo(x,y) { print("Two! " + x + "," + y); } - -fn foo() { print("None."); } - -fn foo(x) { print("HA! NEW ONE! " + x); } // overwrites previous definition - -foo(1,2,3); // prints "Three!!! 1,2,3" - -foo(42); // prints "HA! NEW ONE! 42" - -foo(1,2); // prints "Two!! 1,2" - -foo(); // prints "None." -``` diff --git a/doc/src/language/print-debug.md b/doc/src/language/print-debug.md deleted file mode 100644 index 996e6aac..00000000 --- a/doc/src/language/print-debug.md +++ /dev/null @@ -1,72 +0,0 @@ -`print` and `debug` -=================== - -{{#include ../links.md}} - -The `print` and `debug` functions default to printing to `stdout`, with `debug` using standard debug formatting. - -```rust -print("hello"); // prints hello to stdout - -print(1 + 2 + 3); // prints 6 to stdout - -print("hello" + 42); // prints hello42 to stdout - -debug("world!"); // prints "world!" to stdout using debug formatting -``` - -Override `print` and `debug` with Callback Functions --------------------------------------------------- - -When embedding Rhai into an application, it is usually necessary to trap `print` and `debug` output -(for logging into a tracking log, for example) with the `Engine::on_print` and `Engine::on_debug` methods: - -```rust -// Any function or closure that takes an '&str' argument can be used to override 'print'. -engine.on_print(|x| println!("hello: {}", x)); - -// Any function or closure that takes a '&str' and a 'Position' argument can be used to -// override 'debug'. -engine.on_debug(|x, src, pos| println!("DEBUG of {} at {:?}: {}", src.unwrap_or("unknown"), pos, x)); - -// Example: quick-'n-dirty logging -let logbook = Arc::new(RwLock::new(Vec::::new())); - -// Redirect print/debug output to 'log' -let log = logbook.clone(); -engine.on_print(move |s| log.write().unwrap().push(format!("entry: {}", s))); - -let log = logbook.clone(); -engine.on_debug(move |s, src, pos| log.write().unwrap().push( - format!("DEBUG of {} at {:?}: {}", src.unwrap_or("unknown"), pos, s) - )); - -// Evaluate script -engine.eval::<()>(script)?; - -// 'logbook' captures all the 'print' and 'debug' output -for entry in logbook.read().unwrap().iter() { - println!("{}", entry); -} -``` - - -`on_debug` Callback Signature ------------------------------ - -The function signature passed to `Engine::on_debug` takes the following form: - -> `Fn(text: &str, source: Option<&str>, pos: Position) + 'static` - -where: - -| Parameter | Type | Description | -| --------- | :------------: | --------------------------------------------------------------- | -| `text` | `&str` | text to display | -| `source` | `Option<&str>` | source of the current evaluation, if any | -| `pos` | `Position` | position (line number and character offset) of the `debug` call | - -The _source_ of a script evaluation is any text string provided to an [`AST`] via the `AST::set_source` method. - -If a [module] is loaded via an [`import`] statement, then the _source_ of functions defined -within the module will be the module's _path_. diff --git a/doc/src/language/return.md b/doc/src/language/return.md deleted file mode 100644 index 41c063f9..00000000 --- a/doc/src/language/return.md +++ /dev/null @@ -1,16 +0,0 @@ -Return Values -============= - -{{#include ../links.md}} - -The `return` statement is used to immediately stop evaluation and exist the current context -(typically a function call) yielding a _return value_. - -```rust -return; // equivalent to return (); - -return 123 + 456; // returns 579 -``` - -A `return` statement at _global_ level stop the entire script evaluation, -the return value is taken as the result of the script evaluation. diff --git a/doc/src/language/statements.md b/doc/src/language/statements.md deleted file mode 100644 index a4fad876..00000000 --- a/doc/src/language/statements.md +++ /dev/null @@ -1,42 +0,0 @@ -Statements -========== - -{{#include ../links.md}} - -Terminated by '`;`' ------------------- - -Statements are terminated by semicolons '`;`' and they are mandatory, -except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted. - -Semicolons can also be omitted if the statement ends with a block itself -(e.g. the `if`, `while`, `for` and `loop` statements). - -```rust -let a = 42; // normal assignment statement -let a = foo(42); // normal function call statement -foo < 42; // normal expression as statement - -let a = { 40 + 2 }; // 'a' is set to the value of the statement block, which is the value of the last statement -// ^ the last statement does not require a terminating semicolon (although it also works with it) -// ^ semicolon required here to terminate the assignment statement; it is a syntax error without it - -if foo { a = 42 } -// ^ there is no need to terminate an if-statement with a semicolon - -4 * 10 + 2 // a statement which is just one expression - no ending semicolon is OK - // because it is the last statement of the whole block -``` - - -Statement Expression --------------------- - -A statement can be used anywhere where an expression is expected. These are called, for lack of a more -creative name, "statement expressions." - -The _last_ statement of a statement block is _always_ the block's return value when used as a statement, -_regardless_ of whether it is terminated by a semicolon or not. This is different from Rust where, -if the last statement is terminated by a semicolon, the block's return value is taken to be `()`. - -If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`]. diff --git a/doc/src/language/string-fn.md b/doc/src/language/string-fn.md deleted file mode 100644 index db3d8b88..00000000 --- a/doc/src/language/string-fn.md +++ /dev/null @@ -1,65 +0,0 @@ -Built-in String Functions -======================== - -{{#include ../links.md}} - -The following standard methods (mostly defined in the [`MoreStringPackage`][packages] but excluded if -using a [raw `Engine`]) operate on [strings]: - -| Function | Parameter(s) | Description | -| ------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| `len` method and property | _none_ | returns the number of characters (not number of bytes) in the string | -| `pad` | 1) target length
2) character/string to pad | pads the string with a character or a string to at least a specified length | -| `+=` operator, `append` | character/string to append | Adds a character or a string to the end of another string | -| `clear` | _none_ | empties the string | -| `truncate` | target length | cuts off the string at exactly a specified number of characters | -| `contains` | character/sub-string to search for | checks if a certain character or sub-string occurs in the string | -| `index_of` | 1) character/sub-string to search for
2) _(optional)_ start index | returns the index that a certain character or sub-string occurs in the string, or -1 if not found | -| `sub_string` | 1) start index
2) _(optional)_ number of characters to extract, none if < 0 | extracts a sub-string (to the end of the string if length is not specified) | -| `split` | delimiter character/string | splits the string by the specified delimiter, returning an [array] of string segments; not available under [`no_index`] | -| `crop` | 1) start index
2) _(optional)_ number of characters to retain, none if < 0 | retains only a portion of the string | -| `replace` | 1) target character/sub-string
2) replacement character/string | replaces a sub-string with another | -| `trim` | _none_ | trims the string of whitespace at the beginning and end | - -Examples --------- - -```rust -let full_name == " Bob C. Davis "; -full_name.len == 14; - -full_name.trim(); -full_name.len == 12; -full_name == "Bob C. Davis"; - -full_name.pad(15, '$'); -full_name.len == 15; -full_name == "Bob C. Davis$$$"; - -let n = full_name.index_of('$'); -n == 12; - -full_name.index_of("$$", n + 1) == 13; - -full_name.sub_string(n, 3) == "$$$"; - -full_name.truncate(6); -full_name.len == 6; -full_name == "Bob C."; - -full_name.replace("Bob", "John"); -full_name.len == 7; -full_name == "John C."; - -full_name.contains('C') == true; -full_name.contains("John") == true; - -full_name.crop(5); -full_name == "C."; - -full_name.crop(0, 1); -full_name == "C"; - -full_name.clear(); -full_name.len == 0; -``` diff --git a/doc/src/language/strings-chars.md b/doc/src/language/strings-chars.md deleted file mode 100644 index f814288e..00000000 --- a/doc/src/language/strings-chars.md +++ /dev/null @@ -1,133 +0,0 @@ -Strings and Characters -===================== - -{{#include ../links.md}} - -String in Rhai contain any text sequence of valid Unicode characters. -Internally strings are stored in UTF-8 encoding. - -Strings can be built up from other strings and types via the `+` operator -(provided by the [`MoreStringPackage`][packages] but excluded if using a [raw `Engine`]). -This is particularly useful when printing output. - -[`type_of()`] a string returns `"string"`. - -The maximum allowed length of a string can be controlled via `Engine::set_max_string_size` -(see [maximum length of strings]). - - -The `ImmutableString` Type -------------------------- - -All strings in Rhai are implemented as `ImmutableString` (see [standard types]). -An `ImmutableString` does not change and can be shared. - -Modifying an `ImmutableString` causes it first to be cloned, and then the modification made to the copy. - -### **IMPORTANT** – Avoid `String` Parameters - -`ImmutableString` should be used in place of `String` for function parameters because using -`String` is very inefficient (the `String` argument is cloned during every call). - -A alternative is to use `&str` which de-sugars to `ImmutableString`. - -```rust -fn slow(s: String) -> i64 { ... } // string is cloned each call - -fn fast1(s: ImmutableString) -> i64 { ... } // cloning 'ImmutableString' is cheap - -fn fast2(s: &str) -> i64 { ... } // de-sugars to above -``` - - -String and Character Literals ----------------------------- - -String and character literals follow C-style formatting, with support for Unicode ('`\u`_xxxx_' or '`\U`_xxxxxxxx_') -and hex ('`\x`_xx_') escape sequences. - -Hex sequences map to ASCII characters, while '`\u`' maps to 16-bit common Unicode code points and '`\U`' maps the full, -32-bit extended Unicode code points. - -Standard escape sequences: - -| Escape sequence | Meaning | -| --------------- | -------------------------------- | -| `\\` | back-slash `\` | -| `\t` | tab | -| `\r` | carriage-return `CR` | -| `\n` | line-feed `LF` | -| `\"` | double-quote `"` | -| `\'` | single-quote `'` | -| `\x`_xx_ | ASCII character in 2-digit hex | -| `\u`_xxxx_ | Unicode character in 4-digit hex | -| `\U`_xxxxxxxx_ | Unicode character in 8-digit hex | - - -Differences from Rust Strings ----------------------------- - -Internally Rhai strings are stored as UTF-8 just like Rust (they _are_ Rust `String`'s!), -but nevertheless there are major differences. - -In Rhai a string is the same as an array of Unicode characters and can be directly indexed (unlike Rust). - -This is similar to most other languages where strings are internally represented not as UTF-8 but as arrays of multi-byte -Unicode characters. - -Individual characters within a Rhai string can also be replaced just as if the string is an array of Unicode characters. - -In Rhai, there are also no separate concepts of `String` and `&str` as in Rust. - - -Examples --------- - -```rust -let name = "Bob"; -let middle_initial = 'C'; -let last = "Davis"; - -let full_name = name + " " + middle_initial + ". " + last; -full_name == "Bob C. Davis"; - -// String building with different types -let age = 42; -let record = full_name + ": age " + age; -record == "Bob C. Davis: age 42"; - -// Unlike Rust, Rhai strings can be indexed to get a character -// (disabled with 'no_index') -let c = record[4]; -c == 'C'; - -ts.s = record; // custom type properties can take strings - -let c = ts.s[4]; -c == 'C'; - -let c = "foo"[0]; // indexing also works on string literals... -c == 'f'; - -let c = ("foo" + "bar")[5]; // ... and expressions returning strings -c == 'r'; - -// Escape sequences in strings -record += " \u2764\n"; // escape sequence of '❤' in Unicode -record == "Bob C. Davis: age 42 ❤\n"; // '\n' = new-line - -// Unlike Rust, Rhai strings can be directly modified character-by-character -// (disabled with 'no_index') -record[4] = '\x58'; // 0x58 = 'X' -record == "Bob X. Davis: age 42 ❤\n"; - -// Use 'in' to test if a substring (or character) exists in a string -"Davis" in record == true; -'X' in record == true; -'C' in record == false; - -// Strings can be iterated with a 'for' statement, yielding characters -for ch in record { - print(ch); -} -``` diff --git a/doc/src/language/switch.md b/doc/src/language/switch.md deleted file mode 100644 index 08d380ee..00000000 --- a/doc/src/language/switch.md +++ /dev/null @@ -1,111 +0,0 @@ -`switch` Expression -=================== - -{{#include ../links.md}} - -The `switch` _expression_ allows matching on literal values, and it mostly follows Rust's -`match` syntax: - -```c -switch calc_secret_value(x) { - 1 => print("It's one!"), - 2 => { - print("It's two!"); - print("Again!"); - } - 3 => print("Go!"), - // _ is the default when no cases match - _ => print("Oops! Something's wrong: " + x) -} -``` - - -Expression, Not Statement ------------------------- - -`switch` is not a statement, but an expression. This means that a `switch` expression can -appear anywhere a regular expression can, e.g. as function call arguments. - -```c -let x = switch foo { 1 => true, _ => false }; - -func(switch foo { - "hello" => 42, - "world" => 123, - _ => 0 -}); - -// The above is somewhat equivalent to: - -let x = if foo == 1 { true } else { false }; - -if foo == "hello" { - func(42); -} else if foo == "world" { - func(123); -} else { - func(0); -} -``` - - -Array and Object Map Literals Also Work --------------------------------------- - -The `switch` expression can match against any _literal_, including [array] and [object map] literals. - -```c -// Match on arrays -switch [foo, bar, baz] { - ["hello", 42, true] => { ... } - ["hello", 123, false] => { ... } - ["world", 1, true] => { ... } - _ => { ... } -} - -// Match on object maps -switch map { - #{ a: 1, b: 2, c: true } => { ... } - #{ a: 42, d: "hello" } => { ... } - _ => { ... } -} -``` - -Switching on [arrays] is very useful when working with Rust enums (see [this chapter]({{rootUrl}}/patterns/enums.md) -for more details). - - -Difference From `if`-`else if` Chain ------------------------------------ - -Although a `switch` expression looks _almost_ the same as an `if`-`else if` chain, -there are subtle differences between the two. - -### Look-up Table vs `x == y` - -A `switch` expression matches through _hashing_ via a look-up table. -Therefore, matching is very fast. Walking down an `if`-`else if` chain -is _much_ slower. - -On the other hand, operators can be [overloaded][operator overloading] in Rhai, -meaning that it is possible to override the `==` operator for integers such -that `x == y` returns a different result from the built-in default. - -`switch` expressions do _not_ use the `==` operator for comparison; -instead, they _hash_ the data values and jump directly to the correct -statements via a pre-compiled look-up table. This makes matching extremely -efficient, but it also means that [overloading][operator overloading] -the `==` operator will have no effect. - -Therefore, in environments where it is desirable to [overload][operator overloading] -the `==` operator – though it is difficult to think of valid scenarios where you'd want -`1 == 1` to return something other than `true` – avoid using the `switch` expression. - -### Efficiency - -Because the `switch` expression works through a look-up table, it is very efficient -even for _large_ number of cases; in fact, switching is an O(1) operation regardless -of the size of the data and number of cases to match. - -A long `if`-`else if` chain becomes increasingly slower with each additional case -because essentially an O(n) _linear scan_ is performed. diff --git a/doc/src/language/throw.md b/doc/src/language/throw.md deleted file mode 100644 index a11a8074..00000000 --- a/doc/src/language/throw.md +++ /dev/null @@ -1,52 +0,0 @@ -Throw Exception on Error -======================= - -{{#include ../links.md}} - -All of [`Engine`]'s evaluation/consuming methods return `Result>` -with `EvalAltResult` holding error information. - -To deliberately return an error during an evaluation, use the `throw` keyword. - -```rust -if some_bad_condition_has_happened { - throw error; // 'throw' any value as the exception -} - -throw; // defaults to '()' -``` - -Exceptions thrown via `throw` in the script can be captured in Rust by matching -`Err(Box)` with the exception value -captured by `value`. - -```rust -let result = engine.eval::(r#" - let x = 42; - - if x > 0 { - throw x; - } -"#); - -println!("{}", result); // prints "Runtime error: 42 (line 5, position 15)" -``` - - -Catch a Thrown Exception ------------------------- - -It is possible to _catch_ an exception instead of having it abort the evaluation -of the entire script via the [`try` ... `catch`]({{rootUrl}}/language/try-catch.md) -statement common to many C-like languages. - -```rust -try -{ - throw 42; -} -catch (err) // 'err' captures the thrown exception value -{ - print(err); // prints 42 -} -``` diff --git a/doc/src/language/timestamps.md b/doc/src/language/timestamps.md deleted file mode 100644 index 0a8a0adc..00000000 --- a/doc/src/language/timestamps.md +++ /dev/null @@ -1,40 +0,0 @@ -`timestamp` -=========== - -{{#include ../links.md}} - -Timestamps are provided by the [`BasicTimePackage`][packages] (excluded if using a [raw `Engine`]) -via the `timestamp` function. - -Timestamps are not available under [`no_std`]. - -The Rust type of a timestamp is `std::time::Instant` ([`instant::Instant`] in [WASM] builds). - -[`type_of()`] a timestamp returns `"timestamp"`. - - -Built-in Functions ------------------ - -The following methods (defined in the [`BasicTimePackage`][packages] but excluded if using a [raw `Engine`]) operate on timestamps: - -| Function | Parameter(s) | Description | -| ----------------------------- | ------------------------------------------- | -------------------------------------------------------- | -| `elapsed` method and property | _none_ | returns the number of seconds since the timestamp | -| `-` operator | 1) later timestamp
2) earlier timestamp | returns the number of seconds between the two timestamps | -| `+` operator | number of seconds to add | returns a new timestamp | -| `-` operator | number of seconds to subtract | returns a new timestamp | - - -Examples --------- - -```rust -let now = timestamp(); - -// Do some lengthy operation... - -if now.elapsed > 30.0 { - print("takes too long (over 30 seconds)!") -} -``` diff --git a/doc/src/language/try-catch.md b/doc/src/language/try-catch.md deleted file mode 100644 index a132fc61..00000000 --- a/doc/src/language/try-catch.md +++ /dev/null @@ -1,108 +0,0 @@ -Catch Exceptions -================ - -{{#include ../links.md}} - - -When an [exception] is thrown via a [`throw`] statement, evaluation of the script halts -and the [`Engine`] returns with `Err(Box)` containing the -exception value that has been thrown. - -It is possible, via the `try` ... `catch` statement, to _catch_ exceptions, optionally -with an _error variable_. - -```rust -// Catch an exception and capturing its value -try -{ - throw 42; -} -catch (err) // 'err' captures the thrown exception value -{ - print(err); // prints 42 -} - -// Catch an exception without capturing its value -try -{ - print(42/0); // deliberate divide-by-zero exception -} -catch // no error variable - exception value is discarded -{ - print("Ouch!"); -} - -// Exception in the 'catch' block -try -{ - print(42/0); // throw divide-by-zero exception -} -catch -{ - print("You seem to be dividing by zero here..."); - - throw "die"; // a 'throw' statement inside a 'catch' block - // throws a new exception -} -``` - - -Re-Throw Exception ------------------- - -Like the `try` ... `catch` syntax in most languages, it is possible to _re-throw_ -an exception within the `catch` block simply by another [`throw`] statement without -a value. - - -```rust -try -{ - // Call something that will throw an exception... - do_something_bad_that_throws(); -} -catch -{ - print("Oooh! You've done something real bad!"); - - throw; // 'throw' without a value within a 'catch' block - // re-throws the original exception -} - -``` - - -Catchable Exceptions --------------------- - -Many script-oriented exceptions can be caught via `try` ... `catch`: - -| Error type | Error value | -| --------------------------------------------- | :------------------------: | -| Runtime error thrown by a [`throw`] statement | value in `throw` statement | -| Other runtime error | error message [string] | -| Arithmetic error | error message [string] | -| Variable not found | error message [string] | -| [Function] not found | error message [string] | -| [Module] not found | error message [string] | -| Unbound [`this`] | error message [string] | -| Data type mismatch | error message [string] | -| Assignment to a calculated/constant value | error message [string] | -| [Array]/[string] indexing out-of-bounds | error message [string] | -| Indexing with an inappropriate data type | error message [string] | -| Error in a dot expression | error message [string] | -| `for` statement without a [type iterator] | error message [string] | -| Error in an `in` expression | error message [string] | -| Data race detected | error message [string] | - - -Non-Catchable Exceptions ------------------------- - -Some exceptions _cannot_ be caught: - -* Syntax error during parsing -* System error – e.g. script file not found -* Script evaluation metrics over [safety limits]({{rootUrl}}/safety/index.md) -* Function calls nesting exceeding [maximum call stack depth] -* Script evaluation manually terminated diff --git a/doc/src/language/type-of.md b/doc/src/language/type-of.md deleted file mode 100644 index 45e3d0b0..00000000 --- a/doc/src/language/type-of.md +++ /dev/null @@ -1,47 +0,0 @@ -`type_of()` -=========== - -{{#include ../links.md}} - -The `type_of` function detects the actual type of a value. - -This is useful because all variables are [`Dynamic`] in nature. - -```rust -// Use 'type_of()' to get the actual types of values -type_of('c') == "char"; -type_of(42) == "i64"; - -let x = 123; -x.type_of() == "i64"; // method-call style is also OK -type_of(x) == "i64"; - -x = 99.999; -type_of(x) == "f64"; - -x = "hello"; -if type_of(x) == "string" { - do_something_with_string(x); -} -``` - - -Custom Types ------------- - -`type_of()` a [custom type] returns: - -* if registered via `Engine::register_type_with_name` – the registered name - -* if registered via `Engine::register_type` – the full Rust path name - -```rust -struct TestStruct1; -struct TestStruct2; - -engine - // type_of(struct1) == "crate::path::to::module::TestStruct1" - .register_type::() - // type_of(struct2) == "MyStruct" - .register_type_with_name::("MyStruct"); -``` diff --git a/doc/src/language/values-and-types.md b/doc/src/language/values-and-types.md deleted file mode 100644 index fbae2013..00000000 --- a/doc/src/language/values-and-types.md +++ /dev/null @@ -1,42 +0,0 @@ -Values and Types -=============== - -{{#include ../links.md}} - -The following primitive types are supported natively: - -| Category | Equivalent Rust types | [`type_of()`] | `to_string()` | -| -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | --------------------- | ----------------------- | -| **Integer number** | `u8`, `i8`, `u16`, `i16`,
`u32`, `i32` (default for [`only_i32`]),
`u64`, `i64` _(default)_ | `"i32"`, `"u64"` etc. | `"42"`, `"123"` etc. | -| **Floating-point number** (disabled with [`no_float`]) | `f32` (default for [`f32_float`]), `f64` _(default)_ | `"f32"` or `"f64"` | `"123.4567"` etc. | -| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` | -| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` etc. | -| **Immutable Unicode [string]** | `rhai::ImmutableString` (implemented as `Rc` or `Arc`) | `"string"` | `"hello"` etc. | -| **[`Array`]** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` | -| **[Object map]** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `"#{ "a": 1, "b": 2 }"` | -| **[Timestamp]** (implemented in the [`BasicTimePackage`][packages], disabled with [`no_std`]) | `std::time::Instant` ([`instant::Instant`] if [WASM] build) | `"timestamp"` | `""` | -| **[Function pointer]** | `rhai::FnPtr` | `Fn` | `"Fn(foo)"` | -| **[`Dynamic`] value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ | -| **Shared value** (a reference-counted, shared [`Dynamic`] value, created via [automatic currying], disabled with [`no_closure`]) | | _the actual type_ | _actual value_ | -| **System integer** (current configuration) | `rhai::INT` (`i32` or `i64`) | `"i32"` or `"i64"` | `"42"`, `"123"` etc. | -| **System floating-point** (current configuration, disabled with [`no_float`]) | `rhai::FLOAT` (`f32` or `f64`) | `"f32"` or `"f64"` | `"123.456"` etc. | -| **Nothing/void/nil/null/Unit** (or whatever it is called) | `()` | `"()"` | `""` _(empty string)_ | - -All types are treated strictly separate by Rhai, meaning that `i32` and `i64` and `u32` are completely different - -they even cannot be added together. This is very similar to Rust. - -The default integer type is `i64`. If other integer types are not needed, it is possible to exclude them and make a -smaller build with the [`only_i64`] feature. - -If only 32-bit integers are needed, enabling the [`only_i32`] feature will remove support for all integer types other than `i32`, including `i64`. -This is useful on some 32-bit targets where using 64-bit integers incur a performance penalty. - -If no floating-point is needed or supported, use the [`no_float`] feature to remove it. - -[Strings] in Rhai are _immutable_, meaning that they can be shared but not modified. In actual, the `ImmutableString` type -is an alias to `Rc` or `Arc` (depending on the [`sync`] feature). -Any modification done to a Rhai string will cause the string to be cloned and the modifications made to the copy. - -The `to_string` function converts a standard type into a [string] for display purposes. - -The `to_debug` function converts a standard type into a [string] in debug format. diff --git a/doc/src/language/variables.md b/doc/src/language/variables.md deleted file mode 100644 index d2582906..00000000 --- a/doc/src/language/variables.md +++ /dev/null @@ -1,68 +0,0 @@ -Variables -========= - -{{#include ../links.md}} - -Valid Names ------------ - -Variables in Rhai follow normal C naming rules – must contain only ASCII letters, digits and underscores '`_`', -and cannot start with a digit. - -For example: '`_c3po`' and '`r2d2`' are valid variable names, but '`3abc`' is not. - -However, unlike Rust, a variable name must also contain at least one ASCII letter, and an ASCII letter must come before any digit. -In other words, the first character that is not an underscore '`_`' must be an ASCII letter and not a digit. - -Therefore, some names acceptable to Rust, like '`_`', '`_42foo`', '`_1`' etc., are not valid in Rhai. -This restriction is to reduce confusion because, for instance, '`_1`' can easily be misread (or mis-typed) as `-1`. - -Variable names are case _sensitive_. - -Variable names also cannot be the same as a [keyword]. - -### Unicode Standard Annex #31 Identifiers - -The [`unicode-xid-ident`] feature expands the allowed characters for variable names to the set defined by -[Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/). - - -Declare a Variable ------------------- - -Variables are declared using the `let` keyword. - -Variables do not have to be given an initial value. -If none is provided, it defaults to [`()`]. - -A variable defined within a statement block is _local_ to that block. - -Use `is_def_var` to detect if a variable is defined. - -```rust -let x; // ok - value is '()' -let x = 3; // ok -let _x = 42; // ok -let x_ = 42; // also ok -let _x_ = 42; // still ok - -let _ = 123; // <- syntax error: illegal variable name -let _9 = 9; // <- syntax error: illegal variable name - -let x = 42; // variable is 'x', lower case -let X = 123; // variable is 'X', upper case -x == 42; -X == 123; - -{ - let x = 999; // local variable 'x' shadows the 'x' in parent block - x == 999; // access to local 'x' -} -x == 42; // the parent block's 'x' is not changed - -is_def_var("x") == true; - -is_def_var("_x") == true; - -is_def_var("y") == false; -``` diff --git a/doc/src/language/while.md b/doc/src/language/while.md deleted file mode 100644 index 5b7a5ac8..00000000 --- a/doc/src/language/while.md +++ /dev/null @@ -1,20 +0,0 @@ -`while` Loop -============ - -{{#include ../links.md}} - -`while` loops follow C syntax. - -Like C, `continue` can be used to skip to the next iteration, by-passing all following statements; -`break` can be used to break out of the loop unconditionally. - -```rust -let x = 10; - -while x > 0 { - x -= 1; - if x < 6 { continue; } // skip to the next iteration - print(x); - if x == 5 { break; } // break out of while loop -} -``` diff --git a/doc/src/links.md b/doc/src/links.md deleted file mode 100644 index c2681d79..00000000 --- a/doc/src/links.md +++ /dev/null @@ -1,147 +0,0 @@ -[features]: {{rootUrl}}/start/features.md -[`unchecked`]: {{rootUrl}}/start/features.md -[`sync`]: {{rootUrl}}/start/features.md -[`no_optimize`]: {{rootUrl}}/start/features.md -[`no_float`]: {{rootUrl}}/start/features.md -[`f32_float`]: {{rootUrl}}/start/features.md -[`only_i32`]: {{rootUrl}}/start/features.md -[`only_i64`]: {{rootUrl}}/start/features.md -[`no_index`]: {{rootUrl}}/start/features.md -[`no_object`]: {{rootUrl}}/start/features.md -[`no_function`]: {{rootUrl}}/start/features.md -[`no_module`]: {{rootUrl}}/start/features.md -[`no_closure`]: {{rootUrl}}/start/features.md -[`no_std`]: {{rootUrl}}/start/features.md -[`no-std`]: {{rootUrl}}/start/features.md -[`metadata`]: {{rootUrl}}/start/features.md -[`internals`]: {{rootUrl}}/start/features.md -[`unicode-xid-ident`]: {{rootUrl}}/start/features.md - -[minimal builds]: {{rootUrl}}/start/builds/minimal.md -[WASM]: {{rootUrl}}/start/builds/wasm.md -[playground]: https://alvinhochun.github.io/rhai-demo - -[`Engine`]: {{rootUrl}}/engine/hello-world.md -[traits]: {{rootUrl}}/rust/traits.md -[`private`]: {{rootUrl}}/engine/call-fn.md -[`call_fn`]: {{rootUrl}}/engine/call-fn.md -[`Func`]: {{rootUrl}}/engine/func.md -[`AST`]: {{rootUrl}}/engine/compile.md -[`eval_expression`]: {{rootUrl}}/engine/expressions.md -[`eval_expression_with_scope`]: {{rootUrl}}/engine/expressions.md -[raw `Engine`]: {{rootUrl}}/engine/raw.md -[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators -[package]: {{rootUrl}}/rust/packages/index.md -[packages]: {{rootUrl}}/rust/packages/index.md -[custom package]: {{rootUrl}}/rust/packages/create.md -[custom packages]: {{rootUrl}}/rust/packages/create.md -[plugin]: {{rootUrl}}/plugins/index.md -[plugins]: {{rootUrl}}/plugins/index.md -[plugin module]: {{rootUrl}}/plugins/module.md -[plugin modules]: {{rootUrl}}/plugins/module.md -[plugin function]: {{rootUrl}}/plugins/function.md -[plugin functions]: {{rootUrl}}/plugins/function.md -[functions metadata]: {{rootUrl}}/engine/metadata/index.md -[`Scope`]: {{rootUrl}}/engine/scope.md -[`serde`]: {{rootUrl}}/rust/serde.md - -[`type_of()`]: {{rootUrl}}/language/type-of.md -[`to_string()`]: {{rootUrl}}/language/values-and-types.md -[`()`]: {{rootUrl}}/language/values-and-types.md -[standard types]: {{rootUrl}}/language/values-and-types.md -[`Dynamic`]: {{rootUrl}}/language/dynamic.md -[`to_int`]: {{rootUrl}}/language/convert.md -[`to_float`]: {{rootUrl}}/language/convert.md -[`parse_int`]: {{rootUrl}}/language/convert.md -[`parse_float`]: {{rootUrl}}/language/convert.md - -[custom type]: {{rootUrl}}/rust/custom.md -[custom types]: {{rootUrl}}/rust/custom.md -[getters/setters]: {{rootUrl}}/rust/getters-setters.md -[indexers]: {{rootUrl}}/rust/indexers.md -[type iterator]: {{rootUrl}}/language/iterator.md -[type iterators]: {{rootUrl}}/language/iterator.md - -[`instant::Instant`]: https://crates.io/crates/instant - -[`print`]: {{rootUrl}}/language/print-debug.md -[`debug`]: {{rootUrl}}/language/print-debug.md - -[keywords]: {{rootUrl}}/appendix/keywords.md -[keyword]: {{rootUrl}}/appendix/keywords.md - -[variable]: {{rootUrl}}/language/variables.md -[variables]: {{rootUrl}}/language/variables.md -[constant]: {{rootUrl}}/language/constants.md -[constants]: {{rootUrl}}/language/constants.md - -[string]: {{rootUrl}}/language/strings-chars.md -[strings]: {{rootUrl}}/language/strings-chars.md -[char]: {{rootUrl}}/language/strings-chars.md - -[array]: {{rootUrl}}/language/arrays.md -[arrays]: {{rootUrl}}/language/arrays.md -[`Array`]: {{rootUrl}}/language/arrays.md - -[`Map`]: {{rootUrl}}/language/object-maps.md -[object map]: {{rootUrl}}/language/object-maps.md -[object maps]: {{rootUrl}}/language/object-maps.md - -[`timestamp`]: {{rootUrl}}/language/timestamps.md -[timestamp]: {{rootUrl}}/language/timestamps.md -[timestamps]: {{rootUrl}}/language/timestamps.md - -[doc-comments]: {{rootUrl}}/language/doc-comments.md -[function]: {{rootUrl}}/language/functions.md -[functions]: {{rootUrl}}/language/functions.md -[function overloading]: {{rootUrl}}/rust/functions.md#function-overloading -[fallible function]: {{rootUrl}}/rust/fallible.md -[fallible functions]: {{rootUrl}}/rust/fallible.md -[`throw`]: {{rootUrl}}/language/throw.md -[exception]: {{rootUrl}}/language/throw.md -[exceptions]: {{rootUrl}}/language/throw.md -[function pointer]: {{rootUrl}}/language/fn-ptr.md -[function pointers]: {{rootUrl}}/language/fn-ptr.md -[currying]: {{rootUrl}}/language/fn-curry.md -[capture]: {{rootUrl}}/language/fn-capture.md -[automatic currying]: {{rootUrl}}/language/fn-closure.md -[closure]: {{rootUrl}}/language/fn-closure.md -[closures]: {{rootUrl}}/language/fn-closure.md -[function namespace]: {{rootUrl}}/language/fn-namespaces.md -[function namespaces]: {{rootUrl}}/language/fn-namespaces.md -[anonymous function]: {{rootUrl}}/language/fn-anon.md -[anonymous functions]: {{rootUrl}}/language/fn-anon.md -[operator overloading]: {{rootUrl}}/rust/operators.md - -[`Module`]: {{rootUrl}}/rust/modules/index.md -[module]: {{rootUrl}}/rust/modules/index.md -[modules]: {{rootUrl}}/rust/modules/index.md -[module resolver]: {{rootUrl}}/rust/modules/resolvers.md -[variable resolver]: {{rootUrl}}/engine/var.md -[`export`]: {{rootUrl}}/language/modules/export.md -[`import`]: {{rootUrl}}/language/modules/import.md - -[`eval`]: {{rootUrl}}/language/eval.md - -[OOP]: {{rootUrl}}/patterns/oop.md -[DSL]: {{rootUrl}}/engine/dsl.md - -[sand-boxed]: {{rootUrl}}/safety/sandbox.md -[maximum statement depth]: {{rootUrl}}/safety/max-stmt-depth.md -[maximum call stack depth]: {{rootUrl}}/safety/max-call-stack.md -[maximum number of operations]: {{rootUrl}}/safety/max-operations.md -[maximum number of modules]: {{rootUrl}}/safety/max-modules.md -[maximum length of strings]: {{rootUrl}}/safety/max-string-size.md -[maximum size of arrays]: {{rootUrl}}/safety/max-array-size.md -[maximum size of object maps]: {{rootUrl}}/safety/max-map-size.md -[progress]: {{rootUrl}}/safety/progress.md - -[script optimization]: {{rootUrl}}/engine/optimize/index.md -[`OptimizationLevel::Full`]: {{rootUrl}}/engine/optimize/optimize-levels.md -[`OptimizationLevel::Simple`]: {{rootUrl}}/engine/optimize/optimize-levels.md -[`OptimizationLevel::None`]: {{rootUrl}}/engine/optimize/optimize-levels.md - -[disable keywords and operators]: {{rootUrl}}/engine/disable.md -[custom operator]: {{rootUrl}}/engine/custom-op.md -[custom operators]: {{rootUrl}}/engine/custom-op.md -[custom syntax]: {{rootUrl}}/engine/custom-syntax.md diff --git a/doc/src/patterns/config.md b/doc/src/patterns/config.md deleted file mode 100644 index 6af3ae10..00000000 --- a/doc/src/patterns/config.md +++ /dev/null @@ -1,163 +0,0 @@ -Loadable Configuration -====================== - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system where settings and configurations are complex and logic-driven. - -* Where said system is too complex to configure via standard configuration file formats such as `JSON`, `TOML` or `YAML`. - -* The system is complex enough to require a full programming language to configure. Essentially _configuration by code_. - -* Yet the configuration must be flexible, late-bound and dynamically loadable, just like a configuration file. - - -Key Concepts ------------- - -* Leverage the loadable [modules] of Rhai. The [`no_module`] feature must not be on. - -* Expose the configuration API. Use separate scripts to configure that API. Dynamically load scripts via the `import` statement. - -* Leverage [function overloading] to simplify the API design. - -* Since Rhai is _sand-boxed_, it cannot mutate the environment. To modify the external configuration object via an API, it must be wrapped in a `RefCell` (or `RwLock`/`Mutex` for [`sync`]) and shared to the [`Engine`]. - - -Implementation --------------- - -### Configuration Type - -```rust -#[derive(Debug, Clone, Default)] -struct Config { - pub id: String; - pub some_field: i64; - pub some_list: Vec; - pub some_map: HashMap; -} -``` - -### Make Shared Object - -```rust -pub type SharedConfig = Rc>; -``` - -Note: Use `Arc>` or `Arc>` when using the [`sync`] feature because the function -must then be `Send + Sync`. - -```rust -let config: SharedConfig = Rc::new(RefCell::new(Default::default())); -``` - -### Register Config API - -The trick to building a Config API is to clone the shared configuration object and -move it into each function registration via a closure. - -Therefore, it is not possible to use a [plugin module] to achieve this, and each function must -be registered one after another. - -```rust -// Notice 'move' is used to move the shared configuration object into the closure. -let cfg = config.clone(); -engine.register_fn("config_set_id", move |id: String| *cfg.borrow_mut().id = id); - -let cfg = config.clone(); -engine.register_fn("config_get_id", move || cfg.borrow().id.clone()); - -let cfg = config.clone(); -engine.register_fn("config_set", move |value: i64| *cfg.borrow_mut().some_field = value); - -// Remember Rhai functions can be overloaded when designing the API. - -let cfg = config.clone(); -engine.register_fn("config_add", move |value: String| - cfg.borrow_mut().some_list.push(value) -); - -let cfg = config.clone(); -engine.register_fn("config_add", move |values: &mut Array| - cfg.borrow_mut().some_list.extend(values.into_iter().map(|v| v.to_string())) -); - -let cfg = config.clone(); -engine.register_fn("config_add", move |key: String, value: bool| - cfg.borrow_mut().some_map.insert(key, value) -); - -let cfg = config.clone(); -engine.register_fn("config_contains", move |value: String| - cfg.borrow().some_list.contains(&value) -); - -let cfg = config.clone(); -engine.register_fn("config_is_set", move |value: String| - cfg.borrow().some_map.get(&value).cloned().unwrap_or(false) -); -``` - -### Configuration Script - -```rust ------------------- -| my_config.rhai | ------------------- - -config_set_id("hello"); - -config_add("foo"); // add to list -config_add("bar", true); // add to map - -if config_contains("hey") || config_is_set("hey") { - config_add("baz", false); // add to map -} -``` - -### Load the Configuration - -```rust -import "my_config"; // run configuration script without creating a module - -let id = config_get_id(); - -id == "hello"; -``` - - -Consider a Custom Syntax ------------------------- - -This is probably one of the few scenarios where a [custom syntax] can be recommended. - -A properly-designed [custom syntax] can make the configuration file clean, simple to write, -easy to understand and quick to modify. - -For example, the above configuration example may be expressed by this custom syntax: - -```rust ------------------- -| my_config.rhai | ------------------- - -// Configure ID -id "hello"; - -// Add to list -list + "foo"; - -// Add to map -map "bar" => true; - -if config contains "hey" || config is_set "hey" { - map "baz" => false; -} -``` - -Notice that `contains` and `is_set` may be implemented as a [custom operator]. diff --git a/doc/src/patterns/control.md b/doc/src/patterns/control.md deleted file mode 100644 index 25d73231..00000000 --- a/doc/src/patterns/control.md +++ /dev/null @@ -1,144 +0,0 @@ -Scriptable Control Layer -======================== - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system provides core functionalities, but no driving logic. - -* The driving logic must be dynamic and hot-loadable. - -* A script is used to drive the system and provide control intelligence. - - -Key Concepts ------------- - -* Expose a Control API. - -* Leverage [function overloading] to simplify the API design. - -* Since Rhai is _[sand-boxed]_, it cannot mutate the environment. To perform external actions via an API, the actual system must be wrapped in a `RefCell` (or `RwLock`/`Mutex` for [`sync`]) and shared to the [`Engine`]. - - -Implementation --------------- - -There are two broad ways for Rhai to control an external system, both of which involve -wrapping the system in a shared, interior-mutated object. - -This is one way which does not involve exposing the data structures of the external system, -but only through exposing an abstract API primarily made up of functions. - -Use this when the API is relatively simple and clean, and the number of functions is small enough. - -For a complex API involving lots of functions, or an API that has a clear object structure, -use the [Singleton Command Object]({{rootUrl}}/patterns/singleton.md) pattern instead. - - -### Functional API - -Assume that a system provides the following functional API: - -```rust -struct EnergizerBunny; - -impl EnergizerBunny { - pub fn new () -> Self { ... } - pub fn go (&mut self) { ... } - pub fn stop (&mut self) { ... } - pub fn is_going (&self) { ... } - pub fn get_speed (&self) -> i64 { ... } - pub fn set_speed (&mut self, speed: i64) { ... } -} -``` - -### Wrap API in Shared Object - -```rust -pub type SharedBunny = Rc>; -``` - -Note: Use `Arc>` or `Arc>` when using the [`sync`] feature because the function -must then be `Send + Sync`. - -```rust -let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new())); -``` - -### Register Control API - -The trick to building a Control API is to clone the shared API object and -move it into each function registration via a closure. - -Therefore, it is not possible to use a [plugin module] to achieve this, and each function must -be registered one after another. - -```rust -// Notice 'move' is used to move the shared API object into the closure. -let b = bunny.clone(); -engine.register_fn("bunny_power", move |on: bool| { - if on { - if b.borrow().is_going() { - println!("Still going..."); - } else { - b.borrow_mut().go(); - } - } else { - if b.borrow().is_going() { - b.borrow_mut().stop(); - } else { - println!("Already out of battery!"); - } - } -}); - -let b = bunny.clone(); -engine.register_fn("bunny_is_going", move || b.borrow().is_going()); - -let b = bunny.clone(); -engine.register_fn("bunny_get_speed", move || - if b.borrow().is_going() { b.borrow().get_speed() } else { 0 } -); - -let b = bunny.clone(); -engine.register_result_fn("bunny_set_speed", move |speed: i64| - if speed <= 0 { - return Err("Speed must be positive!".into()); - } else if speed > 100 { - return Err("Bunny will be going too fast!".into()); - } - - if b.borrow().is_going() { - b.borrow_mut().set_speed(speed) - } else { - return Err("Bunny is not yet going!".into()); - } - - Ok(Dynamic::UNIT) -); -``` - -### Use the API - -```rust -if !bunny_is_going() { bunny_power(true); } - -if bunny_get_speed() > 50 { bunny_set_speed(50); } -``` - - -Caveat ------- - -Although this usage pattern appears a perfect fit for _game_ logic, avoid writing the -_entire game_ in Rhai. Performance will not be acceptable. - -Implement as much functionalities of the game engine in Rust as possible. -Rhai integrates well with Rust so this is usually not a hinderance. - -Lift as much out of Rhai as possible. -Use Rhai only for the logic that _must_ be dynamic or hot-loadable. diff --git a/doc/src/patterns/dynamic-const.md b/doc/src/patterns/dynamic-const.md deleted file mode 100644 index e3fe7c06..00000000 --- a/doc/src/patterns/dynamic-const.md +++ /dev/null @@ -1,56 +0,0 @@ -Dynamic Constants Provider -========================= - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system has a _large_ number of constants, but only a minor set will be used by any script. - -* The system constants are expensive to load. - -* The system constants set is too massive to push into a custom [`Scope`]. - -* The values of system constants are volatile and call-dependent. - - -Key Concepts ------------- - -* Use a [variable resolver] to intercept variable access. - -* Only load a variable when it is being used. - -* Perform a lookup based on variable name, and provide the correct data value. - -* May even perform back-end network access or look up the latest value from a database. - - -Implementation --------------- - -```rust -let mut engine = Engine::new(); - -// Create shared data provider. -// Assume that SystemValuesProvider::get(&str) -> Option gets a value. -let provider = Arc::new(SystemValuesProvider::new()); - -// Clone the shared provider -let db = provider.clone(); - -// Register a variable resolver. -// Move the shared provider into the closure. -engine.on_var(move |name, _, _, _| Ok(db.get(name).map(Dynamic::from))); -``` - - -Values are Constants --------------------- - -All values provided by a [variable resolver] are _constants_ due to their dynamic nature. -They cannot be assigned to. - -In order to change values in an external system, register a dedicated API for that purpose. diff --git a/doc/src/patterns/enums.md b/doc/src/patterns/enums.md deleted file mode 100644 index d76e62f9..00000000 --- a/doc/src/patterns/enums.md +++ /dev/null @@ -1,237 +0,0 @@ -Working With Rust Enums -======================= - -{{#include ../links.md}} - -Enums in Rust are typically used with _pattern matching_. Rhai is dynamic, so although -it integrates with Rust enum variants just fine (treated transparently as [custom types]), -it is impossible (short of registering a complete API) to distinguish between individual -enum variants or to extract internal data from them. - - -Simulate an Enum API --------------------- - -A [plugin module] is extremely handy in creating an entire API for a custom enum type. - -```rust -use rhai::{Engine, Dynamic, EvalAltResult}; -use rhai::plugin::*; - -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -enum MyEnum { - Foo, - Bar(i64), - Baz(String, bool) -} - -// Create a plugin module with functions constructing the 'MyEnum' variants -#[export_module] -mod MyEnumModule { - // Constructors for 'MyEnum' variants - pub const Foo: &MyEnum = MyEnum::Foo; - pub fn Bar(value: i64) -> MyEnum { - MyEnum::Bar(value) - } - pub fn Baz(val1: String, val2: bool) -> MyEnum { - MyEnum::Baz(val1, val2) - } - // Access to fields - #[rhai_fn(get = "enum_type")] - pub fn get_type(a: &mut MyEnum) -> String { - match a { - MyEnum::Foo => "Foo".to_string(), - MyEnum::Bar(_) => "Bar".to_string(), - MyEnum::Baz(_, _) => "Baz".to_string() - } - } - #[rhai_fn(get = "field_0")] - pub fn get_field_0(a: &mut MyEnum) -> Dynamic { - match a { - MyEnum::Foo => Dynamic::UNIT, - MyEnum::Bar(x) => Dynamic::from(x), - MyEnum::Baz(x, _) => Dynamic::from(x) - } - } - #[rhai_fn(get = "field_1")] - pub fn get_field_1(a: &mut MyEnum) -> Dynamic { - match a { - MyEnum::Foo | MyEnum::Bar(_) => Dynamic::UNIT, - MyEnum::Baz(_, x) => Dynamic::from(x) - } - } - // Printing - #[rhai(global, name = "to_string", name = "print", name = "to_debug", name = "debug")] - pub fn to_string(a: &mut MyEnum) -> String { - format!("{:?}", a)) - } - #[rhai_fn(global, name = "+")] - pub fn add_to_str(s: &str, a: MyEnum) -> String { - format!("{}{:?}", s, a)) - } - #[rhai_fn(global, name = "+")] - pub fn add_str(a: &mut MyEnum, s: &str) -> String { - format!("{:?}", a).push_str(s)) - } - #[rhai_fn(global, name = "+=")] - pub fn append_to_str(s: &mut ImmutableString, a: MyEnum) -> String { - s += a.to_string()) - } - // '==' and '!=' operators - #[rhai_fn(global, name = "==")] - pub fn eq(a: &mut MyEnum, b: MyEnum) -> bool { - a == &b - } - #[rhai_fn(global, name = "!=")] - pub fn neq(a: &mut MyEnum, b: MyEnum) -> bool { - a != &b - } - // Array functions - #[rhai_fn(global, name = "push")] - pub fn append_to_array(list: &mut Array, item: MyEnum) { - list.push(Dynamic::from(item))); - } - #[rhai_fn(global, name = "+=")] - pub fn append_to_array_op(list: &mut Array, item: MyEnum) { - list.push(Dynamic::from(item))); - } - #[rhai_fn(global, name = "insert")] - pub fn insert_to_array(list: &mut Array, position: i64, item: MyEnum) { - if position <= 0 { - list.insert(0, Dynamic::from(item)); - } else if (position as usize) >= list.len() - 1 { - list.push(item); - } else { - list.insert(position as usize, Dynamic::from(item)); - } - } - #[rhai_fn(global, name = "pad")] - pub fn pad_array(list: &mut Array, len: i64, item: MyEnum) { - if len as usize > list.len() { list.resize(len as usize, item); } - } -} - -let mut engine = Engine::new(); - -// Load the module as the module namespace "MyEnum" -engine - .register_type_with_name::("MyEnum") - .register_static_module("MyEnum", exported_module!(MyEnumModule).into()); -``` - -With this API in place, working with enums feels almost the same as in Rust: - -```rust -let x = MyEnum::Foo; - -let y = MyEnum::Bar(42); - -let z = MyEnum::Baz("hello", true); - -x == MyEnum::Foo; - -y != MyEnum::Bar(0); - -// Detect enum types - -x.enum_type == "Foo"; - -y.enum_type == "Bar"; - -z.enum_type == "Baz"; - -// Extract enum fields - -y.field_0 == 42; - -y.field_1 == (); - -z.field_0 == "hello"; - -z.field_1 == true; -``` - -Since enums are internally treated as [custom types], they are not _literals_ and cannot be -used as a match case in `switch` expressions. This is quite a limitation because the equivalent -`match` statement is commonly used in Rust to work with enums and bind variables to -variant-internal data. - -It is possible, however, to `switch` through enum variants based on their types: - -```c -switch x.enum_type { - "Foo" => ..., - "Bar" => { - let value = foo.field_0; - ... - } - "Baz" => { - let val1 = foo.field_0; - let val2 = foo.field_1; - ... - } -} -``` - - -Use `switch` Through Arrays ---------------------------- - -Another way to work with Rust enums in a `switch` expression is through exposing the internal data -(or at least those that act as effective _discriminants_) of each enum variant as a variable-length -[array], usually with the name of the variant as the first item for convenience: - -```rust -use rhai::Array; - -engine.register_get("enum_data", |x: &mut Enum| { - match x { - Enum::Foo => vec![ "Foo".into() ] as Array, - - // Say, skip the data field because it is not - // used as a discriminant - Enum::Bar(value) => vec![ "Bar".into() ] as Array, - - // Say, all fields act as discriminants - Enum::Baz(val1, val2) => vec![ - "Baz".into(), val1.clone().into(), (*val2).into() - ] as Array - } -}); -``` - -Then it is a simple matter to match an enum via the `switch` expression: - -```c -// Assume 'value' = 'MyEnum::Baz("hello", true)' -// 'enum_data' creates a variable-length array with 'MyEnum' data -let x = switch value.enum_data { - ["Foo"] => 1, - ["Bar"] => value.field_1, - ["Baz", "hello", false] => 4, - ["Baz", "hello", true] => 5, - _ => 9 -}; - -x == 5; - -// Which is essentially the same as: -let x = switch [value.type, value.field_0, value.field_1] { - ["Foo", (), ()] => 1, - ["Bar", 42, ()] => 42, - ["Bar", 123, ()] => 123, - : - ["Baz", "hello", false] => 4, - ["Baz", "hello", true] => 5, - _ => 9 -} -``` - -Usually, a helper method returns an array of values that can uniquely determine -the switch case based on actual usage requirements – which means that it probably -skips fields that contain data instead of discriminants. - -Then `switch` is used to very quickly match through a large number of array shapes -and jump to the appropriate case implementation. - -Data fields can then be extracted from the enum independently. diff --git a/doc/src/patterns/events.md b/doc/src/patterns/events.md deleted file mode 100644 index 24574612..00000000 --- a/doc/src/patterns/events.md +++ /dev/null @@ -1,202 +0,0 @@ -Scriptable Event Handler with State -================================== - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system sends _events_ that must be handled. - -* Flexibility in event handling must be provided, through user-side scripting. - -* State must be kept between invocations of event handlers. - -* Default implementations of event handlers can be provided. - - -Key Concepts ------------- - -* An _event handler_ object is declared that holds the following items: - * [`Engine`] with registered functions serving as an API, - * [`AST`] of the user script, - * a [`Scope`] containing state. - -* Upon an event, the appropriate event handler function in the script is called via [`Engine::call_fn`][`call_fn`]. - -* Optionally, trap the `EvalAltResult::ErrorFunctionNotFound` error to provide a default implementation. - - -Implementation --------------- - -### Declare Handler Object - -In most cases, it would be simpler to store an [`Engine`] instance together with the handler object -because it only requires registering all API functions only once. - -In rare cases where handlers are created and destroyed in a tight loop, a new [`Engine`] instance -can be created for each event. See [_One Engine Instance Per Call_](parallel.md) for more details. - -```rust -use rhai::{Engine, Scope, AST, EvalAltResult}; - -// Event handler -struct Handler { - // Scripting engine - pub engine: Engine, - // Use a custom 'Scope' to keep stored state - pub scope: Scope<'static>, - // Program script - pub ast: AST -} -``` - -### Register API for Any Custom Type - -[Custom types] are often used to hold state. The easiest way to register an entire API is via a [plugin module]. - -```rust -use rhai::plugin::*; - -// A custom type to a hold state value. -#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] -pub struct SomeType { - data: i64; -} - -#[export_module] -mod SomeTypeAPI { - #[rhai_fn(global)] - pub func1(obj: &mut SomeType) -> bool { ... } - #[rhai_fn(global)] - pub func2(obj: &mut SomeType) -> bool { ... } - pub process(data: i64) -> i64 { ... } - #[rhai_fn(get = "value")] - pub get_value(obj: &mut SomeType) -> i64 { obj.data } - #[rhai_fn(set = "value")] - pub set_value(obj: &mut SomeType, value: i64) { obj.data = value; } -} -``` - -### Initialize Handler Object - -Steps to initialize the event handler: - -1. Register an API with the [`Engine`], -2. Create a custom [`Scope`] to serve as the stored state, -3. Add default state variables into the custom [`Scope`], -4. Get the handler script and [compile][`AST`] it, -5. Store the compiled [`AST`] for future evaluations, -6. Run the [`AST`] to initialize event handler state variables. - -```rust -impl Handler { - pub new(path: impl Into) -> Self { - let mut engine = Engine::new(); - - // Register custom types and API's - engine - .register_type_with_name::("SomeType") - .register_global_module(exported_module!(SomeTypeAPI)); - - // Create a custom 'Scope' to hold state - let mut scope = Scope::new(); - - // Add initialized state into the custom 'Scope' - scope.push("state1", false); - scope.push("state2", SomeType::new(42)); - - // Compile the handler script. - // In a real application you'd be handling errors... - let ast = engine.compile_file(path).unwrap(); - - // Evaluate the script to initialize it and other state variables. - // In a real application you'd again be handling errors... - engine.consume_ast_with_scope(&mut scope, &ast).unwrap(); - - // The event handler is essentially these three items: - Handler { engine, scope, ast } - } -} -``` - -### Hook up events - -There is usually an interface or trait that gets called when an event comes from the system. - -Mapping an event from the system into a scripted handler is straight-forward: - -```rust -impl Handler { - // Say there are three events: 'start', 'end', 'update'. - // In a real application you'd be handling errors... - pub fn on_event(&mut self, event_name: &str, event_data: i64) -> Result<(), Error> { - let engine = &self.engine; - let scope = &mut self.scope; - let ast = &self.ast; - - match event_name { - // The 'start' event maps to function 'start'. - // In a real application you'd be handling errors... - "start" => engine.call_fn(scope, ast, "start", (event_data,))?, - - // The 'end' event maps to function 'end'. - // In a real application you'd be handling errors... - "end" => engine.call_fn(scope, ast, "end", (event_data,))?, - - // The 'update' event maps to function 'update'. - // This event provides a default implementation when the scripted function - // is not found. - "update" => - engine.call_fn(scope, ast, "update", (event_data,)) - .or_else(|err| match *err { - EvalAltResult::ErrorFunctionNotFound(fn_name, _) if fn_name == "update" => { - // Default implementation of 'update' event handler - self.scope.set_value("state2", SomeType::new(42)); - // Turn function-not-found into a success - Ok(Dynamic::UNIT) - } - _ => Err(err.into()) - })? - } - } -} -``` - -### Sample Handler Script - -Because the stored state is kept in a custom [`Scope`], it is possible for all functions defined -in the handler script to access and modify these state variables. - -The API registered with the [`Engine`] can be also used throughout the script. - -```rust -fn start(data) { - if state1 { - throw "Already started!"; - } - if state2.func1() || state2.func2() { - throw "Conditions not yet ready to start!"; - } - state1 = true; - state2.value = data; -} - -fn end(data) { - if !state1 { - throw "Not yet started!"; - } - if state2.func1() || state2.func2() { - throw "Conditions not yet ready to start!"; - } - state1 = false; - state2.value = data; -} - -fn update(data) { - state2.value += process(data); -} -``` diff --git a/doc/src/patterns/index.md b/doc/src/patterns/index.md deleted file mode 100644 index fb651ae8..00000000 --- a/doc/src/patterns/index.md +++ /dev/null @@ -1,7 +0,0 @@ -Usage Patterns -============== - -{{#include ../links.md}} - - -Leverage the full power and flexibility of Rhai in different scenarios. diff --git a/doc/src/patterns/multi-layer.md b/doc/src/patterns/multi-layer.md deleted file mode 100644 index 9092ca82..00000000 --- a/doc/src/patterns/multi-layer.md +++ /dev/null @@ -1,117 +0,0 @@ -Multi-Layer Functions -===================== - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system is divided into separate _layers_, each providing logic in terms of scripted [functions]. - -* A lower layer provides _default implementations_ of certain functions. - -* Higher layers each provide progressively more specific implementations of the same functions. - -* A more specific function, if defined in a higher layer, always overrides the implementation in a lower layer. - -* This is akin to object-oriented programming but with functions. - -* This type of system is extremely convenient for dynamic business rules configuration, setting corporate-wide - policies, granting permissions for specific roles etc. where specific, local rules need to override - corporate-wide defaults. - - -Key Concepts ------------- - -* Each layer is a separate script. - -* The lowest layer script is compiled into a base [`AST`]. - -* Higher layer scripts are also compiled into [`AST`] and _combined_ into the base using `AST::combine` - (or the `+=` operator), overriding any existing functions. - - -Examples --------- - -Assume the following four scripts: - -```rust ----------------- -| default.rhai | ----------------- - -// Default implementation of 'foo'. -fn foo(x) { x + 1 } - -// Default implementation of 'bar'. -fn bar(x, y) { x + y } - -// Default implementation of 'no_touch'. -fn no_touch() { throw "do not touch me!"; } - - ---------------- -| lowest.rhai | ---------------- - -// Specific implementation of 'foo'. -fn foo(x) { x * 2 } - -// New implementation for this layer. -fn baz() { print("hello!"); } - - ---------------- -| middle.rhai | ---------------- - -// Specific implementation of 'bar'. -fn bar(x, y) { x - y } - -// Specific implementation of 'baz'. -fn baz() { print("hey!"); } - - ----------------- -| highest.rhai | ----------------- - -// Specific implementation of 'foo'. -fn foo(x) { x + 42 } -``` - -Load and combine them sequentially: - -```rust -let engine = Engine::new(); - -// Compile the baseline default implementations. -let mut ast = engine.compile_file("default.rhai".into())?; - -// Combine the first layer. -let lowest = engine.compile_file("lowest.rhai".into())?; -ast += lowest; - -// Combine the second layer. -let middle = engine.compile_file("middle.rhai".into())?; -ast += lowest; - -// Combine the third layer. -let highest = engine.compile_file("highest.rhai".into())?; -ast += lowest; - -// Now, 'ast' contains the following functions: -// -// fn no_touch() { // from 'default.rhai' -// throw "do not touch me!"; -// } -// fn foo(x) { x + 42 } // from 'highest.rhai' -// fn bar(x, y) { x - y } // from 'middle.rhai' -// fn baz() { print("hey!"); } // from 'middle.rhai' -``` - -Unfortunately, there is no `super` call that calls the base implementation -(i.e. no way for a higher-layer function to call an equivalent lower-layer function). diff --git a/doc/src/patterns/multiple.md b/doc/src/patterns/multiple.md deleted file mode 100644 index dad53501..00000000 --- a/doc/src/patterns/multiple.md +++ /dev/null @@ -1,89 +0,0 @@ -Multiple Instantiation -====================== - -{{#include ../links.md}} - - -Background ----------- - -Rhai's [features] are not strictly additive. This is easily deduced from the [`no_std`] feature -which prepares the crate for `no-std` builds. Obviously, turning on this feature has a material -impact on how Rhai behaves. - -Many crates resolve this by going the opposite direction: build for `no-std` in default, -but add a `std` feature, included by default, which builds for the `stdlib`. - - -Rhai Language Features Are Not Additive --------------------------------------- - -Rhai, however, is more complex. Language features cannot be easily made _additive_. - -That is because the _lack_ of a language feature is a feature by itself. - -For example, by including [`no_float`], a project sets the Rhai language to ignore floating-point math. -Floating-point numbers do not even parse under this case and will generate syntax errors. -Assume that the project expects this behavior (why? perhaps integers are all that make sense -within the project domain). - -Now, assume that a dependent crate also depends on Rhai. Under such circumstances, -unless _exact_ versioning is used and the dependent crate depends on a _different_ version -of Rhai, Cargo automatically _merges_ both dependencies, with the [`no_float`] feature turned on -because Cargo features are _additive_. - -This will break the dependent crate, which does not by itself specify [`no_float`] -and expects floating-point numbers and math to work normally. - -There is no way out of this dilemma. Reversing the [features] set with a `float` feature -causes the project to break because floating-point numbers are not rejected as expected. - - -Multiple Instantiations of Rhai Within The Same Project ------------------------------------------------------- - -The trick is to differentiate between multiple identical copies of Rhai, each having -a different [features] set, by their _sources_: - -* Different versions from [`crates.io`](https://crates.io/crates/rhai/) – The official crate. - -* Different releases from [`GitHub`](https://github.com/rhaiscript/rhai) – Crate source on GitHub. - -* Forked copy of [https://github.com/rhaiscript/rhai](https://github.com/rhaiscript/rhai) on GitHub. - -* Local copy of [https://github.com/rhaiscript/rhai](https://github.com/rhaiscript/rhai) downloaded form GitHub. - -Use the following configuration in `Cargo.toml` to pull in multiple copies of Rhai within the same project: - -```toml -[dependencies] -rhai = { version = "{{version}}", features = [ "no_float" ] } -rhai_github = { git = "https://github.com/rhaiscript/rhai", features = [ "unchecked" ] } -rhai_my_github = { git = "https://github.com/my_github/rhai", branch = "variation1", features = [ "serde", "no_closure" ] } -rhai_local = { path = "../rhai_copy" } -``` - -The example above creates four different modules: `rhai`, `rhai_github`, `rhai_my_github` and -`rhai_local`, each referring to a different Rhai copy with the appropriate [features] set. - -Only one crate of any particular version can be used from each source, because Cargo merges -all candidate cases within the same source, adding all [features] together. - -If more than four different instantiations of Rhai is necessary (why?), create more local repositories -or GitHub forks or branches. - - -Caveat – No Way To Avoid Dependency Conflicts --------------------------------------------------- - -Unfortunately, pulling in Rhai from different sources do not resolve the problem of -[features] conflict between dependencies. Even overriding `crates.io` via the `[patch]` manifest -section doesn't work – all dependencies will eventually find the only one copy. - -What is necessary – multiple copies of Rhai, one for each dependent crate that requires it, -together with their _unique_ [features] set intact. In other words, turning off Cargo's -crate merging feature _just for Rhai_. - -Unfortunately, as of this writing, there is no known method to achieve it. - -Therefore, moral of the story: avoid pulling in multiple crates that depend on Rhai. diff --git a/doc/src/patterns/oop.md b/doc/src/patterns/oop.md deleted file mode 100644 index 7b225c8c..00000000 --- a/doc/src/patterns/oop.md +++ /dev/null @@ -1,109 +0,0 @@ -Object-Oriented Programming (OOP) -================================ - -{{#include ../links.md}} - -Rhai does not have _objects_ per se, but it is possible to _simulate_ object-oriented programming. - - -Use Object Maps to Simulate OOP ------------------------------- - -Rhai's [object maps] has [special support for OOP]({{rootUrl}}/language/object-maps-oop.md). - -| Rhai concept | Maps to OOP | -| ----------------------------------------------------- | :---------: | -| [Object maps] | objects | -| [Object map] properties holding values | properties | -| [Object map] properties that hold [function pointers] | methods | - -When a property of an [object map] is called like a method function, and if it happens to hold -a valid [function pointer] (perhaps defined via an [anonymous function] or more commonly as a [closure]), -then the call will be dispatched to the actual function with `this` binding to the [object map] itself. - - -Use Closures to Define Methods ------------------------------ - -[Anonymous functions] or [closures] defined as values for [object map] properties take on -a syntactic shape which resembles very closely that of class methods in an OOP language. - -Closures also _[capture][automatic currying]_ variables from the defining environment, which is a very -common language feature. Capturing is accomplished via a feature called _[automatic currying]_ and -can be turned off via the [`no_closure`] feature. - - -Examples --------- - -```rust -let factor = 1; - -// Define the object -let obj = #{ - data: 0, // object field - increment: |x| this.data += x, // 'this' binds to 'obj' - update: |x| this.data = x * factor, // 'this' binds to 'obj', 'factor' is captured - action: || print(this.data) // 'this' binds to 'obj' - }; - -// Use the object -obj.increment(1); -obj.action(); // prints 1 - -obj.update(42); -obj.action(); // prints 42 - -factor = 2; - -obj.update(42); -obj.action(); // prints 84 -``` - - -Simulating Inheritance With Mixin --------------------------------- - -The `fill_with` method of [object maps] can be conveniently used to _polyfill_ default -method implementations from a _base class_, as per OOP lingo. - -Do not use the `mixin` method because it _overwrites_ existing fields. - -```rust -// Define base class -let BaseClass = #{ - factor: 1, - data: 42, - - get_data: || this.data * 2, - update: |x| this.data += x * this.factor -}; - -let obj = #{ - // Override base class field - factor: 100, - - // Override base class method - // Notice that the base class can also be accessed, if in scope - get_data: || this.call(BaseClass.get_data) * 999, -} - -// Polyfill missing fields/methods -obj.fill_with(BaseClass); - -// By this point, 'obj' has the following: -// -// #{ -// factor: 100 -// data: 42, -// get_data: || this.call(BaseClass.get_data) * 999, -// update: |x| this.data += x * this.factor -// } - -// obj.get_data() => (this.data (42) * 2) * 999 -obj.get_data() == 83916; - -obj.update(1); - -obj.data == 142 -``` diff --git a/doc/src/patterns/parallel.md b/doc/src/patterns/parallel.md deleted file mode 100644 index 3db89b3f..00000000 --- a/doc/src/patterns/parallel.md +++ /dev/null @@ -1,75 +0,0 @@ -One Engine Instance Per Call -=========================== - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system where scripts are called a _lot_, in tight loops or in parallel. - -* Keeping a global [`Engine`] instance is sub-optimal due to contention and locking. - -* Scripts need to be executed independently from each other, perhaps concurrently. - -* Scripts are used to [create Rust closure][`Func`] that are stored and may be called at any time, perhaps concurrently. - In this case, the [`Engine`] instance is usually moved into the closure itself. - - -Key Concepts ------------- - -* Create a single instance of each standard [package] required. - To duplicate `Engine::new`, create a [`StandardPackage`]({{rootUrl}}/rust/packages/builtin.md). - -* Gather up all common custom functions into a [custom package]. - -* Store a global `AST` for use with all engines. - -* Always use `Engine::new_raw` to create a [raw `Engine`], instead of `Engine::new` which is _much_ more expensive. - A [raw `Engine`] is _extremely_ cheap to create. - - Registering the [`StandardPackage`]({{rootUrl}}/rust/packages/builtin.md) into a [raw `Engine`] via - `Engine::register_global_module` is essentially the same as `Engine::new`. - - However, because packages are shared, using existing package is _much cheaper_ than - registering all the functions one by one. - -* Register the required packages with the [raw `Engine`] via `Engine::register_global_module`, - using `Package::as_shared_module` to obtain a shared [module]. - - -Examples --------- - -```rust -use rhai::packages::{Package, StandardPackage}; - -let ast = /* ... some AST ... */; -let std_pkg = StandardPackage::new(); -let custom_pkg = MyCustomPackage::new(); - -let make_call = |x: i64| -> Result<(), Box> { - // Create a raw Engine - extremely cheap - let mut engine = Engine::new_raw(); - - // Register packages as global modules - cheap - engine.register_global_module(std_pkg.as_shared_module()); - engine.register_global_module(custom_pkg.as_shared_module()); - - // Create custom scope - cheap - let mut scope = Scope::new(); - - // Push variable into scope - relatively cheap - scope.push("x", x); - - // Evaluate script. - engine.consume_ast_with_scope(&mut scope, &ast) -}; - -// The following loop creates 10,000 Engine instances! -for x in 0..10_000 { - make_call(x)?; -} -``` diff --git a/doc/src/patterns/singleton.md b/doc/src/patterns/singleton.md deleted file mode 100644 index 97b7d221..00000000 --- a/doc/src/patterns/singleton.md +++ /dev/null @@ -1,175 +0,0 @@ -Singleton Command Object -======================= - -{{#include ../links.md}} - - -Usage Scenario --------------- - -* A system provides core functionalities, but no driving logic. - -* The driving logic must be dynamic and hot-loadable. - -* A script is used to drive the system and provide control intelligence. - -* The API is multiplexed, meaning that it can act on multiple system-provided entities, or - -* The API lends itself readily to an object-oriented (OO) representation. - - -Key Concepts ------------- - -* Expose a Command type with an API. The [`no_object`] feature must not be on. - -* Leverage [function overloading] to simplify the API design. - -* Since Rhai is _[sand-boxed]_, it cannot mutate the environment. To perform external actions via an API, the command object type must be wrapped in a `RefCell` (or `RwLock`/`Mutex` for [`sync`]) and shared to the [`Engine`]. - -* Load each command object into a custom [`Scope`] as constant variables. - -* Control each command object in script via the constants. - - -Implementation --------------- - -There are two broad ways for Rhai to control an external system, both of which involve -wrapping the system in a shared, interior-mutated object. - -This is the other way which involves directly exposing the data structures of the external system -as a name singleton object in the scripting space. - -Use this when the API is complex but has a clear object structure. - -For a relatively simple API that is action-based and not object-based, -use the [Control Layer]({{rootUrl}}/patterns/control.md) pattern instead. - - -### Functional API - -Assume the following command object type: - -```rust -struct EnergizerBunny { ... } - -impl EnergizerBunny { - pub fn new () -> Self { ... } - pub fn go (&mut self) { ... } - pub fn stop (&mut self) { ... } - pub fn is_going (&self) -> bol { ... } - pub fn get_speed (&self) -> i64 { ... } - pub fn set_speed (&mut self, speed: i64) { ... } - pub fn turn (&mut self, left_turn: bool) { ... } -} -``` - -### Wrap Command Object Type as Shared - -```rust -pub type SharedBunny = Rc>; -``` - -Note: Use `Arc>` or `Arc>` when using the [`sync`] feature because the function -must then be `Send + Sync`. - -### Register the Custom Type - -```rust -engine.register_type_with_name::("EnergizerBunny"); -``` - -### Develop a Plugin with Methods and Getters/Setters - -The easiest way to develop a complete set of API for a [custom type] is via a [plugin module]. - -```rust -use rhai::plugin::*; - -#[export_module] -pub mod bunny_api { - pub const MAX_SPEED: i64 = 100; - - #[rhai_fn(get = "power")] - pub fn get_power(bunny: &mut SharedBunny) -> bool { - bunny.borrow().is_going() - } - #[rhai_fn(set = "power")] - pub fn set_power(bunny: &mut SharedBunny, on: bool) { - if on { - if bunny.borrow().is_going() { - println!("Still going..."); - } else { - bunny.borrow_mut().go(); - } - } else { - if bunny.borrow().is_going() { - bunny.borrow_mut().stop(); - } else { - println!("Already out of battery!"); - } - } - } - #[rhai_fn(get = "speed")] - pub fn get_speed(bunny: &mut SharedBunny) -> i64 { - if bunny.borrow().is_going() { - bunny.borrow().get_speed() - } else { - 0 - } - } - #[rhai_fn(set = "speed", return_raw)] - pub fn set_speed(bunny: &mut SharedBunny, speed: i64) - -> Result> - { - if speed <= 0 { - Err("Speed must be positive!".into()) - } else if speed > MAX_SPEED { - Err("Bunny will be going too fast!".into()) - } else if !bunny.borrow().is_going() { - Err("Bunny is not yet going!".into()) - } else { - b.borrow_mut().set_speed(speed); - Ok(Dynamic::UNIT) - } - } - pub fn turn_left(bunny: &mut SharedBunny) { - if bunny.borrow().is_going() { - bunny.borrow_mut().turn(true); - } - } - pub fn turn_right(bunny: &mut SharedBunny) { - if bunny.borrow().is_going() { - bunny.borrow_mut().turn(false); - } - } -} - -engine.register_global_module(exported_module!(bunny_api).into()); -``` - -### Push Constant Command Object into Custom Scope - -```rust -let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new())); - -let mut scope = Scope::new(); - -// Add the command object into a custom Scope. -scope.push_constant("Bunny", bunny.clone()); - -engine.consume_with_scope(&mut scope, script)?; -``` - -### Use the Command API in Script - -```rust -// Access the command object via constant variable 'Bunny'. - -if !Bunny.power { Bunny.power = true; } - -if Bunny.speed > 50 { Bunny.speed = 50; } - -Bunny.turn_left(); -``` diff --git a/doc/src/plugins/function.md b/doc/src/plugins/function.md deleted file mode 100644 index 8f7b3f46..00000000 --- a/doc/src/plugins/function.md +++ /dev/null @@ -1,156 +0,0 @@ -Export a Rust Function to Rhai -============================= - -{{#include ../links.md}} - - -Sometimes only a few ad hoc functions are required and it is simpler to register -individual functions instead of a full-blown [plugin module]. - - -Macros ------- - -| Macro | Signature | Description | -| ------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | -| `#[export_fn]` | apply to rust function defined in a Rust module | exports the function | -| `register_exported_fn!` | `register_exported_fn!(&mut `_engine_`, "`_name_`", `_function_`)` | registers the function into an [`Engine`] under a specific name | -| `set_exported_fn!` | `set_exported_fn!(&mut `_module_`, "`_name_`", `_function_`)` | registers the function into a [`Module`] under a specific name | -| `set_exported_global_fn!` | `set_exported_global_fn!(&mut `_module_`, "`_name_`", `_function_`)` | registers the function into a [`Module`] under a specific name, exposing it to the global namespace | - - -`#[export_fn]` and `register_exported_fn!` ------------------------------------------ - -Apply `#[export_fn]` onto a function defined at _module level_ to convert it into a Rhai plugin function. - -The function cannot be nested inside another function – it can only be defined directly under a module. - -To register the plugin function, simply call `register_exported_fn!`. The name of the function can be -any text string, so it is possible to register _overloaded_ functions as well as operators. - -```rust -use rhai::plugin::*; // import macros - -#[export_fn] -fn increment(num: &mut i64) { - *num += 1; -} - -fn main() { - let mut engine = Engine::new(); - - // 'register_exported_fn!' registers the function as 'inc' with the Engine. - register_exported_fn!(engine, "inc", increment); -} -``` - - -Fallible Functions ------------------- - -To register [fallible functions] (i.e. functions that may return errors), apply the -`#[rhai_fn(return_raw)]` attribute on plugin functions that return `Result>`. - -A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does not -have the appropriate return type. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_fn] -#[rhai_fn(return_raw)] -pub fn double_and_divide(x: i64, y: i64) -> Result> { - if y == 0 { - Err("Division by zero!".into()) - } else { - let result = (x * 2) / y; - Ok(result.into()) - } -} - -fn main() { - let mut engine = Engine::new(); - - // Overloads the operator '+' with the Engine. - register_exported_fn!(engine, "+", double_and_divide); -} -``` - - -`NativeCallContext` Parameter ----------------------------- - -If the _first_ parameter of a function is of type `rhai::NativeCallContext`, then it is treated -specially by the plugins system. - -`NativeCallContext` is a type that encapsulates the current _native call context_ and exposes the following: - -| Field | Type | Description | -| ------------------- | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. | -| `source()` | `Option<&str>` | reference to the current source, if any | -| `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | - -This first parameter, if exists, will be stripped before all other processing. It is _virtual_. -Most importantly, it does _not_ count as a parameter to the function and there is no need to provide -this argument when calling the function in Rhai. - -The native call context can be used to call a [function pointer] or [closure] that has been passed -as a parameter to the function, thereby implementing a _callback_: - -```rust -use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult}; -use rhai::plugin::*; // a "prelude" import for macros - -#[export_fn] -#[rhai_fn(return_raw)] -pub fn greet(context: NativeCallContext, callback: FnPtr) - -> Result> -{ - // Call the callback closure with the current context - // to obtain the name to greet! - let name = callback.call_dynamic(context, None, [])?; - Ok(format!("hello, {}!", name).into()) -} -``` - -The native call context is also useful in another scenario: protecting a function from malicious scripts. - -```rust -use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; -use rhai::plugin::*; // a "prelude" import for macros - -// This function builds an array of arbitrary size, but is protected -// against attacks by first checking with the allowed limit set -// into the 'Engine'. -#[export_fn] -#[rhai_fn(return_raw)] -pub fn grow(context: NativeCallContext, size: i64) - -> Result> -{ - // Make sure the function does not generate a - // data structure larger than the allowed limit - // for the Engine! - if size as usize > context.engine().max_array_size() - { - return EvalAltResult::ErrorDataTooLarge( - "Size to grow".to_string(), - context.engine().max_array_size(), - size as usize, - Position::NONE, - ).into(); - } - - let array = Array::new(); - - for x in 0..size { - array.push(x.into()); - } - - OK(array.into()) -} -``` diff --git a/doc/src/plugins/index.md b/doc/src/plugins/index.md deleted file mode 100644 index 1e3f3cc9..00000000 --- a/doc/src/plugins/index.md +++ /dev/null @@ -1,13 +0,0 @@ -Plugins -======= - -{{#include ../links.md}} - -Rhai contains a robust _plugin_ system that greatly simplifies registration of custom -functionality. - -Instead of using the large `Engine::register_XXX` API or the parallel `Module::set_fn_XXX` API, -a _plugin_ simplifies the work of creating and registering new functionality in an [`Engine`]. - -Plugins are processed via a set of procedural macros under the `rhai::plugin` module. These -allow registering Rust functions directly in the Engine, or adding Rust modules as packages. diff --git a/doc/src/plugins/module.md b/doc/src/plugins/module.md deleted file mode 100644 index c147809f..00000000 --- a/doc/src/plugins/module.md +++ /dev/null @@ -1,507 +0,0 @@ -Export a Rust Module to Rhai -============================ - -{{#include ../links.md}} - - -Prelude -------- - -When using the plugins system, the entire `rhai::plugin` module must be imported as a prelude -because code generated will need these imports. - -```rust -use rhai::plugin::*; -``` - - -`#[export_module]` ------------------- - -When applied to a Rust module, the `#[export_module]` attribute generates the necessary -code and metadata to allow Rhai access to its public (i.e. marked `pub`) functions, constants -and sub-modules. - -This code is exactly what would need to be written by hand to achieve the same goal, -and is custom fit to each exported item. - -All `pub` functions become registered functions, all `pub` constants become [module] constant variables, -and all sub-modules become Rhai sub-modules. - -This Rust module can then be registered into an [`Engine`] as a normal [module]. -This is done via the `exported_module!` macro. - -The macro `combine_with_exported_module!` can be used to _combine_ all the functions -and variables into an existing [module], _flattening_ the namespace – i.e. all sub-modules -are eliminated and their contents promoted to the top level. This is typical for -developing [custom packages]. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This constant will be registered as the constant variable 'MY_NUMBER'. - // Ignored when registered as a global module. - pub const MY_NUMBER: i64 = 42; - - // This function will be registered as 'greet'. - pub fn greet(name: &str) -> String { - format!("hello, {}!", name) - } - // This function will be registered as 'get_num'. - pub fn get_num() -> i64 { - mystic_number() - } - // This function will be registered as 'increment'. - // It will also be exposed to the global namespace since 'global' is set. - #[rhai_fn(global)] - pub fn increment(num: &mut i64) { - *num += 1; - } - // This function is not 'pub', so NOT registered. - fn mystic_number() -> i64 { - 42 - } - - // Sub-modules are ignored when the module is registered globally. - pub mod my_sub_module { - // This function is ignored when registered globally. - // Otherwise it is a valid registered function under a sub-module. - pub fn get_info() -> String { - "hello".to_string() - } - } - - // Sub-modules are commonly used to put feature gates on a group of - // functions because feature gates cannot be put on function definitions. - // This is currently a limitation of the plugin procedural macros. - #[cfg(feature = "advanced_functions")] - pub mod advanced { - // This function is ignored when registered globally. - // Otherwise it is a valid registered function under a sub-module - // which only exists when the 'advanced_functions' feature is used. - pub fn advanced_calc(input: i64) -> i64 { - input * 2 - } - } -} -``` - -### Use `Engine::register_global_module` - -The simplest way to register this into an [`Engine`] is to first use the `exported_module!` macro -to turn it into a normal Rhai [module], then use the `Engine::register_global_module` method on it: - -```rust -fn main() { - let mut engine = Engine::new(); - - // The macro call creates a Rhai module from the plugin module. - let module = exported_module!(my_module); - - // A module can simply be registered into the global namespace. - engine.register_global_module(module.into()); -} -``` - -The functions contained within the module definition (i.e. `greet`, `get_num` and `increment`) -are automatically registered into the [`Engine`] when `Engine::register_global_module` is called. - -```rust -let x = greet("world"); -x == "hello, world!"; - -let x = greet(get_num().to_string()); -x == "hello, 42!"; - -let x = get_num(); -x == 42; - -increment(x); -x == 43; -``` - -Notice that, when using a [module] as a [package], only functions registered at the _top level_ -can be accessed. - -Variables as well as sub-modules are **ignored**. - -### Use `Engine::register_static_module` - -Another simple way to register this into an [`Engine`] is, again, to use the `exported_module!` macro -to turn it into a normal Rhai [module], then use the `Engine::register_static_module` method on it: - -```rust -fn main() { - let mut engine = Engine::new(); - - // The macro call creates a Rhai module from the plugin module. - let module = exported_module!(my_module); - - // A module can simply be registered as a static module namespace. - engine.register_static_module("service", module.into()); -} -``` - -The functions contained within the module definition (i.e. `greet`, `get_num` and `increment`), -plus the constant `MY_NUMBER`, are automatically registered under the module namespace `service`: - -```rust -let x = service::greet("world"); -x == "hello, world!"; - -service::MY_NUMBER == 42; - -let x = service::greet(service::get_num().to_string()); -x == "hello, 42!"; - -let x = service::get_num(); -x == 42; - -service::increment(x); -x == 43; -``` - -All functions (usually _methods_) defined in the module and marked with `#[rhai_fn(global)]`, -as well as all [type iterators], are automatically exposed to the _global_ namespace, so -[iteration]({{rootUrl}}/language/for.md), [getters/setters] and [indexers] for [custom types] -can work as expected. - -In fact, the default for all [getters/setters] and [indexers] defined in a plugin module -is `#[rhai_fn(global)]` unless specifically overridden by `#[rhai_fn(internal)]`. - -Therefore, in the example above, the `increment` method (defined with `#[rhai_fn(global)]`) -works fine when called in method-call style: - -```rust -let x = 42; -x.increment(); -x == 43; -``` - -### Use Dynamically - -Using this directly as a dynamically-loadable Rhai [module] is almost the same, except that a -[module resolver] must be used to serve the module, and the module is loaded via `import` statements. - -See the [module] section for more information. - -### Combine into Custom Package - -Finally the plugin module can also be used to develop a [custom package], -using `combine_with_exported_module!`: - -```rust -def_package!(rhai:MyPackage:"My own personal super package", module, { - combine_with_exported_module!(module, "my_module_ID", my_module)); -}); -``` - -`combine_with_exported_module!` automatically _flattens_ the module namespace so that all -functions in sub-modules are promoted to the top level. This is convenient for [custom packages]. - - -Sub-Modules and Feature Gates ----------------------------- - -Sub-modules in a plugin module definition are turned into valid sub-modules in the resultant -Rhai `Module`. - -They are also commonly used to put _feature gates_ or _compile-time gates_ on a group of functions, -because currently attributes do not work on individual function definitions due to a limitation of -the procedural macros system. - -This is especially convenient when using the `combine_with_exported_module!` macro to develop -[custom packages] because selected groups of functions can easily be included or excluded based on -different combinations of feature flags instead of having to manually include/exclude every -single function. - -```rust -#[export_module] -mod my_module { - // Always available - pub fn func0() {} - - // The following sub-module is only available under 'feature1' - #[cfg(feature = "feature1")] - pub mod feature1 { - fn func1() {} - fn func2() {} - fn func3() {} - } - - // The following sub-module is only available under 'feature2' - #[cfg(feature = "feature2")] - pub mod feature2 { - fn func4() {} - fn func5() {} - fn func6() {} - } -} - -// Registered functions: -// func0 - always available -// func1 - available under 'feature1' -// func2 - available under 'feature1' -// func3 - available under 'feature1' -// func4 - available under 'feature2' -// func5 - available under 'feature2' -// func6 - available under 'feature2' -combine_with_exported_module!(module, "my_module_ID", my_module); -``` - - -Function Overloading and Operators ---------------------------------- - -Operators and overloaded functions can be specified via applying the `#[rhai_fn(name = "...")]` -attribute to individual functions. - -The text string given as the `name` parameter to `#[rhai_fn]` is used to register the function with -the [`Engine`], disregarding the actual name of the function. - -With `#[rhai_fn(name = "...")]`, multiple functions may be registered under the same name in Rhai, -so long as they have different parameters. - -Operators (which require function names that are not valid for Rust) can also be registered this way. - -Registering the same function name with the same parameter types will cause a parsing error. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This is the '+' operator for 'TestStruct'. - #[rhai_fn(name = "+")] - pub fn add(obj: &mut TestStruct, value: i64) { - obj.prop += value; - } - // This function is 'calc (i64)'. - #[rhai_fn(name = "calc")] - pub fn calc_with_default(num: i64) -> i64 { - ... - } - // This function is 'calc (i64, bool)'. - #[rhai_fn(name = "calc")] - pub fn calc_with_option(num: i64, option: bool) -> i64 { - ... - } -} -``` - - -Getters, Setters and Indexers ------------------------------ - -Functions can be marked as [getters/setters] and [indexers] for [custom types] via the `#[rhai_fn]` -attribute, which is applied on a function level. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This is a normal function 'greet'. - pub fn greet(name: &str) -> String { - format!("hello, {}!", name) - } - // This is a getter for 'TestStruct::prop'. - #[rhai_fn(get = "prop")] - pub fn get_prop(obj: &mut TestStruct) -> i64 { - obj.prop - } - // This is a setter for 'TestStruct::prop'. - #[rhai_fn(set = "prop")] - pub fn set_prop(obj: &mut TestStruct, value: i64) { - obj.prop = value; - } - // This is an index getter for 'TestStruct'. - #[rhai_fn(index_get)] - pub fn get_index(obj: &mut TestStruct, index: i64) -> bool { - obj.list[index] - } - // This is an index setter for 'TestStruct'. - #[rhai_fn(index_set)] - pub fn get_index(obj: &mut TestStruct, index: i64, state: bool) { - obj.list[index] = state; - } -} -``` - - -Multiple Registrations ----------------------- - -Parameters to the `#[rhai_fn(...)]` attribute can be applied multiple times. - -This is especially useful for the `name = "..."`, `get = "..."` and `set = "..."` parameters -to give multiple alternative names to the same function. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This function can be called in five ways - #[rhai_fn(name = "get_prop_value", name = "prop", name = "+", set = "prop", index_get)] - pub fn prop_function(obj: &mut TestStruct, index: i64) -> i64 { - obj.prop[index] - } -} -``` - -The above function can be called in five ways: - -| Parameter for `#[rhai_fn(...)]` | Type | Call style | -| ------------------------------- | :-------------: | --------------------------------------------- | -| `name = "get_prop_value"` | method function | `get_prop_value(x, 0)`, `x.get_prop_value(0)` | -| `name = "prop"` | method function | `prop(x, 0)`, `x.prop(0)` | -| `name = "+"` | operator | `x + 42` | -| `set = "prop"` | setter | `x.prop = 42` | -| `index_get` | index getter | `x[0]` | - - -Fallible Functions ------------------- - -To register [fallible functions] (i.e. functions that may return errors), apply the -`#[rhai_fn(return_raw)]` attribute on functions that return `Result>`. - -A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does not -have the appropriate return type. - -```rust -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This overloads the '/' operator for i64. - #[rhai_fn(name = "/", return_raw)] - pub fn double_and_divide(x: i64, y: i64) -> Result> { - if y == 0 { - Err("Division by zero!".into()) - } else { - let result = (x * 2) / y; - Ok(result.into()) - } - } -} -``` - - -`NativeCallContext` Parameter ----------------------------- - -If the _first_ parameter of a function is of type `rhai::NativeCallContext`, then it is treated -specially by the plugins system. - -`NativeCallContext` is a type that encapsulates the current _native call context_ and exposes the following: - -| Field | Type | Description | -| ------------------- | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. | -| `source()` | `Option<&str>` | reference to the current source, if any | -| `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | - -This first parameter, if exists, will be stripped before all other processing. It is _virtual_. -Most importantly, it does _not_ count as a parameter to the function and there is no need to provide -this argument when calling the function in Rhai. - -The native call context can be used to call a [function pointer] or [closure] that has been passed -as a parameter to the function, thereby implementing a _callback_: - -```rust -use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult}; -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - #[rhai_fn(return_raw)] - pub fn greet(context: NativeCallContext, callback: FnPtr) - -> Result> - { - // Call the callback closure with the current context - // to obtain the name to greet! - let name = callback.call_dynamic(context, None, [])?; - Ok(format!("hello, {}!", name).into()) - } -} -``` - -The native call context is also useful in another scenario: protecting a function from malicious scripts. - -```rust -use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; -use rhai::plugin::*; // a "prelude" import for macros - -#[export_module] -mod my_module { - // This function builds an array of arbitrary size, but is protected - // against attacks by first checking with the allowed limit set - // into the 'Engine'. - #[rhai_fn(return_raw)] - pub fn grow(context: NativeCallContext, size: i64) - -> Result> - { - // Make sure the function does not generate a - // data structure larger than the allowed limit - // for the Engine! - if size as usize > context.engine().max_array_size() - { - return EvalAltResult::ErrorDataTooLarge( - "Size to grow".to_string(), - context.engine().max_array_size(), - size as usize, - Position::NONE, - ).into(); - } - - let array = Array::new(); - - for x in 0..size { - array.push(x.into()); - } - - OK(array.into()) - } -} -``` - - -`#[export_module]` Parameters ----------------------------- - -Parameters can be applied to the `#[export_module]` attribute to override its default behavior. - -| Parameter | Description | -| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -| _none_ | exports only public (i.e. `pub`) functions | -| `export_all` | exports all functions (including private, non-`pub` functions); use `#[rhai_fn(skip)]` on individual functions to avoid export | -| `export_prefix = "..."` | exports functions (including private, non-`pub` functions) with names starting with a specific prefix | - - -Inner Attributes ----------------- - -Inner attributes can be applied to the inner items of a module to tweak the export process. - -`#[rhai_fn]` is applied to functions, while `#[rhai_mod]` is applied to sub-modules. - -Parameters should be set on inner attributes to specify the desired behavior. - -| Attribute Parameter | Use with | Apply to | Description | -| ------------------- | --------------------------- | ----------------------------------------------------- | ------------------------------------------------------- | -| `skip` | `#[rhai_fn]`, `#[rhai_mod]` | function or sub-module | do not export this function/sub-module | -| `global` | `#[rhai_fn]` | function | expose this function to the global namespace | -| `internal` | `#[rhai_fn]` | function | keep this function within the internal module namespace | -| `name = "..."` | `#[rhai_fn]`, `#[rhai_mod]` | function or sub-module | registers function/sub-module under the specified name | -| `get = "..."` | `#[rhai_fn]` | `pub fn (&mut Type) -> Value` | registers a getter for the named property | -| `set = "..."` | `#[rhai_fn]` | `pub fn (&mut Type, Value)` | registers a setter for the named property | -| `index_get` | `#[rhai_fn]` | `pub fn (&mut Type, INT) -> Value` | registers an index getter | -| `index_set` | `#[rhai_fn]` | `pub fn (&mut Type, INT, Value)` | registers an index setter | -| `return_raw` | `#[rhai_fn]` | `pub fn (...) -> Result>` | marks this as a [fallible function] | diff --git a/doc/src/rust/custom.md b/doc/src/rust/custom.md deleted file mode 100644 index 1b0bec44..00000000 --- a/doc/src/rust/custom.md +++ /dev/null @@ -1,200 +0,0 @@ -Register any Rust Type and its Methods -===================================== - -{{#include ../links.md}} - - -Free Typing ------------ - -Rhai works seamlessly with _any_ Rust type. The type can be _anything_; it does not -have any prerequisites other than being `Clone`. It does not need to implement -any other trait or use any custom `#[derive]`. - -This allows Rhai to be integrated into an existing Rust code base with as little plumbing -as possible, usually silently and seamlessly. External types that are not defined -within the same crate (and thus cannot implement special Rhai traits or -use special `#[derive]`) can also be used easily with Rhai. - -The reason why it is termed a _custom_ type throughout this documentation is that -Rhai natively supports a number of data types with fast, internal treatment (see -the list of [standard types]). Any type outside of this list is considered _custom_. - -Any type not supported natively by Rhai is stored as a Rust _trait object_, with no -restrictions other than being `Clone` (plus `Send + Sync` under the [`sync`] feature). -It runs slightly slower than natively-supported types as it does not have built-in, -optimized implementations for commonly-used functions, but for all other purposes has -no difference. - -Support for custom types can be turned off via the [`no_object`] feature. - - -Register a Custom Type and its Methods -------------------------------------- - -Any custom type must implement the `Clone` trait as this allows the [`Engine`] to pass by value. - -If the [`sync`] feature is used, it must also be `Send + Sync`. - -Notice that the custom type needs to be _registered_ using `Engine::register_type` -or `Engine::register_type_with_name`. - -To use native methods on custom types in Rhai scripts, it is common to register an API -for the type using one of the `Engine::register_XXX` functions. - -```rust -use rhai::{Engine, EvalAltResult}; -use rhai::RegisterFn; // remember 'RegisterFn' is needed - -#[derive(Clone)] -struct TestStruct { - field: i64 -} - -impl TestStruct { - fn new() -> Self { - Self { field: 1 } - } - - fn update(&mut self, x: i64) { // methods take &mut as first parameter - self.field += x; - } -} - -let mut engine = Engine::new(); - -// Most Engine API's can be chained up. -engine - .register_type::() // register custom type - .register_fn("new_ts", TestStruct::new) - .register_fn("update", TestStruct::update); - -// Cast result back to custom type. -let result = engine.eval::( - r" - let x = new_ts(); // calls 'TestStruct::new' - x.update(41); // calls 'TestStruct::update' - x // 'x' holds a 'TestStruct' - " -)?; - -println!("result: {}", result.field); // prints 42 -``` - -Rhai follows the convention that methods of custom types take a `&mut` first parameter -to that type, so that invoking methods can always update it. - -All other parameters in Rhai are passed by value (i.e. clones). - -**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** - - -Method-Call Style vs. Function-Call Style ----------------------------------------- - -Any function with a first argument that is a `&mut` reference can be used -as method calls because internally they are the same thing: methods on a type is -implemented as a functions taking a `&mut` first argument. - -This design is similar to Rust. - -```rust -impl TestStruct { - fn foo(&mut self) -> i64 { - self.field - } -} - -engine.register_fn("foo", TestStruct::foo); - -let result = engine.eval::( - r" - let x = new_ts(); - foo(x); // normal call to 'foo' - x.foo() // 'foo' can also be called like a method on 'x' - " -)?; - -println!("result: {}", result); // prints 1 -``` - -Under [`no_object`], however, the _method_ style of function calls -(i.e. calling a function as an object-method) is no longer supported. - -```rust -// Below is a syntax error under 'no_object'. -let result = engine.eval("let x = [1, 2, 3]; x.clear();")?; - // ^ cannot call in method style under 'no_object' -``` - - -`type_of()` a Custom Type -------------------------- - -[`type_of()`] works fine with custom types and returns the name of the type. - -If `Engine::register_type_with_name` is used to register the custom type -with a special "pretty-print" name, [`type_of()`] will return that name instead. - -```rust -engine - .register_type::() - .register_fn("new_ts1", TestStruct1::new) - .register_type_with_name::("TestStruct") - .register_fn("new_ts2", TestStruct2::new); - -let ts1_type = engine.eval::(r#"let x = new_ts1(); x.type_of()"#)?; -let ts2_type = engine.eval::(r#"let x = new_ts2(); x.type_of()"#)?; - -println!("{}", ts1_type); // prints 'path::to::TestStruct' -println!("{}", ts1_type); // prints 'TestStruct' -``` - - -Use the Custom Type With Arrays ------------------------------- - -The `push`, `insert`, `pad` functions, as well as the `+=` operator, for [arrays] are only -defined for standard built-in types. For custom types, type-specific versions must be registered: - -```rust -engine - .register_fn("push", |list: &mut Array, item: TestStruct| { - list.push(Dynamic::from(item)); - }).register_fn("+=", |list: &mut Array, item: TestStruct| { - list.push(Dynamic::from(item)); - }).register_fn("insert", |list: &mut Array, position: i64, item: TestStruct| { - if position <= 0 { - list.insert(0, Dynamic::from(item)); - } else if (position as usize) >= list.len() - 1 { - list.push(item); - } else { - list.insert(position as usize, Dynamic::from(item)); - } - }).register_fn("pad", |list: &mut Array, len: i64, item: TestStruct| { - if len as usize > list.len() { - list.resize(len as usize, item); - } - }); -``` - -In particular, in order to use the `in` operator with a custom type for an [array], -the `==` operator must be registered for the custom type: - -```rust -// Assume 'TestStruct' implements `PartialEq` -engine.register_fn("==", - |item1: &mut TestStruct, item2: TestStruct| item1 == &item2 -); - -// Then this works in Rhai: -let item = new_ts(); // construct a new 'TestStruct' -item in array; // 'in' operator uses '==' -``` - - -Working With Enums ------------------- - -It is quite easy to use Rust enums with Rhai. -See [this chapter]({{rootUrl}}/patterns/enums.md) for more details. diff --git a/doc/src/rust/disable-custom.md b/doc/src/rust/disable-custom.md deleted file mode 100644 index 912482e5..00000000 --- a/doc/src/rust/disable-custom.md +++ /dev/null @@ -1,18 +0,0 @@ -Disable Custom Types -==================== - -{{#include ../links.md}} - - -`no_object` Feature -------------------- - -The custom types API `register_type`, `register_type_with_name`, `register_get`, `register_get_result`, -`register_set`, `register_set_result` and `register_get_set` are not available under [`no_object`]. - - -`no_index` Feature ------------------- - -The indexers API `register_indexer_get`, `register_indexer_get_result`, `register_indexer_set`, -`register_indexer_set_result`, and `register_indexer_get_set` are also not available under [`no_index`]. diff --git a/doc/src/rust/fallible.md b/doc/src/rust/fallible.md deleted file mode 100644 index 86d15576..00000000 --- a/doc/src/rust/fallible.md +++ /dev/null @@ -1,41 +0,0 @@ -Register a Fallible Rust Function -================================ - -{{#include ../links.md}} - -If a function is _fallible_ (i.e. it returns a `Result<_, Error>`), it can be registered with `register_result_fn` -(using the `RegisterResultFn` trait). - -The function must return `Result>`. - -```rust -use rhai::{Engine, EvalAltResult, Position}; -use rhai::RegisterResultFn; // use 'RegisterResultFn' trait for 'register_result_fn' - -// Function that may fail - the result type must be 'Dynamic' -fn safe_divide(x: i64, y: i64) -> Result> { - if y == 0 { - // Return an error if y is zero - Err("Division by zero!".into()) // shortcut to create Box - } else { - Ok((x / y).into()) // convert result into 'Dynamic' - } -} - -let mut engine = Engine::new(); - -// Fallible functions that return Result values must use register_result_fn() -engine.register_result_fn("divide", safe_divide); - -if let Err(error) = engine.eval::("divide(40, 0)") { - println!("Error: {:?}", *error); // prints ErrorRuntime("Division by zero detected!", (1, 1)") -} -``` - -Create a `Box` ----------------------------- - -`Box` implements `From<&str>` and `From` etc. -and the error text gets converted into `Box`. - -The error values are `Box`-ed in order to reduce memory footprint of the error path, which should be hit rarely. diff --git a/doc/src/rust/functions.md b/doc/src/rust/functions.md deleted file mode 100644 index 99e9a485..00000000 --- a/doc/src/rust/functions.md +++ /dev/null @@ -1,73 +0,0 @@ -Register a Rust Function -======================== - -{{#include ../links.md}} - -Rhai's scripting engine is very lightweight. It gets most of its abilities from functions. - -To call these functions, they need to be _registered_ with the [`Engine`] using `Engine::register_fn` -(in the `RegisterFn` trait) and `Engine::register_result_fn` (in the `RegisterResultFn` trait, -see [fallible functions]). - -```rust -use rhai::{Dynamic, Engine, EvalAltResult, ImmutableString}; -use rhai::RegisterFn; // use 'RegisterFn' trait for 'register_fn' -use rhai::RegisterResultFn; // use 'RegisterResultFn' trait for 'register_result_fn' - -// Normal function that returns a standard type -// Remember to use 'ImmutableString' and not 'String' -fn add_len(x: i64, s: ImmutableString) -> i64 { - x + s.len() -} -// Alternatively, '&str' maps directly to 'ImmutableString' -fn add_len_str(x: i64, s: &str) -> i64 { - x + s.len() -} - -// Function that returns a 'Dynamic' value - must return a 'Result' -fn get_any_value() -> Result> { - Ok((42_i64).into()) // standard types can use 'into()' -} - -let mut engine = Engine::new(); - -engine - .register_fn("add", add_len) - .register_fn("add_str", add_len_str); - -let result = engine.eval::(r#"add(40, "xx")"#)?; - -println!("Answer: {}", result); // prints 42 - -let result = engine.eval::(r#"add_str(40, "xx")"#)?; - -println!("Answer: {}", result); // prints 42 - -// Functions that return Dynamic values must use register_result_fn() -engine.register_result_fn("get_any_value", get_any_value); - -let result = engine.eval::("get_any_value()")?; - -println!("Answer: {}", result); // prints 42 -``` - -To create a [`Dynamic`] value, use the `Dynamic::from` method. -[Standard types] in Rhai can also use `into()`. - -```rust -use rhai::Dynamic; - -let x = (42_i64).into(); // 'into()' works for standard types - -let y = Dynamic::from("hello!".to_string()); // remember &str is not supported by Rhai -``` - - -Function Overloading --------------------- - -Functions registered with the [`Engine`] can be _overloaded_ as long as the _signature_ is unique, -i.e. different functions can have the same name as long as their parameters are of different types -or different number. - -New definitions _overwrite_ previous definitions of the same name and same number/types of parameters. diff --git a/doc/src/rust/generic.md b/doc/src/rust/generic.md deleted file mode 100644 index d2bea789..00000000 --- a/doc/src/rust/generic.md +++ /dev/null @@ -1,30 +0,0 @@ -Register a Generic Rust Function -=============================== - -{{#include ../links.md}} - -Rust generic functions can be used in Rhai, but separate instances for each concrete type must be registered separately. - -This essentially _overloads_ the function with different parameter types as Rhai does not natively support generics -but Rhai does support _function overloading_. - -```rust -use std::fmt::Display; - -use rhai::{Engine, RegisterFn}; - -fn show_it(x: &mut T) { - println!("put up a good show: {}!", x) -} - -let mut engine = Engine::new(); - -engine - .register_fn("print", show_it::) - .register_fn("print", show_it::) - .register_fn("print", show_it::); -``` - -The above example shows how to register multiple functions -(or, in this case, multiple overloaded versions of the same function) -under the same name. diff --git a/doc/src/rust/getters-setters.md b/doc/src/rust/getters-setters.md deleted file mode 100644 index 334c7438..00000000 --- a/doc/src/rust/getters-setters.md +++ /dev/null @@ -1,69 +0,0 @@ -Custom Type Property Getters and Setters -======================================= - -{{#include ../links.md}} - -A [custom type] can also expose properties by registering `get` and/or `set` functions. - -Getters and setters each take a `&mut` reference to the first parameter. - -Getters and setters are disabled when the [`no_object`] feature is used. - -| `Engine` API | Function signature(s)
(`T: Clone` = custom type,
`V: Clone` = data type) | Can mutate `T`? | -| --------------------- | -------------------------------------------------------------------------------- | :----------------------------: | -| `register_get` | `Fn(&mut T) -> V` | yes, but not advised | -| `register_set` | `Fn(&mut T, V)` | yes | -| `register_get_set` | getter: `Fn(&mut T) -> V`
setter: `Fn(&mut T, V)` | yes, but not advised in getter | -| `register_get_result` | `Fn(&mut T) -> Result>` | yes, but not advised | -| `register_set_result` | `Fn(&mut T, V) -> Result<(), Box>` | yes | - -By convention, property getters are not supposed to mutate the [custom type], although there is nothing -that prevents this mutation. - - -Cannot Override Object Maps --------------------------- - -Property getters and setters are mainly intended for [custom types]. - -Any getter or setter function registered for [object maps] is simply _ignored_ because -the get/set calls will be interpreted as properties on the [object maps]. - - -Examples --------- - -```rust -#[derive(Clone)] -struct TestStruct { - field: String -} - -impl TestStruct { - // Remember &mut must be used even for getters - fn get_field(&mut self) -> String { - self.field.clone() - } - - fn set_field(&mut self, new_val: &str) { - self.field = new_val.to_string(); - } - - fn new() -> Self { - Self { field: "hello" } - } -} - -let mut engine = Engine::new(); - -engine - .register_type::() - .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field) - .register_fn("new_ts", TestStruct::new); - -let result = engine.eval::(r#"let a = new_ts(); a.xyz = "42"; a.xyz"#)?; - -println!("Answer: {}", result); // prints 42 -``` - -**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** diff --git a/doc/src/rust/index.md b/doc/src/rust/index.md deleted file mode 100644 index 6a0ca08d..00000000 --- a/doc/src/rust/index.md +++ /dev/null @@ -1,9 +0,0 @@ -Extend Rhai with Rust -==================== - -{{#include ../links.md}} - -Most features and functionalities required by a Rhai script should actually be coded in Rust, -which leverages the superior native run-time speed. - -This section discusses how to extend Rhai with functionalities written in Rust. diff --git a/doc/src/rust/indexers.md b/doc/src/rust/indexers.md deleted file mode 100644 index f7cff1af..00000000 --- a/doc/src/rust/indexers.md +++ /dev/null @@ -1,82 +0,0 @@ -Custom Type Indexers -=================== - -{{#include ../links.md}} - -A [custom type] can also expose an _indexer_ by registering an indexer function. - -A [custom type] with an indexer function defined can use the bracket notation to get a property value: - -> _object_ `[` _index_ `]` - -Like property [getters/setters], indexers take a `&mut` reference to the first parameter. - -They also take an additional parameter of any type that serves as the _index_ within brackets. - -Indexers are disabled when the [`no_index`] feature is used. - -| `Engine` API | Function signature(s)
(`T: Clone` = custom type,
`X: Clone` = index type,
`V: Clone` = data type) | Can mutate `T`? | -| ----------------------------- | ------------------------------------------------------------------------------------------------------------- | :----------------------------: | -| `register_indexer_get` | `Fn(&mut T, X) -> V` | yes, but not advised | -| `register_indexer_set` | `Fn(&mut T, X, V)` | yes | -| `register_indexer_get_set` | getter: `Fn(&mut T, X) -> V`
setter: `Fn(&mut T, X, V)` | yes, but not advised in getter | -| `register_indexer_get_result` | `Fn(&mut T, X) -> Result>` | yes, but not advised | -| `register_indexer_set_result` | `Fn(&mut T, X, V) -> Result<(), Box>` | yes | - -By convention, index getters are not supposed to mutate the [custom type], although there is nothing -that prevents this mutation. - -**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.** - - -Cannot Override Arrays, Object Maps and Strings ----------------------------------------------- - -For efficiency reasons, indexers **cannot** be used to overload (i.e. override) -built-in indexing operations for [arrays], [object maps] and [strings]. - -Attempting to register indexers for an [array], [object map] or [string] panics. - - -Examples --------- - -```rust -#[derive(Clone)] -struct TestStruct { - fields: Vec -} - -impl TestStruct { - // Remember &mut must be used even for getters - fn get_field(&mut self, index: String) -> i64 { - self.fields[index.len()] - } - fn set_field(&mut self, index: String, value: i64) { - self.fields[index.len()] = value - } - - fn new() -> Self { - Self { fields: vec![1, 2, 3, 4, 5] } - } -} - -let mut engine = Engine::new(); - -engine - .register_type::() - .register_fn("new_ts", TestStruct::new) - // Short-hand: .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field); - .register_indexer_get(TestStruct::get_field) - .register_indexer_set(TestStruct::set_field); - -let result = engine.eval::( - r#" - let a = new_ts(); - a["xyz"] = 42; // these indexers use strings - a["xyz"] // as the index type - "# -)?; - -println!("Answer: {}", result); // prints 42 -``` diff --git a/doc/src/rust/modules/ast.md b/doc/src/rust/modules/ast.md deleted file mode 100644 index 0b2bb8b8..00000000 --- a/doc/src/rust/modules/ast.md +++ /dev/null @@ -1,80 +0,0 @@ -Create a Module from an AST -========================== - -{{#include ../../links.md}} - - -`Module::eval_ast_as_new` ------------------------- - -A [module] can be created from a single script (or pre-compiled [`AST`]) containing global variables, -functions and sub-modules via the `Module::eval_ast_as_new` method. - -See the section on [_Exporting Variables, Functions and Sub-Modules_][`export`] for details on how to -prepare a Rhai script for this purpose as well as to control which functions/variables to export. - -When given an [`AST`], it is first evaluated, then the following items are exposed as members of the -new [module]: - -* Global variables – all variables exported via the `export` statement (those not exported remain hidden). - -* Functions not specifically marked `private`. - -* Global modules that remain in the [`Scope`] at the end of a script run (become sub-modules). - -`Module::eval_ast_as_new` encapsulates the entire `AST` into each function call, merging the -module namespace with the global namespace. Therefore, functions defined within the same module -script can cross-call each other. - - -Examples --------- - -Don't forget the [`export`] statement, otherwise there will be no variables exposed by the module -other than non-[`private`] functions (unless that's intentional). - -```rust -use rhai::{Engine, Module}; - -let engine = Engine::new(); - -// Compile a script into an 'AST' -let ast = engine.compile(r#" - // Functions become module functions - fn calc(x) { - x + 1 - } - fn add_len(x, y) { - x + y.len - } - - // Imported modules can become sub-modules - import "another module" as extra; - - // Variables defined at global level can become module variables - const x = 123; - let foo = 41; - let hello; - - // Variable values become constant module variable values - foo = calc(foo); - hello = "hello, " + foo + " worlds!"; - - // Finally, export the variables and modules - export - x as abc, // aliased variable name - foo, - hello, - extra as foobar; // export sub-module -"#)?; - -// Convert the 'AST' into a module, using the 'Engine' to evaluate it first -// A copy of the entire 'AST' is encapsulated into each function, -// allowing functions in the module script to cross-call each other. -let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?; - -// 'module' now contains: -// - sub-module: 'foobar' (renamed from 'extra') -// - functions: 'calc', 'add_len' -// - constants: 'abc' (renamed from 'x'), 'foo', 'hello' -``` diff --git a/doc/src/rust/modules/create.md b/doc/src/rust/modules/create.md deleted file mode 100644 index f5e10e97..00000000 --- a/doc/src/rust/modules/create.md +++ /dev/null @@ -1,158 +0,0 @@ -Create a Module from Rust -======================== - -{{#include ../../links.md}} - - -Create via Plugin ------------------ - -By far the simplest way to create a [module] is via a [plugin module] -which converts a normal Rust module into a Rhai [module] via procedural macros. - - -Create via `Module` API ------------------------ - -Manually creating a [module] is possible via the `Module` API. - -For the complete `Module` API, refer to the [documentation](https://docs.rs/rhai/{{version}}/rhai/struct.Module.html) online. - - -Use Case 1 – Make the `Module` Globally Available ------------------------------------------------------- - -`Engine::register_global_module` registers a shared [module] into the _global_ namespace. - -All [functions] and [type iterators] can be accessed without _namespace qualifiers_. -Variables and sub-modules are **ignored**. - -This is by far the easiest way to expose a module's functionalities to Rhai. - -```rust -use rhai::{Engine, Module}; - -let mut module = Module::new(); // new module - -// Use the 'Module::set_fn_XXX' API to add functions. -let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1)); - -// Remember to update the parameter names/types and return type metadata. -// 'Module::set_fn_XXX' by default does not set function metadata. -module.update_fn_metadata(hash, ["x: i64", "i64"]); - -// Register the module into the global namespace of the Engine. -let mut engine = Engine::new(); -engine.register_global_module(module.into()); - -engine.eval::("inc(41)")? == 42; // no need to import module -``` - -Registering a [module] via `Engine::register_global_module` is essentially the _same_ -as calling `Engine::register_fn` (or any of the `Engine::register_XXX` API) individually -on each top-level function within that [module]. In fact, the actual implementation of -`Engine::register_fn` etc. simply adds the function to an internal [module]! - -```rust -// The above is essentially the same as: -let mut engine = Engine::new(); - -engine.register_fn("inc", |x: i64| x + 1); - -engine.eval::("inc(41)")? == 42; // no need to import module -``` - -Use Case 2 – Make the `Module` a Static Module ---------------------------------------------------- - -`Engine::register_static_module` registers a [module] and under a specific module namespace. - -```rust -use rhai::{Engine, Module}; - -let mut module = Module::new(); // new module - -// Use the 'Module::set_fn_XXX' API to add functions. -let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1)); - -// Remember to update the parameter names/types and return type metadata. -// 'Module::set_fn_XXX' by default does not set function metadata. -module.update_fn_metadata(hash, ["x: i64", "i64"]); - -// Register the module into the Engine as the static module namespace path -// 'services::calc' -let mut engine = Engine::new(); -engine.register_static_module("services::calc", module.into()); - -// refer to the 'services::calc' module -engine.eval::("services::calc::inc(41)")? == 42; -``` - -### Expose Functions to the Global Namespace - -The `Module::set_fn_XXX_mut` API methods can optionally expose functions in the [module] -to the _global_ namespace by setting the `namespace` parameter to `FnNamespace::Global`, -so [getters/setters] and [indexers] for [custom types] can work as expected. - -[Type iterators], because of their special nature, are _always_ exposed to the _global_ namespace. - -```rust -use rhai::{Engine, Module, FnNamespace}; - -let mut module = Module::new(); // new module - -// Expose method 'inc' to the global namespace (default is 'FnNamespace::Internal') -let hash = module.set_fn_1_mut("inc", FnNamespace::Global, |x: &mut i64| Ok(x + 1)); - -// Remember to update the parameter names/types and return type metadata. -// 'Module::set_fn_XXX_mut' by default does not set function metadata. -module.update_fn_metadata(hash, ["x: &mut i64", "i64"]); - -// Register the module into the Engine as a static module namespace 'calc' -let mut engine = Engine::new(); -engine.register_static_module("calc", module.into()); - -// 'inc' works when qualified by the namespace -engine.eval::("calc::inc(41)")? == 42; - -// 'inc' also works without a namespace qualifier -// because it is exposed to the global namespace -engine.eval::("let x = 41; x.inc()")? == 42; -engine.eval::("let x = 41; inc(x)")? == 42; -``` - - -Use Case 3 – Make the `Module` Dynamically Loadable --------------------------------------------------------- - -In order to dynamically load a custom module, there must be a [module resolver] which serves -the module when loaded via `import` statements. - -The easiest way is to use, for example, the [`StaticModuleResolver`][module resolver] to hold such -a custom module. - -```rust -use rhai::{Engine, Scope, Module}; -use rhai::module_resolvers::StaticModuleResolver; - -let mut module = Module::new(); // new module -module.set_var("answer", 41_i64); // variable 'answer' under module -module.set_fn_1("inc", |x: i64| Ok(x + 1)); // use the 'set_fn_XXX' API to add functions - -// Create the module resolver -let mut resolver = StaticModuleResolver::new(); - -// Add the module into the module resolver under the name 'question' -// They module can then be accessed via: 'import "question" as q;' -resolver.insert("question", module); - -// Set the module resolver into the 'Engine' -let mut engine = Engine::new(); -engine.set_module_resolver(resolver); - -// Use namespace-qualified variables -engine.eval::(r#"import "question" as q; q::answer + 1"#)? == 42; - -// Call namespace-qualified functions -engine.eval::(r#"import "question" as q; q::inc(q::answer)"#)? == 42; -``` diff --git a/doc/src/rust/modules/imp-resolver.md b/doc/src/rust/modules/imp-resolver.md deleted file mode 100644 index 1094e208..00000000 --- a/doc/src/rust/modules/imp-resolver.md +++ /dev/null @@ -1,72 +0,0 @@ -Implement a Custom Module Resolver -================================= - -{{#include ../../links.md}} - -For many applications in which Rhai is embedded, it is necessary to customize the way that modules -are resolved. For instance, modules may need to be loaded from script texts stored in a database, -not in the file system. - -A module resolver must implement the trait [`rhai::ModuleResolver`][traits], -which contains only one function: `resolve`. - -When Rhai prepares to load a module, `ModuleResolver::resolve` is called with the name -of the _module path_ (i.e. the path specified in the [`import`] statement). - -* Upon success, it should return an [`Rc`][module] (or [`Arc`][module] under [`sync`]). - - The module should call `Module::build_index` on the target module before returning. - This method flattens the entire module tree and _indexes_ it for fast function name resolution. - If the module is already indexed, calling this method has no effect. - -* If the path does not resolve to a valid module, return `EvalAltResult::ErrorModuleNotFound`. - -* If the module failed to load, return `EvalAltResult::ErrorInModule`. - - -Example -------- - -```rust -use rhai::{ModuleResolver, Module, Engine, EvalAltResult}; - -// Define a custom module resolver. -struct MyModuleResolver {} - -// Implement the 'ModuleResolver' trait. -impl ModuleResolver for MyModuleResolver { - // Only required function. - fn resolve( - &self, - engine: &Engine, // reference to the current 'Engine' - path: &str, // the module path - pos: Position, // position of the 'import' statement - ) -> Result, Box> { - // Check module path. - if is_valid_module_path(path) { - let mut my_module = - load_secret_module(path) // load the custom module - .map_err(|err| - // Return EvalAltResult::ErrorInModule upon loading error - EvalAltResult::ErrorInModule(path.into(), Box::new(err), pos).into() - )?; - my_module.build_index(); // index it - Rc::new(my_module) // make it shared - } else { - // Return EvalAltResult::ErrorModuleNotFound if the path is invalid - Err(EvalAltResult::ErrorModuleNotFound(path.into(), pos).into()) - } - } -} - -let mut engine = Engine::new(); - -// Set the custom module resolver into the 'Engine'. -engine.set_module_resolver(MyModuleResolver {}); - -engine.consume(r#" - import "hello" as foo; // this 'import' statement will call - // 'MyModuleResolver::resolve' with "hello" as 'path' - foo:bar(); -"#)?; -``` diff --git a/doc/src/rust/modules/index.md b/doc/src/rust/modules/index.md deleted file mode 100644 index b42aa030..00000000 --- a/doc/src/rust/modules/index.md +++ /dev/null @@ -1,29 +0,0 @@ -Modules -======= - -{{#include ../../links.md}} - -Rhai allows organizing functionalities (functions, both Rust-based or script-based, and variables) -into independent _modules_. Modules can be disabled via the [`no_module`] feature. - -A module is of the type `Module` and holds a collection of functions, variables, -[type iterators] and sub-modules. - -It may be created entirely from Rust functions, or it may encapsulate a Rhai script together -with the functions and variables defined by that script. - -Other scripts can then load this module and use the functions and variables exported -as if they were defined inside the same script. - -Alternatively, modules can be registered directly into an [`Engine`] and made available -to scripts either globally or under individual static module [_namespaces_][function namespaces]. - - -Usage Patterns --------------- - -| Usage | API | Lookup | Sub-modules? | Variables? | -| -------------- | :-------------------------------: | :----------------------: | :----------: | :--------: | -| Global module | `Engine:: register_global_module` | simple name | ignored | ignored | -| Static module | `Engine:: register_static_module` | namespace-qualified name | yes | yes | -| Dynamic module | [`import`] statement | namespace-qualified name | yes | yes | diff --git a/doc/src/rust/modules/resolvers.md b/doc/src/rust/modules/resolvers.md deleted file mode 100644 index c7ba3196..00000000 --- a/doc/src/rust/modules/resolvers.md +++ /dev/null @@ -1,181 +0,0 @@ -Module Resolvers -================ - -{{#include ../../links.md}} - -When encountering an [`import`] statement, Rhai attempts to _resolve_ the module based on the path string. - -See the section on [_Importing Modules_][`import`] for more details. - -_Module Resolvers_ are service types that implement the [`ModuleResolver`][traits] trait. - - -Built-In Module Resolvers ------------------------- - -There are a number of standard resolvers built into Rhai, the default being the `FileModuleResolver` -which simply loads a script file based on the path (with `.rhai` extension attached) -and execute it to form a module. - -Built-in module resolvers are grouped under the `rhai::module_resolvers` module namespace. - - -`FileModuleResolver` (default) ------------------------------ - -The _default_ module resolution service, not available for [`no_std`] or [WASM] builds. -Loads a script file (based off the current directory) with `.rhai` extension. - -All functions in the _global_ namespace, plus all those defined in the same module, -are _merged_ into a _unified_ namespace. - -All modules imported at _global_ level via [`import`] statements become sub-modules, -which are also available to functions defined within the same script file. - -Modules are also _cached_ so a script file is only evaluated _once_, even when repeatedly imported. - -```rust ------------------- -| my_module.rhai | ------------------- - -// This function overrides any in the main script. -private fn inner_message() { "hello! from module!" } - -fn greet() { - print(inner_message()); // call function in module script -} - -fn greet_main() { - print(main_message()); // call function not in module script -} - -------------- -| main.rhai | -------------- - -// This function is overridden by the module script. -fn inner_message() { "hi! from main!" } - -// This function is found by the module script. -fn main_message() { "main here!" } - -import "my_module" as m; - -m::greet(); // prints "hello! from module!" - -m::greet_main(); // prints "main here!" -``` - -### Simulating virtual functions - -When calling a namespace-qualified function defined within a module, other functions defined within -the same module script override any similar-named functions (with the same number of parameters) -defined in the global namespace. This is to ensure that a module acts as a self-contained unit and -functions defined in the calling script do not override module code. - -In some situations, however, it is actually beneficial to do it in reverse: have module code call functions -defined in the calling script (i.e. in the global namespace) if they exist, and only call those defined -in the module script if none are found. - -One such situation is the need to provide a _default implementation_ to a simulated _virtual_ function: - -```rust ------------------- -| my_module.rhai | ------------------- - -// Do not do this (it will override the main script): -// fn message() { "hello! from module!" } - -// This function acts as the default implementation. -private fn default_message() { "hello! from module!" } - -// This function depends on a 'virtual' function 'message' -// which is not defined in the module script. -fn greet() { - if is_def_fn("message", 0) { // 'is_def_fn' detects if 'message' is defined. - print(message()); - } else { - print(default_message()); - } -} - -------------- -| main.rhai | -------------- - -// The main script defines 'message' which is needed by the module script. -fn message() { "hi! from main!" } - -import "my_module" as m; - -m::greet(); // prints "hi! from main!" - --------------- -| main2.rhai | --------------- - -// The main script does not define 'message' which is needed by the module script. - -import "my_module" as m; - -m::greet(); // prints "hello! from module!" -``` - -### Changing the base directory - -The base directory can be changed via the `FileModuleResolver::new_with_path` constructor function. - - -`StaticModuleResolver` ---------------------- - -Loads modules that are statically added. This can be used under [`no_std`]. - -Functions are searched in the _global_ namespace by default. - -```rust -use rhai::{Module, module_resolvers::StaticModuleResolver}; - -let module: Module = create_a_module(); - -let mut resolver = StaticModuleResolver::new(); -resolver.insert("my_module", module); -``` - - -`ModuleResolversCollection` --------------------------- - -A collection of module resolvers. Modules will be resolved from each resolver in sequential order. - -This is useful when multiple types of modules are needed simultaneously. - - -`DummyResolversCollection` -------------------------- - -This module resolver acts as a _dummy_ and always fails all module resolution calls. - - -Set into `Engine` ------------------ - -An [`Engine`]'s module resolver is set via a call to `Engine::set_module_resolver`: - -```rust -use rhai::module_resolvers::{DummyModuleResolver, StaticModuleResolver}; - -// Create a module resolver -let resolver = StaticModuleResolver::new(); - -// Register functions into 'resolver'... - -// Use the module resolver -engine.set_module_resolver(resolver); - -// Effectively disable 'import' statements by setting module resolver to -// the 'DummyModuleResolver' which acts as... well... a dummy. -engine.set_module_resolver(DummyModuleResolver::new()); -``` diff --git a/doc/src/rust/operators.md b/doc/src/rust/operators.md deleted file mode 100644 index 83175bf8..00000000 --- a/doc/src/rust/operators.md +++ /dev/null @@ -1,74 +0,0 @@ -Operator Overloading -=================== - -{{#include ../links.md}} - -In Rhai, a lot of functionalities are actually implemented as functions, including basic operations -such as arithmetic calculations. - -For example, in the expression "`a + b`", the `+` operator calls a function named "`+`"! - -```rust -let x = a + b; - -let x = +(a, b); // <- the above is equivalent to this function call -``` - -Similarly, comparison operators including `==`, `!=` etc. are all implemented as functions, -with the stark exception of `&&` and `||`. - - -`&&` and `||` Cannot Be Overloaded ---------------------------------- - -Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators), `&&` and `||` are -handled specially and _not_ via a function; as a result, overriding them has no effect at all. - - -Overload Operator via Rust Function ----------------------------------- - -Operator functions cannot be defined as a script function (because operators syntax are not valid function names). - -However, operator functions _can_ be registered to the [`Engine`] via the methods -`Engine::register_fn`, `Engine::register_result_fn` etc. - -When a custom operator function is registered with the same name as an operator, it _overrides_ the built-in version. - -```rust -use rhai::{Engine, EvalAltResult, RegisterFn}; - -let mut engine = Engine::new(); - -fn strange_add(a: i64, b: i64) -> i64 { (a + b) * 42 } - -engine.register_fn("+", strange_add); // overload '+' operator for two integers! - -let result: i64 = engine.eval("1 + 0"); // the overloading version is used - -result == 42; - -let result: f64 = engine.eval("1.0 + 0.0"); // '+' operator for two floats not overloaded - -result == 1.0; - -fn mixed_add(a: i64, b: f64) -> f64 { (a as f64) + b } - -engine.register_fn("+", mixed_add); // register '+' operator for an integer and a float - -let result: i64 = engine.eval("1 + 1.0"); // <- normally an error... - -result == 2.0; // ... but not now -``` - - -Considerations --------------- - -Normally, use operator overloading for [custom types] only. - -Be very careful when overriding built-in operators because script authors expect standard operators to behave in a -consistent and predictable manner, and will be annoyed if a calculation for '`+`' turns into a subtraction, for example. - -Operator overloading also impacts script optimization when using [`OptimizationLevel::Full`]. -See the [script-optimization] for more details. diff --git a/doc/src/rust/override.md b/doc/src/rust/override.md deleted file mode 100644 index 7620bfd5..00000000 --- a/doc/src/rust/override.md +++ /dev/null @@ -1,22 +0,0 @@ -Override a Built-in Function -=========================== - -{{#include ../links.md}} - -Any similarly-named function defined in a script _overrides_ any built-in or registered -native Rust function of the same name and number of parameters. - -```rust -// Override the built-in function 'to_float' when called as a method -fn to_float() { - print("Ha! Gotcha! " + this); - 42.0 -} - -let x = 123.to_float(); - -print(x); // what happens? -``` - -A registered native Rust function, in turn, overrides any built-in function of the -same name, number and types of parameters. diff --git a/doc/src/rust/packages/builtin.md b/doc/src/rust/packages/builtin.md deleted file mode 100644 index a9b07b6c..00000000 --- a/doc/src/rust/packages/builtin.md +++ /dev/null @@ -1,40 +0,0 @@ -Built-In Packages -================ - -{{#include ../../links.md}} - -`Engine::new` creates an [`Engine`] with the `StandardPackage` loaded. - -`Engine::new_raw` creates an [`Engine`] with _no_ package loaded. - -| Package | Description | In `Core` | In `Standard` | -| ---------------------- | ------------------------------------------------------------------------------------------------------ | :-------: | :-----------: | -| `ArithmeticPackage` | arithmetic operators (e.g. `+`, `-`, `*`, `/`) for numeric types that are not built in (e.g. `u16`) | yes | yes | -| `BasicIteratorPackage` | numeric ranges (e.g. `range(1, 10)`) | yes | yes | -| `LogicPackage` | logical and comparison operators (e.g. `==`, `>`) for numeric types that are not built in (e.g. `u16`) | yes | yes | -| `BasicStringPackage` | basic string functions (e.g. `print`, `debug`, `len`) that are not built in | yes | yes | -| `BasicTimePackage` | basic time functions (e.g. [timestamps]) | yes | yes | -| `MoreStringPackage` | additional string functions, including converting common types to string | no | yes | -| `BasicMathPackage` | basic math functions (e.g. `sin`, `sqrt`) | no | yes | -| `BasicArrayPackage` | basic [array] functions (not available under `no_index`) | no | yes | -| `BasicMapPackage` | basic [object map] functions (not available under `no_object`) | no | yes | -| `BasicFnPackage` | basic methods for [function pointers]. | yes | yes | -| `CorePackage` | basic essentials | yes | yes | -| `StandardPackage` | standard library (default for `Engine::new`) | no | yes | - - -`CorePackage` -------------- - -If only minimal functionalities are required, register the `CorePackage` instead: - -```rust -use rhai::Engine; -use rhai::packages::{Package, CorePackage}; - -let mut engine = Engine::new_raw(); -let package = CorePackage::new(); - -// Register the package into the 'Engine' by converting it into a shared module. -engine.register_global_module(package.as_shared_module()); -``` diff --git a/doc/src/rust/packages/create.md b/doc/src/rust/packages/create.md deleted file mode 100644 index b02fe61d..00000000 --- a/doc/src/rust/packages/create.md +++ /dev/null @@ -1,130 +0,0 @@ -Create a Custom Package -======================= - -{{#include ../../links.md}} - - -The macro `def_package!` can be used to create a custom [package]. - -A custom package can aggregate many other packages into a single self-contained unit. -More functions can be added on top of others. - - -`def_package!` --------------- - -> `def_package!(root:package_name:description, variable, block)` - -where: - -| Parameter | Description | -| :------------: | ----------------------------------------------------------------------------------------------- | -| `root` | root namespace, usually `rhai` | -| `package_name` | name of the package, usually ending in `...Package` | -| `description` | doc-comment for the package | -| `variable` | a variable name holding a reference to the [module] (`&mut Module`) that is to form the package | -| `block` | a code block that initializes the package | - - -Examples --------- - -```rust -// Import necessary types and traits. -use rhai::{ - def_package, // 'def_package!' macro - packages::Package, // 'Package' trait - packages::{ // pre-defined packages - ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage - } -}; - -// Define the package 'MyPackage'. -def_package!(rhai:MyPackage:"My own personal super package", module, { - // Aggregate other packages simply by calling 'init' on each. - ArithmeticPackage::init(module); - LogicPackage::init(module); - BasicArrayPackage::init(module); - BasicMapPackage::init(module); - - // Register additional Rust functions using the standard 'set_fn_XXX' module API. - let hash = module.set_fn_1("foo", |s: ImmutableString| { - Ok(foo(s.into_owned())) - }); - - // Remember to update the parameter names/types and return type metadata. - // 'set_fn_XXX' by default does not set function metadata. - module.update_fn_metadata(hash, ["s: ImmutableString", "i64"]); -}); -``` - - -Create a Custom Package from a Plugin Module -------------------------------------------- - -By far the easiest way to create a custom module is to call `plugin::combine_with_exported_module!` -from within `def_package!` which simply merges in all the functions defined within a [plugin module]. - -In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented. - -Due to specific requirements of a [package], `plugin::combine_with_exported_module!` -_flattens_ all sub-modules (i.e. all functions and [type iterators] defined within sub-modules -are pulled up to the top level instead) and so there will not be any sub-modules added to the package. - -Variables in the [plugin module] are ignored. - -```rust -// Import necessary types and traits. -use rhai::{ - def_package, - packages::Package, - packages::{ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage} -}; -use rhai::plugin::*; - -// Define plugin module. -#[export_module] -mod my_module { - pub const MY_NUMBER: i64 = 42; - - pub fn greet(name: &str) -> String { - format!("hello, {}!", name) - } - pub fn get_num() -> i64 { - 42 - } - - // This is a sub-module, but if using combine_with_exported_module!, it will - // be flattened and all functions registered at the top level. - pub mod my_sub_module { - pub fn get_sub_num() -> i64 { - 0 - } - } -} - -// Define the package 'MyPackage'. -def_package!(rhai:MyPackage:"My own personal super package", module, { - // Aggregate other packages simply by calling 'init' on each. - ArithmeticPackage::init(module); - LogicPackage::init(module); - BasicArrayPackage::init(module); - BasicMapPackage::init(module); - - // Merge all registered functions and constants from the plugin module into the custom package. - // - // The sub-module 'my_sub_module' is flattened and its functions registered at the top level. - // - // The text string name in the second parameter can be anything and is reserved for future use; - // it is recommended to be an ID string that uniquely identifies the plugin module. - // - // The constant variable, 'MY_NUMBER', is ignored. - // - // This call ends up registering three functions at the top level of the package: - // 1) greet - // 2) get_num - // 3) get_sub_num (pulled up from 'my_sub_module') - // - combine_with_exported_module!(module, "my-functions", my_module)); -}); -``` diff --git a/doc/src/rust/packages/index.md b/doc/src/rust/packages/index.md deleted file mode 100644 index afbba8cf..00000000 --- a/doc/src/rust/packages/index.md +++ /dev/null @@ -1,58 +0,0 @@ -Packages -======== - -{{#include ../../links.md}} - -The built-in library of Rhai is provided as various _packages_ that can be -turned into _shared_ [modules], which in turn can be registered into the -_global namespace_ of an [`Engine`] via `Engine::register_global_module`. - -Packages reside under `rhai::packages::*` and the trait `rhai::packages::Package` -must be loaded in order for packages to be used. - -### Packages _are_ Modules - -Internally, a _package_ is a _newtype_ wrapping a pre-defined [module], -with some conveniences to make it easier to define and use as a standard -_library_ for an [`Engine`]. - -Packages typically contain Rust functions that are callable within a Rhai script. -All _top-level_ functions in a package are available under the _global namespace_ -(i.e. they're available without namespace qualifiers). - -Sub-modules and variables are ignored in packages. - - -Share a Package Among Multiple `Engine`'s ----------------------------------------- - -`Engine::register_global_module` and `Engine::register_static_module` both require _shared_ [modules]. - -Once a package is created (e.g. via `Package::new`), it can create _shared_ [modules] -(via `Package::as_shared_module`) and register them into multiple instances of [`Engine`], -even across threads (under the [`sync`] feature). - -Therefore, a package only has to be created _once_ and essentially shared among multiple -[`Engine`] instances. This is particular useful when spawning large number of [raw `Engine`'s][raw `Engine`]. - -```rust -use rhai::Engine; -use rhai::packages::Package // load the 'Package' trait to use packages -use rhai::packages::CorePackage; // the 'core' package contains basic functionalities (e.g. arithmetic) - -// Create a package - can be shared among multiple 'Engine' instances -let package = CorePackage::new(); - -let mut engines_collection: Vec = Vec::new(); - -// Create 100 'raw' Engines -for _ in 0..100 { - let mut engine = Engine::new_raw(); - - // Register the package into the global namespace. - // 'Package::as_shared_module' converts the package into a shared module. - engine.register_global_module(package.as_shared_module()); - - engines_collection.push(engine); -} -``` diff --git a/doc/src/rust/print-custom.md b/doc/src/rust/print-custom.md deleted file mode 100644 index c013559b..00000000 --- a/doc/src/rust/print-custom.md +++ /dev/null @@ -1,18 +0,0 @@ -Printing for Custom Types -======================== - -{{#include ../links.md}} - -To use custom types for [`print`] and [`debug`], or convert its value into a [string], -it is necessary that the following functions be registered (assuming the custom type -is `T: Display + Debug`): - -| Function | Signature | Typical implementation | Usage | -| ----------- | ---------------------------------------------- | ---------------------------- | -------------------------------------------------------------------- | -| `to_string` | \|x: &mut T\| -> String | `x.to_string()` | converts the custom type into a [string] | -| `print` | \|x: &mut T\| -> String | `x.to_string()` | converts the custom type into a [string] for the [`print`] statement | -| `to_debug` | \|x: &mut T\| -> String | `format!("{:?}", x)` | converts the custom type into a [string] in debug format | -| `debug` | \|x: &mut T\| -> String | `format!("{:?}", x)` | converts the custom type into a [string] for the [`debug`] statement | -| `+` | \|s: &str, x: T\| -> String | `format!("{}{}", s, x)` | concatenates the custom type with another [string] | -| `+` | \|x: &mut T, s: &str\| -> String | `x.to_string().push_str(s);` | concatenates another [string] with the custom type | -| `+=` | \|s: &mut ImmutableString, x: T\| | `s += x.to_string()` | appends the custom type to an existing [string] | diff --git a/doc/src/rust/register-raw.md b/doc/src/rust/register-raw.md deleted file mode 100644 index 7b7566f7..00000000 --- a/doc/src/rust/register-raw.md +++ /dev/null @@ -1,189 +0,0 @@ -Use the Low-Level API to Register a Rust Function -================================================ - -{{#include ../links.md}} - -When a native Rust function is registered with an `Engine` using the `Engine::register_XXX` API, -Rhai transparently converts all function arguments from [`Dynamic`] into the correct types before -calling the function. - -For more power and flexibility, there is a _low-level_ API to work directly with [`Dynamic`] values -without the conversions. - - -Raw Function Registration -------------------------- - -The `Engine::register_raw_fn` method is marked _volatile_, meaning that it may be changed without warning. - -If this is acceptable, then using this method to register a Rust function opens up more opportunities. - -In particular, a the current _native call context_ (in form of the `NativeCallContext` type) is passed as an argument. -`NativeCallContext` exposes the current [`Engine`], among others, so the Rust function can also use [`Engine`] facilities -(such as evaluating a script). - -```rust -engine.register_raw_fn( - "increment_by", // function name - &[ // a slice containing parameter types - std::any::TypeId::of::(), // type of first parameter - std::any::TypeId::of::() // type of second parameter - ], - |context, args| { // fixed function signature - // Arguments are guaranteed to be correct in number and of the correct types. - - // But remember this is Rust, so you can keep only one mutable reference at any one time! - // Therefore, get a '&mut' reference to the first argument _last_. - // Alternatively, use `args.split_first_mut()` etc. to split the slice first. - - let y = *args[1].read_lock::().unwrap(); // get a reference to the second argument - // then copy it because it is a primary type - - let y = std::mem::take(args[1]).cast::(); // alternatively, directly 'consume' it - - let x = args[0].write_lock::().unwrap(); // get a '&mut' reference to the first argument - - *x += y; // perform the action - - Ok(Dynamic::UNIT) // must be 'Result>' - } -); - -// The above is the same as (in fact, internally they are equivalent): - -engine.register_fn("increment_by", |x: &mut i64, y: i64| *x += y); -``` - - -Function Signature ------------------- - -The function signature passed to `Engine::register_raw_fn` takes the following form: - -> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic])` -> `-> Result> + 'static` - -where: - -| Parameter | Type | Description | -| -------------------------- | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `T` | `impl Clone` | return type of the function | -| `context` | `NativeCallContext` | the current _native call context_ | -| • `engine()` | `&Engine` | the current [`Engine`], with all configurations and settings.
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. | -| • `source()` | `Option<&str>` | reference to the current source, if any | -| • `iter_imports()` | `impl Iterator` | iterator of the current stack of [modules] imported via `import` statements | -| • `imports()` | `&Imports` | reference to the current stack of [modules] imported via `import` statements; requires the [`internals`] feature | -| • `iter_namespaces()` | `impl Iterator` | iterator of the namespaces (as [modules]) containing all script-defined functions | -| • `namespaces()` | `&[&Module]` | reference to the namespaces (as [modules]) containing all script-defined functions; requires the [`internals`] feature | -| `args` | `&mut [&mut Dynamic]` | a slice containing `&mut` references to [`Dynamic`] values.
The slice is guaranteed to contain enough arguments _of the correct types_. | - -### Return value - -The return value is the result of the function call. - -Remember, in Rhai, all arguments _except_ the _first_ one are always passed by _value_ (i.e. cloned). -Therefore, it is unnecessary to ever mutate any argument except the first one, as all mutations -will be on the cloned copy. - - -Extract Arguments ------------------ - -To extract an argument from the `args` parameter (`&mut [&mut Dynamic]`), use the following: - -| Argument type | Access (`n` = argument position) | Result | -| ------------------------------ | ------------------------------------- | ----------------------------------------------------- | -| [Primary type][standard types] | `args[n].clone().cast::()` | copy of value | -| [Custom type] | `args[n].read_lock::().unwrap()` | immutable reference to value | -| [Custom type] (consumed) | `std::mem::take(args[n]).cast::()` | the _consumed_ value; the original value becomes `()` | -| `this` object | `args[0].write_lock::().unwrap()` | mutable reference to value | - -When there is a mutable reference to the `this` object (i.e. the first argument), -there can be no other immutable references to `args`, otherwise the Rust borrow checker will complain. - - -Example – Passing a Callback to a Rust Function ----------------------------------------------------- - -The low-level API is useful when there is a need to interact with the scripting [`Engine`] -within a function. - -The following example registers a function that takes a [function pointer] as an argument, -then calls it within the same [`Engine`]. This way, a _callback_ function can be provided -to a native Rust function. - -```rust -use rhai::{Engine, FnPtr}; - -let mut engine = Engine::new(); - -// Register a Rust function -engine.register_raw_fn( - "bar", - &[ - std::any::TypeId::of::(), // parameter types - std::any::TypeId::of::(), - std::any::TypeId::of::(), - ], - |context, args| { - // 'args' is guaranteed to contain enough arguments of the correct types - - let fp = std::mem::take(args[1]).cast::(); // 2nd argument - function pointer - let value = args[2].clone(); // 3rd argument - function argument - let this_ptr = args.get_mut(0).unwrap(); // 1st argument - this pointer - - // Use 'FnPtr::call_dynamic' to call the function pointer. - // Beware, private script-defined functions will not be found. - fp.call_dynamic(context, Some(this_ptr), [value]) - }, -); - -let result = engine.eval::( - r#" - fn foo(x) { this += x; } // script-defined function 'foo' - - let x = 41; // object - x.bar(Fn("foo"), 1); // pass 'foo' as function pointer - x - "#)?; -``` - - -TL;DR – Why `read_lock` and `write_lock` ---------------------------------------------- - -The `Dynamic` API that casts it to a reference to a particular data type is `read_lock` -(for an immutable reference) and `write_lock` (for a mutable reference). - -As the naming shows, something is _locked_ in order to allow this access, and that something -is a _shared value_ created by [capturing][automatic currying] variables from [closures]. - -Shared values are implemented as `Rc>` (`Arc>` under [`sync`]). - -If the value is _not_ a shared value, or if running under [`no_closure`] where there is -no [capturing][automatic currying], this API de-sugars to a simple `Dynamic::downcast_ref` and -`Dynamic::downcast_mut`. In other words, there is no locking and reference counting overhead -for the vast majority of non-shared values. - -If the value is a shared value, then it is first locked and the returned lock guard -then allows access to the underlying value in the specified type. - - -Hold Multiple References ------------------------- - -In order to access a value argument that is expensive to clone _while_ holding a mutable reference -to the first argument, either _consume_ that argument via `mem::take` as above, or use `args.split_first` -to partition the slice: - -```rust -// Partition the slice -let (first, rest) = args.split_first_mut().unwrap(); - -// Mutable reference to the first parameter -let this_ptr = &mut *first.write_lock::().unwrap(); - -// Immutable reference to the second value parameter -// This can be mutable but there is no point because the parameter is passed by value -let value_ref = &*rest[0].read_lock::().unwrap(); -``` diff --git a/doc/src/rust/serde.md b/doc/src/rust/serde.md deleted file mode 100644 index 38ef690a..00000000 --- a/doc/src/rust/serde.md +++ /dev/null @@ -1,126 +0,0 @@ -Serialization and Deserialization of `Dynamic` with `serde` -========================================================= - -{{#include ../links.md}} - -Rhai's [`Dynamic`] type supports serialization and deserialization by [`serde`](https://crates.io/crates/serde) -via the [`serde`][features] feature. - -A [`Dynamic`] can be seamlessly converted to and from a type that implements -[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) and/or -[`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html). - - -Serialization -------------- - -The function `rhai::serde::to_dynamic` automatically converts any Rust type that implements -[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) into a [`Dynamic`]. - -This is usually not necessary because using [`Dynamic::from`][`Dynamic`] is much easier and is essentially -the same thing. The only difference is treatment for integer values. `Dynamic::from` will keep the different -integer types intact, while `rhai::serde::to_dynamic` will convert them all into [`INT`][standard types] -(i.e. the system integer type which is `i64` or `i32` depending on the [`only_i32`] feature). - -In particular, Rust `struct`'s (or any type that is marked as a `serde` map) are converted into [object maps] -while Rust `Vec`'s (or any type that is marked as a `serde` sequence) are converted into [arrays]. - -While it is also simple to serialize a Rust type to `JSON` via `serde`, -then use [`Engine::parse_json`]({{rootUrl}}/language/json.md) to convert it into an [object map], -`rhai::serde::to_dynamic` serializes it to [`Dynamic`] directly via `serde` without going through the `JSON` step. - -```rust -use rhai::{Dynamic, Map}; -use rhai::serde::to_dynamic; - -#[derive(Debug, serde::Serialize)] -struct Point { - x: f64, - y: f64 -} - -#[derive(Debug, serde::Serialize)] -struct MyStruct { - a: i64, - b: Vec, - c: bool, - d: Point -} - -let x = MyStruct { - a: 42, - b: vec![ "hello".into(), "world".into() ], - c: true, - d: Point { x: 123.456, y: 999.0 } -}; - -// Convert the 'MyStruct' into a 'Dynamic' -let map: Dynamic = to_dynamic(x); - -map.is::() == true; -``` - - -Deserialization ---------------- - -The function `rhai::serde::from_dynamic` automatically converts a [`Dynamic`] value into any Rust type -that implements [`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html). - -In particular, [object maps] are converted into Rust `struct`'s (or any type that is marked as -a `serde` map) while [arrays] are converted into Rust `Vec`'s (or any type that is marked -as a `serde` sequence). - -```rust -use rhai::{Engine, Dynamic}; -use rhai::serde::from_dynamic; - -#[derive(Debug, serde::Deserialize)] -struct Point { - x: f64, - y: f64 -} - -#[derive(Debug, serde::Deserialize)] -struct MyStruct { - a: i64, - b: Vec, - c: bool, - d: Point -} - -let engine = Engine::new(); - -let result: Dynamic = engine.eval(r#" - ##{ - a: 42, - b: [ "hello", "world" ], - c: true, - d: #{ x: 123.456, y: 999.0 } - } - "#)?; - -// Convert the 'Dynamic' object map into 'MyStruct' -let x: MyStruct = from_dynamic(&result)?; -``` - - -Cannot Deserialize Shared Values -------------------------------- - -A [`Dynamic`] containing a _shared_ value cannot be deserialized – i.e. it will give a type error. - -Use `Dynamic::flatten` to obtain a cloned copy before deserialization -(if the value is not shared, it is simply returned and not cloned). - -Shared values are turned off via the [`no_closure`] feature. - - -Lighter Alternative -------------------- - -The [`serde`](https://crates.io/crates/serde) crate is quite heavy. - -If only _simple_ JSON parsing (i.e. only deserialization) of a hash object into a Rhai [object map] is required, -the [`Engine::parse_json`]({{rootUrl}}/language/json.md}}) method is available as a _cheap_ alternative, -but it does not provide the same level of correctness, nor are there any configurable options. diff --git a/doc/src/rust/strings.md b/doc/src/rust/strings.md deleted file mode 100644 index 737bb207..00000000 --- a/doc/src/rust/strings.md +++ /dev/null @@ -1,43 +0,0 @@ -`String` Parameters in Rust Functions -==================================== - -{{#include ../links.md}} - - -Avoid `String` --------------- - -As must as possible, avoid using `String` parameters in functions. - -Each `String` argument is cloned during every single call to that function – and the copy -immediately thrown away right after the call. - -Needless to say, it is _extremely_ inefficient to use `String` parameters. - - -`&str` Maps to `ImmutableString` -------------------------------- - -Rust functions accepting parameters of `String` should use `&str` instead because it maps directly to -[`ImmutableString`][string] which is the type that Rhai uses to represent [strings] internally. - -The parameter type `String` involves always converting an [`ImmutableString`][string] into a `String` -which mandates cloning it. - -Using `ImmutableString` or `&str` is much more efficient. -A common mistake made by novice Rhai users is to register functions with `String` parameters. - -```rust -fn get_len1(s: String) -> i64 { s.len() as i64 } // <- Very inefficient!!! -fn get_len2(s: &str) -> i64 { s.len() as i64 } // <- This is better -fn get_len3(s: ImmutableString) -> i64 { s.len() as i64 } // <- the above is equivalent to this - -engine - .register_fn("len1", get_len1) - .register_fn("len2", get_len2) - .register_fn("len3", get_len3); - -let len = engine.eval::("x.len1()")?; // 'x' is cloned, very inefficient! -let len = engine.eval::("x.len2()")?; // 'x' is shared -let len = engine.eval::("x.len3()")?; // 'x' is shared -``` diff --git a/doc/src/rust/traits.md b/doc/src/rust/traits.md deleted file mode 100644 index a9b1a297..00000000 --- a/doc/src/rust/traits.md +++ /dev/null @@ -1,14 +0,0 @@ -Traits -====== - -{{#include ../links.md}} - -A number of traits, under the `rhai::` module namespace, provide additional functionalities. - -| Trait | Description | Methods | -| ------------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------- | -| `RegisterFn` | trait for registering functions | `register_fn` | -| `RegisterResultFn` | trait for registering [fallible functions] | `register_result_fn` | -| `Func` | trait for creating Rust closures from script | `create_from_ast`, `create_from_script` | -| `ModuleResolver` | trait implemented by [module resolution][module resolver] services | `resolve` | -| `plugin::PluginFunction` | trait implemented by [plugin] functions | `call`, `is_method_call`, `is_variadic`, `clone_boxed`, `input_types` | diff --git a/doc/src/safety/checked.md b/doc/src/safety/checked.md deleted file mode 100644 index e16164b0..00000000 --- a/doc/src/safety/checked.md +++ /dev/null @@ -1,11 +0,0 @@ -Checked Arithmetic -================= - -{{#include ../links.md}} - -By default, all arithmetic calculations in Rhai are _checked_, meaning that the script terminates -with an error whenever it detects a numeric over-flow/under-flow condition or an invalid -floating-point operation, instead of crashing the entire system. - -This checking can be turned off via the [`unchecked`] feature for higher performance -(but higher risks as well). diff --git a/doc/src/safety/index.md b/doc/src/safety/index.md deleted file mode 100644 index 6e4e8c1c..00000000 --- a/doc/src/safety/index.md +++ /dev/null @@ -1,45 +0,0 @@ -Safety and Protection Against DoS Attacks -======================================== - -{{#include ../links.md}} - -For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of -resources used by a script so that it does not consume more resources that it is allowed to. - -The most important resources to watch out for are: - -* **Memory**: A malicious script may continuously grow a [string], an [array] or [object map] until all memory is consumed. - - It may also create a large [array] or [object map] literal that exhausts all memory during parsing. - -* **CPU**: A malicious script may run an infinite tight loop that consumes all CPU cycles. - -* **Time**: A malicious script may run indefinitely, thereby blocking the calling system which is waiting for a result. - -* **Stack**: A malicious script may attempt an infinite recursive call that exhausts the call stack. - - Alternatively, it may create a degenerated deep expression with so many levels that the parser exhausts the call stack - when parsing the expression; or even deeply-nested statement blocks, if nested deep enough. - - Another way to cause a stack overflow is to load a [self-referencing module][`import`]. - -* **Overflows**: A malicious script may deliberately cause numeric over-flows and/or under-flows, divide by zero, and/or - create bad floating-point representations, in order to crash the system. - -* **Files**: A malicious script may continuously [`import`] an external module within an infinite loop, - thereby putting heavy load on the file-system (or even the network if the file is not local). - - Even when modules are not created from files, they still typically consume a lot of resources to load. - -* **Data**: A malicious script may attempt to read from and/or write to data that it does not own. If this happens, - it is a severe security breach and may put the entire system at risk. - - -`unchecked` ------------ - -All these safe-guards can be turned off via the [`unchecked`] feature, which disables all -safety checks (even fatal errors such as arithmetic overflows and division-by-zero). - -This will increase script evaluation performance, at the expense of having an erroneous -script able to panic the entire system. diff --git a/doc/src/safety/max-array-size.md b/doc/src/safety/max-array-size.md deleted file mode 100644 index a50a3745..00000000 --- a/doc/src/safety/max-array-size.md +++ /dev/null @@ -1,40 +0,0 @@ -Maximum Size of Arrays -===================== - -{{#include ../links.md}} - -Limit How Large Arrays Can Grow ------------------------------- - -Rhai by default does not limit how large an [array] can be. - -This can be changed via the `Engine::set_max_array_size` method, with zero being unlimited (the default). - -A script attempting to create an array literal larger than the maximum will terminate with a parse error. - -Any script operation that produces an array larger than the maximum also terminates the script with an error result. - -This check can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_array_size(500); // allow arrays only up to 500 items - -engine.set_max_array_size(0); // allow unlimited arrays -``` - - -Setting Maximum Size -------------------- - -Be conservative when setting a maximum limit and always consider the fact that a registered function may grow -an array's size without Rhai noticing until the very end. - -For instance, the built-in '`+`' operator for arrays concatenates two arrays together to form one larger array; -if both arrays are _slightly_ below the maximum size limit, the resultant array may be almost _twice_ the maximum size. - -As a malicious script may create a deeply-nested array which consumes huge amounts of memory while each individual -array still stays under the maximum size limit, Rhai also recursively adds up the sizes of all [strings], [arrays] -and [object maps] contained within each array to make sure that the _aggregate_ sizes of none of these data structures -exceed their respective maximum size limits (if any). diff --git a/doc/src/safety/max-call-stack.md b/doc/src/safety/max-call-stack.md deleted file mode 100644 index 7efb3c9d..00000000 --- a/doc/src/safety/max-call-stack.md +++ /dev/null @@ -1,31 +0,0 @@ -Maximum Call Stack Depth -======================= - -{{#include ../links.md}} - -Limit How Stack Usage by Scripts -------------------------------- - -Rhai by default limits function calls to a maximum depth of 128 levels (8 levels in debug build). - -This limit may be changed via the `Engine::set_max_call_levels` method. - -A script exceeding the maximum call stack depth will terminate with an error result. - -This check can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_call_levels(10); // allow only up to 10 levels of function calls - -engine.set_max_call_levels(0); // allow no function calls at all (max depth = zero) -``` - - -Setting Maximum Stack Depth --------------------------- - -When setting this limit, care must be also taken to the evaluation depth of each _statement_ -within a function. It is entirely possible for a malicious script to embed a recursive call deep -inside a nested expression or statement block (see [maximum statement depth]). diff --git a/doc/src/safety/max-map-size.md b/doc/src/safety/max-map-size.md deleted file mode 100644 index a980562b..00000000 --- a/doc/src/safety/max-map-size.md +++ /dev/null @@ -1,40 +0,0 @@ -Maximum Size of Object Maps -========================== - -{{#include ../links.md}} - -Limit How Large Object Maps Can Grow ------------------------------------ - -Rhai by default does not limit how large (i.e. the number of properties) an [object map] can be. - -This can be changed via the `Engine::set_max_map_size` method, with zero being unlimited (the default). - -A script attempting to create an object map literal with more properties than the maximum will terminate with a parse error. - -Any script operation that produces an object map with more properties than the maximum also terminates the script with an error result. - -This check can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_map_size(500); // allow object maps with only up to 500 properties - -engine.set_max_map_size(0); // allow unlimited object maps -``` - - -Setting Maximum Size -------------------- - -Be conservative when setting a maximum limit and always consider the fact that a registered function may grow -an object map's size without Rhai noticing until the very end. - -For instance, the built-in '`+`' operator for object maps concatenates two object maps together to form one larger object map; -if both object maps are _slightly_ below the maximum size limit, the resultant object map may be almost _twice_ the maximum size. - -As a malicious script may create a deeply-nested object map which consumes huge amounts of memory while each individual -object map still stays under the maximum size limit, Rhai also recursively adds up the sizes of all [strings], [arrays] -and [object maps] contained within each object map to make sure that the _aggregate_ sizes of none of these data structures -exceed their respective maximum size limits (if any). diff --git a/doc/src/safety/max-modules.md b/doc/src/safety/max-modules.md deleted file mode 100644 index adb1c133..00000000 --- a/doc/src/safety/max-modules.md +++ /dev/null @@ -1,26 +0,0 @@ -Maximum Number of Modules -======================== - -{{#include ../links.md}} - -Rhai by default does not limit how many [modules] can be loaded via [`import`] statements. - -This can be changed via the `Engine::set_max_modules` method. Notice that setting the maximum number -of modules to zero does _not_ indicate unlimited modules, but disallows loading any module altogether. - -A script attempting to load more than the maximum number of modules will terminate with an error result. - -This limit can also be used to stop [`import`-loops][`import`] (i.e. cycles of modules referring to each other). - -This check can be disabled via the [`unchecked`] feature for higher performance -(but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_modules(5); // allow loading only up to 5 modules - -engine.set_max_modules(0); // disallow loading any module (maximum = zero) - -engine.set_max_modules(1000); // set to a large number for effectively unlimited modules -``` diff --git a/doc/src/safety/max-operations.md b/doc/src/safety/max-operations.md deleted file mode 100644 index 86d85fc1..00000000 --- a/doc/src/safety/max-operations.md +++ /dev/null @@ -1,44 +0,0 @@ -Maximum Number of Operations -=========================== - -{{#include ../links.md}} - - -Limit How Long a Script Can Run ------------------------------- - -Rhai by default does not limit how much time or CPU a script consumes. - -This can be changed via the `Engine::set_max_operations` method, with zero being unlimited (the default). - -The _operations count_ is intended to be a very course-grained measurement of the amount of CPU that a script -has consumed, allowing the system to impose a hard upper limit on computing resources. - -A script exceeding the maximum operations count terminates with an error result. -This can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_operations(500); // allow only up to 500 operations for this script - -engine.set_max_operations(0); // allow unlimited operations -``` - - -What Does One _Operation_ Mean ------------------------------ - -The concept of one single _operation_ in Rhai is volatile – it roughly equals one expression node, -loading one variable/constant, one operator call, one iteration of a loop, or one function call etc. -with sub-expressions, statements and function calls executed inside these contexts accumulated on top. - -A good rule-of-thumb is that one simple non-trivial expression consumes on average 5-10 operations. - -One _operation_ can take an unspecified amount of time and real CPU cycles, depending on the particulars. -For example, loading a constant consumes very few CPU cycles, while calling an external Rust function, -though also counted as only one operation, may consume much more computing resources. - -To help visualize, think of an _operation_ as roughly equals to one _instruction_ of a hypothetical CPU -which includes _specialized_ instructions, such as _function call_, _load module_ etc., each taking up -one CPU cycle to execute. diff --git a/doc/src/safety/max-stmt-depth.md b/doc/src/safety/max-stmt-depth.md deleted file mode 100644 index e9749689..00000000 --- a/doc/src/safety/max-stmt-depth.md +++ /dev/null @@ -1,56 +0,0 @@ -Maximum Statement Depth -====================== - -{{#include ../links.md}} - -Limit How Deeply-Nested a Statement Can Be ------------------------------------------ - -Rhai by default limits statements and expressions nesting to a maximum depth of 128 -(which should be plenty) when they are at _global_ level, but only a depth of 32 -when they are within function bodies. - -For debug builds, these limits are set further downwards to 32 and 16 respectively. - -That is because it is possible to overflow the [`Engine`]'s stack when it tries to -recursively parse an extremely deeply-nested code stream. - -```rust -// The following, if long enough, can easily cause stack overflow during parsing. -let a = (1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(...)+1))))))))))); -``` - -This limit may be changed via the `Engine::set_max_expr_depths` method. - -There are two limits to set, one for the maximum depth at global level, and the other for function bodies. - -A script exceeding the maximum nesting depths will terminate with a parsing error. -The malicious [`AST`] will not be able to get past parsing in the first place. - -This check can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_expr_depths(50, 5); // allow nesting up to 50 layers of expressions/statements - // at global level, but only 5 inside functions -``` - -Beware that there may be multiple layers for a simple language construct, even though it may correspond -to only one AST node. That is because the Rhai _parser_ internally runs a recursive chain of function calls -and it is important that a malicious script does not panic the parser in the first place. - - -Beware of Recursion -------------------- - -_Functions_ are placed under stricter limits because of the multiplicative effect of _recursion_. - -A script can effectively call itself while deep inside an expression chain within the function body, -thereby overflowing the stack even when the level of recursion is within limit. - -In general, make sure that `C x ( 5 + F ) + S` layered calls do not cause a stack overflow, where: - -* `C` = maximum call stack depth, -* `F` = maximum statement depth for functions, -* `S` = maximum statement depth at global level. diff --git a/doc/src/safety/max-string-size.md b/doc/src/safety/max-string-size.md deleted file mode 100644 index c693af9c..00000000 --- a/doc/src/safety/max-string-size.md +++ /dev/null @@ -1,36 +0,0 @@ -Maximum Length of Strings -======================== - -{{#include ../links.md}} - -Limit How Long Strings Can Grow ------------------------------- - -Rhai by default does not limit how long a [string] can be. - -This can be changed via the `Engine::set_max_string_size` method, with zero being unlimited (the default). - -A script attempting to create a string literal longer than the maximum length will terminate with a parse error. - -Any script operation that produces a string longer than the maximum also terminates the script with an error result. - -This check can be disabled via the [`unchecked`] feature for higher performance (but higher risks as well). - -```rust -let mut engine = Engine::new(); - -engine.set_max_string_size(500); // allow strings only up to 500 bytes long (in UTF-8 format) - -engine.set_max_string_size(0); // allow unlimited string length -``` - - -Setting Maximum Length ---------------------- - -Be conservative when setting a maximum limit and always consider the fact that a registered function may grow -a string's length without Rhai noticing until the very end. - -For instance, the built-in '`+`' operator for strings concatenates two strings together to form one longer string; -if both strings are _slightly_ below the maximum length limit, the resultant string may be almost _twice_ the maximum length. - diff --git a/doc/src/safety/progress.md b/doc/src/safety/progress.md deleted file mode 100644 index 749ac95b..00000000 --- a/doc/src/safety/progress.md +++ /dev/null @@ -1,52 +0,0 @@ -Track Progress and Force-Termination -=================================== - -{{#include ../links.md}} - -It is impossible to know when, or even whether, a script run will end -(a.k.a. the [Halting Problem](http://en.wikipedia.org/wiki/Halting_problem)). - -When dealing with third-party untrusted scripts that may be malicious, to track evaluation progress and -to force-terminate a script prematurely (for any reason), provide a closure to the [`Engine`] via -the `Engine::on_progress` method: - -```rust -let mut engine = Engine::new(); - -engine.on_progress(|count| { // parameter is number of operations already performed - if count % 1000 == 0 { - println!("{}", count); // print out a progress log every 1,000 operations - } - None // return 'None' to continue running the script - // return 'Some(token)' to immediately terminate the script -}); -``` - -The closure passed to `Engine::on_progress` will be called once for every operation. -Return `Some(token)` to terminate the script immediately, with the provided value -(any [`Dynamic`]) acting as a termination token. - - -Termination Token ------------------ - -The [`Dynamic`] value returned by the closure for `Engine::on_progress` is a _termination token_. -A script that is manually terminated returns with `Err(EvalAltResult::ErrorTerminated)` -wrapping this value. - -The termination token is commonly used to provide information on the _reason_ or _source_ -behind the termination decision. - -If the termination token is not needed, simply return `Some(Dynamic::UNIT)` to terminate the script -run with [`()`] as the token. - - -Operations Count vs. Progress Percentage ---------------------------------------- - -Notice that the _operations count_ value passed into the closure does not indicate the _percentage_ of work -already done by the script (and thus it is not real _progress_ tracking), because it is impossible to determine -how long a script may run. - -It is possible, however, to calculate this percentage based on an estimated total number of operations -for a typical run. diff --git a/doc/src/safety/sandbox.md b/doc/src/safety/sandbox.md deleted file mode 100644 index 798a73ac..00000000 --- a/doc/src/safety/sandbox.md +++ /dev/null @@ -1,39 +0,0 @@ -Sand-Boxing – Block Access to External Data -================================================ - -{{#include ../links.md}} - -Rhai is _sand-boxed_ so a script can never read from outside its own environment. - -Furthermore, an [`Engine`] created non-`mut` cannot mutate any state, including itself -(and therefore it is also _re-entrant_). - -It is highly recommended that [`Engine`]'s be created immutable as much as possible. - -```rust -let mut engine = Engine::new(); - -// Use the fluent API to configure an 'Engine' -engine.register_get("field", get_field) - .register_set("field", set_field) - .register_fn("do_work", action); - -// Then turn it into an immutable instance -let engine = engine; - -// 'engine' is immutable... -``` - - -Using Rhai to Control External Environment ------------------------------------------ - -How does a _sand-boxed_, immutable [`Engine`] control the external environment? -This is necessary in order to use Rhai as a _dynamic control layer_ over a Rust core system. - -There are two general patterns, both involving wrapping the external system -in a shared, interior-mutated object (e.g. `Rc>`): - -* [Control Layer]({{rootUrl}}/patterns/control.md) pattern. - -* [Singleton Command Object]({{rootUrl}}/patterns/singleton.md) pattern. diff --git a/doc/src/start/bin.md b/doc/src/start/bin.md deleted file mode 100644 index a053315d..00000000 --- a/doc/src/start/bin.md +++ /dev/null @@ -1,59 +0,0 @@ -Packaged Utilities -================== - -{{#include ../links.md}} - -A number of Rhai-driven utility programs can be found in the `src/bin` directory: - -| Utility program | Description | -| :-----------------------------------------------: | ----------------------------------------------------------- | -| [`rhai-repl`]({{repoTree}}/examples/rhai-repl.rs) | a simple REPL, interactively evaluate statements from stdin | -| [`rhai-run`]({{repoTree}}/examples/rhai-run.rs) | runs each filename passed to it as a Rhai script | - - -`rhai-repl` – The Rhai REPL Tool -------------------------------------- - -`rhai-repl` is a particularly useful utility program – it allows one to interactively -try out Rhai's language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop). - -Filenames passed to it as command line arguments are run and loaded before the REPL starts. - -### Example - -The following command first runs three scripts – `init1.rhai`, `init2.rhai` and -`init3.rhai` – loading the functions defined in each script into the _global_ -namespace. - -Then it enters an REPL, which can call the above functions freely. - -```bash -rhai-repl init1.rhai init2.rhai init3.rhai -``` - - -`rhai-run` – The Rhai Runner ---------------------------------- - -Use `rhai-run` to run Rhai scripts. - -Filenames passed to it as command line arguments are run in sequence. - -### Example - -The following command runs the scripts `script1.rhai`, `script2.rhai` and `script3.rhai` -in order. - -```bash -rhai-run script1.rhai script2.rhai script3.rhai -``` - - -Running a Utility Program -------------------------- - -Utilities can be run with the following command: - -```bash -cargo run --bin {program_name} -``` diff --git a/doc/src/start/builds/index.md b/doc/src/start/builds/index.md deleted file mode 100644 index a3cdfbf3..00000000 --- a/doc/src/start/builds/index.md +++ /dev/null @@ -1,7 +0,0 @@ -Special Builds -============== - -{{#include ../../links.md}} - -It is possible to mix-and-match various [features] of the Rhai crate to make -specialized builds with specific characteristics and behaviors. diff --git a/doc/src/start/builds/minimal.md b/doc/src/start/builds/minimal.md deleted file mode 100644 index c916baea..00000000 --- a/doc/src/start/builds/minimal.md +++ /dev/null @@ -1,54 +0,0 @@ -Minimal Build -============= - -{{#include ../../links.md}} - -Configuration -------------- - -In order to compile a _minimal_ build – i.e. a build optimized for size – perhaps for `no-std` embedded targets or for -compiling to [WASM], it is essential that the correct linker flags are used in `cargo.toml`: - -```toml -[profile.release] -lto = "fat" # turn on Link-Time Optimizations -codegen-units = 1 # trade compile time with maximum optimization -opt-level = "z" # optimize for size -``` - - -Use `i32` Only --------------- - -For embedded systems that must optimize for code size, the architecture is commonly 32-bit. -Use [`only_i32`] to prune away large sections of code implementing functions for other numeric types -(including `i64`). - -If, for some reason, 64-bit long integers must be supported, use [`only_i64`] instead of [`only_i32`]. - - -Opt-Out of Features ------------------- - -Opt out of as many features as possible, if they are not needed, to reduce code size because, remember, by default -all code is compiled into the final binary since what a script requires cannot be predicted. -If a language feature will never be needed, omitting it is a prudent strategy to optimize the build for size. - -Omitting arrays ([`no_index`]) yields the most code-size savings, followed by floating-point support -([`no_float`]), checked arithmetic/script resource limits ([`unchecked`]) and finally object maps and custom types ([`no_object`]). - -Where the usage scenario does not call for loading externally-defined modules, use [`no_module`] to save some bytes. -Disable script-defined functions ([`no_function`]) and possibly closures ([`no_closure`]) when the features are not needed. -Both of these have some code size savings but not much. - - -Use a Raw [`Engine`] -------------------- - -[`Engine::new_raw`][raw `Engine`] creates a _raw_ engine. -A _raw_ engine supports, out of the box, only a very [restricted set]({{rootUrl}}/engine/raw.md#built-in-operators) -of basic arithmetic and logical operators. - -Selectively include other necessary functionalities by picking specific [packages] to minimize the footprint. - -Packages are shared (even across threads via the [`sync`] feature), so they only have to be created once. diff --git a/doc/src/start/builds/no-std.md b/doc/src/start/builds/no-std.md deleted file mode 100644 index ce30ddb0..00000000 --- a/doc/src/start/builds/no-std.md +++ /dev/null @@ -1,79 +0,0 @@ -`no-std` Build -============= - -{{#include ../../links.md}} - -The feature [`no_std`] automatically converts the scripting engine into a `no-std` build. - -Usually, a `no-std` build goes hand-in-hand with [minimal builds] because typical embedded -hardware (the primary target for `no-std`) has limited storage. - - -Nightly Required ----------------- - -Currently, [`no_std`] requires the nightly compiler due to the crates that it uses. - - -Implementation --------------- - -Rhai allocates, so the first thing that must be included in any `no-std` project is -an allocator crate, such as [`wee_alloc`](https://crates.io/crates/wee_alloc). - -Then there is the need to set up proper error/panic handlers. -The following example uses `panic = "abort"` and `wee_alloc` as the allocator. - -```rust -// Set up for no-std. -#![no_std] - -// The following no-std features are usually needed. -#![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)] - -// Set up the global allocator. -extern crate alloc; -extern crate wee_alloc; - -#[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; - -// Rust needs a CRT runtime on Windows when compiled with MSVC. -#[cfg(all(windows, target_env = "msvc"))] -#[link(name = "msvcrt")] -#[link(name = "libcmt")] -extern {} - -// Set up panic and error handlers -#[alloc_error_handler] -fn err_handler(_: core::alloc::Layout) -> ! { - core::intrinsics::abort(); -} - -#[panic_handler] -#[lang = "panic_impl"] -extern "C" fn rust_begin_panic(_: &core::panic::PanicInfo) -> ! { - core::intrinsics::abort(); -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} - -#[no_mangle] -extern "C" fn rust_eh_register_frames() {} - -#[no_mangle] -extern "C" fn rust_eh_unregister_frames() {} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - // ... main program ... -} -``` - - -Samples -------- - -Check out the [`no-std` sample applications](../examples/rust.md#no-std-samples) -for different operating environments. diff --git a/doc/src/start/builds/performance.md b/doc/src/start/builds/performance.md deleted file mode 100644 index 859e1782..00000000 --- a/doc/src/start/builds/performance.md +++ /dev/null @@ -1,61 +0,0 @@ -Performance Build -================= - -{{#include ../../links.md}} - -Some features are for performance. For example, using [`only_i32`] or [`only_i64`] disables all other integer types (such as `u16`). - - -Use Only One Integer Type ------------------------- - -If only a single integer type is needed in scripts – most of the time this is the case – it is best to avoid registering -lots of functions related to other integer types that will never be used. As a result, [`Engine`] creation will be faster -because fewer functions need to be loaded. - -The [`only_i32`] and [`only_i64`] features disable all integer types except `i32` or `i64` respectively. - - -Use Only 32-Bit Numbers ----------------------- - -If only 32-bit integers are needed – again, most of the time this is the case – turn on [`only_i32`]. -Under this feature, only `i32` is supported as a built-in integer type and no others. - -On 64-bit targets this may not gain much, but on certain 32-bit targets this improves performance -due to 64-bit arithmetic requiring more CPU cycles to complete. - - -Minimize Size of `Dynamic` -------------------------- - -Turning on [`no_float`] or [`f32_float`] and [`only_i32`] on 32-bit targets makes the critical [`Dynamic`] -data type only 8 bytes long. -Normally [`Dynamic`] can be up to 12-16 bytes in order to hold an `i64` or `f64`. - -A small [`Dynamic`] helps performance due to better cache efficiency. - - -Use `ImmutableString` --------------------- - -Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type. This is mainly to avoid excessive -cloning when passing function arguments. - -Rhai's internal string type is `ImmutableString` (basically `Rc` or `Arc` depending on the [`sync`] feature). -It is cheap to clone, but expensive to modify (a new copy of the string must be made in order to change it). - -Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (both map to `ImmutableString`) -for the best performance with Rhai. - - -Disable Closures ----------------- - -Support for [closures] that capture shared variables adds material overhead to script evaluation. - -This is because every data access must be checked whether it is a shared value and, if so, take a read -lock before reading it. - -Use [`no_closure`] to disable closure and capturing support to optimize the hot path -because there is no need to take locks for shared data. diff --git a/doc/src/start/builds/wasm.md b/doc/src/start/builds/wasm.md deleted file mode 100644 index 27b85e77..00000000 --- a/doc/src/start/builds/wasm.md +++ /dev/null @@ -1,55 +0,0 @@ -Building to WebAssembly (WASM) -============================= - -{{#include ../../links.md}} - -It is possible to use Rhai when compiling to WebAssembly (WASM). -This yields a scripting engine (and language) that can be run in a standard web browser. - -Why you would _want_ to is another matter... as there is already a nice, fast, complete scripting language -for the the common WASM environment (i.e. a browser) – and it is called JavaScript. - -But anyhow, do it because you _can_! - -When building for WASM, certain features will not be available, -such as the script file API's and loading modules from external script files. - - -Size ----- - -Also look into [minimal builds] to reduce generated WASM size. - -As of this version, a typical, full-featured Rhai scripting engine compiles to a single WASM file -less than 200KB gzipped. - -When excluding features that are marginal in WASM environment, the gzipped payload can be -further shrunk to 160KB. - - -Speed ------ - -In benchmark tests, a WASM build runs scripts roughly 1.7-2.2x slower than a native optimized release build. - - -Common Features ---------------- - -Some Rhai functionalities are not necessary in a WASM environment, so the following features -are typically used for a WASM build: - -| Feature | Description | -| :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`unchecked`] | When a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely – the web app must terminate it itself. | -| [`only_i32`] | WASM supports 32-bit and 64-bit integers, but most scripts will only need 32-bit. | -| [`f32_float`] | WASM supports 32-bit single-precision and 64-bit double-precision floating-point numbers, but single-precision is usually fine for most uses. | -| [`no_module`] | A WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts. | - -The following features are typically _not_ used because they don't make sense in a WASM build: - -| Feature | Why unnecessary | -| :-----------: | ------------------------------------------------------------------------------------------------------ | -| [`sync`] | WASM is single-threaded. | -| [`no_std`] | `std` lib works fine with WASM. | -| [`internals`] | WASM usually doesn't need to access Rhai internal data structures, unless you are walking the [`AST`]. | diff --git a/doc/src/start/examples/index.md b/doc/src/start/examples/index.md deleted file mode 100644 index 6af1495b..00000000 --- a/doc/src/start/examples/index.md +++ /dev/null @@ -1,7 +0,0 @@ -Examples -======== - -{{#include ../../links.md}} - -Rhai comes with a number of examples showing how to integrate the scripting [`Engine`] within -a Rust application, as well as a number of sample scripts that showcase different Rhai language features. diff --git a/doc/src/start/examples/rust.md b/doc/src/start/examples/rust.md deleted file mode 100644 index b46d7249..00000000 --- a/doc/src/start/examples/rust.md +++ /dev/null @@ -1,45 +0,0 @@ -Rust Examples -============ - -{{#include ../../links.md}} - -A number of examples can be found in the `examples` directory: - -| Example | Description | -| ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| [`arrays_and_structs`]({{repoTree}}/examples/arrays_and_structs.rs) | shows how to register a custom Rust type and using [arrays] on it | -| [`custom_types_and_methods`]({{repoTree}}/examples/custom_types_and_methods.rs) | shows how to register a custom Rust type and methods for it | -| [`hello`]({{repoTree}}/examples/hello.rs) | simple example that evaluates an expression and prints the result | -| [`reuse_scope`]({{repoTree}}/examples/reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common [`Scope`] | -| [`serde`]({{repoTree}}/examples/serde.rs) | example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde).
The [`serde`] feature is required to run | -| [`simple_fn`]({{repoTree}}/examples/simple_fn.rs) | shows how to register a simple function | -| [`strings`]({{repoTree}}/examples/strings.rs) | shows different ways to register functions taking string arguments | - - -Running Examples ----------------- - -Examples can be run with the following command: - -```bash -cargo run --example {example_name} -``` - -`no-std` Samples ----------------- - -To illustrate `no-std` builds, a number of sample applications are available under the `no_std` directory: - -| Sample | Description | Optimization | Allocator | Panics | -| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: | -| [`no_std_test`]({{repoTree}}/no_std/no_std_test) | bare-bones test application that evaluates a Rhai expression and sets the result as the return value | size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | abort | - -`cargo run` cannot be used to run a `no-std` sample. It must first be built: - -```bash -cd no_std/no_std_test - -cargo +nightly build --release - -./target/release/no_std_test -``` diff --git a/doc/src/start/examples/scripts.md b/doc/src/start/examples/scripts.md deleted file mode 100644 index 80fe4908..00000000 --- a/doc/src/start/examples/scripts.md +++ /dev/null @@ -1,53 +0,0 @@ -Example Scripts -============== - -{{#include ../../links.md}} - -Language Feature Scripts ------------------------ - -There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` directory: - -| Script | Description | -| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| [`array.rhai`]({{repoTree}}/scripts/array.rhai) | [arrays] | -| [`assignment.rhai`]({{repoTree}}/scripts/assignment.rhai) | variable declarations | -| [`comments.rhai`]({{repoTree}}/scripts/comments.rhai) | just comments | -| [`for1.rhai`]({{repoTree}}/scripts/for1.rhai) | [`for`]({{rootUrl}}/language/for.md) loops | -| [`for2.rhai`]({{repoTree}}/scripts/for2.rhai) | [`for`]({{rootUrl}}/language/for.md) loops on [arrays] | -| [`function_decl1.rhai`]({{repoTree}}/scripts/function_decl1.rhai) | a [function] without parameters | -| [`function_decl2.rhai`]({{repoTree}}/scripts/function_decl2.rhai) | a [function] with two parameters | -| [`function_decl3.rhai`]({{repoTree}}/scripts/function_decl3.rhai) | a [function] with many parameters | -| [`if1.rhai`]({{repoTree}}/scripts/if1.rhai) | [`if`]({{rootUrl}}/language/if.md) example | -| [`loop.rhai`]({{repoTree}}/scripts/loop.rhai) | count-down [`loop`]({{rootUrl}}/language/loop.md) in Rhai, emulating a `do` .. `while` loop | -| [`module.rhai`]({{repoTree}}/scripts/module.rhai) | import a script file as a module | -| [`oop.rhai`]({{repoTree}}/scripts/oop.rhai) | simulate [object-oriented programming (OOP)][OOP] with [closures] | -| [`op1.rhai`]({{repoTree}}/scripts/op1.rhai) | just simple addition | -| [`op2.rhai`]({{repoTree}}/scripts/op2.rhai) | simple addition and multiplication | -| [`op3.rhai`]({{repoTree}}/scripts/op3.rhai) | change evaluation order with parenthesis | -| [`string.rhai`]({{repoTree}}/scripts/string.rhai) | [string] operations | -| [`strings_map.rhai`]({{repoTree}}/scripts/strings_map.rhai) | [string] and [object map] operations | -| [`while.rhai`]({{repoTree}}/scripts/while.rhai) | [`while`]({{rootUrl}}/language/while.md) loop | - - -Benchmark Scripts ----------------- - -The following scripts are for benchmarking the speed of Rhai: - -| Scripts | Description | -| --------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| [`speed_test.rhai`]({{repoTree}}/scripts/speed_test.rhai) | a simple application to measure the speed of Rhai's interpreter (1 million iterations) | -| [`primes.rhai`]({{repoTree}}/scripts/primes.rhai) | use Sieve of Eratosthenes to find all primes smaller than a limit | -| [`fibonacci.rhai`]({{repoTree}}/scripts/fibonacci.rhai) | calculate the n-th Fibonacci number using a really dumb algorithm | -| [`mat_mul.rhai`]({{repoTree}}/scripts/mat_mul.rhai) | matrix multiplication test to measure the speed of multi-dimensional array access | - - -Running Example Scripts ----------------------- - -The [`rhai-run`](../bin.md) utility can be used to run Rhai scripts: - -```bash -cargo run --bin rhai-run scripts/any_script.rhai -``` diff --git a/doc/src/start/features.md b/doc/src/start/features.md deleted file mode 100644 index d1db695b..00000000 --- a/doc/src/start/features.md +++ /dev/null @@ -1,68 +0,0 @@ -Optional Features -================ - -{{#include ../links.md}} - -By default, Rhai includes all the standard functionalities in a small, tight package. - -Most features are here to opt-**out** of certain functionalities that are not needed. -Notice that this deviates from Rust norm where features are _additive_. - -Excluding unneeded functionalities can result in smaller, faster builds as well as -more control over what a script can (or cannot) do. - -| Feature | Additive? | Description | -| ------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `unchecked` | no | disables arithmetic checking (such as over-flows and division by zero), call stack depth limit, operations count limit and modules loading limit.
Beware that a bad script may panic the entire system! | -| `sync` | no | restricts all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync` | -| `no_optimize` | no | disables [script optimization] | -| `no_float` | no | disables floating-point numbers and math | -| `f32_float` | no | sets the system floating-point type to `f32` instead of `f64`. `FLOAT` is set to `f32` | -| `only_i32` | no | sets the system integer type to `i32` and disable all other integer types. `INT` is set to `i32` | -| `only_i64` | no | sets the system integer type to `i64` and disable all other integer types. `INT` is set to `i64` | -| `no_index` | no | disables [arrays] and indexing features | -| `no_object` | no | disables support for [custom types] and [object maps] | -| `no_function` | no | disables script-defined [functions] (implies `no_closure`) | -| `no_module` | no | disables loading external [modules] | -| `no_closure` | no | disables [capturing][automatic currying] external variables in [anonymous functions] to simulate _closures_, or [capturing the calling scope]({{rootUrl}}/language/fn-capture.md) in function calls | -| `no_std` | no | builds for `no-std` (implies `no_closure`). Notice that additional dependencies will be pulled in to replace `std` features | -| `serde` | yes | enables serialization/deserialization via `serde` (requires the [`serde`](https://crates.io/crates/serde) crate) | -| `unicode-xid-ident` | no | allows [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) as identifiers | -| `metadata` | yes | enables exporting [functions metadata] to [JSON format]({{rootUrl}}/engine/metadata/export_to_json.md) (implies `serde` and additionally requires the [`serde_json`](https://crates.io/crates/serde_json) crate) | -| `internals` | yes | exposes internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version | - - -Example -------- - -The `Cargo.toml` configuration below turns on these six features: - -* `sync` (everything `Send + Sync`) -* `unchecked` (disable all checking – should not be used with untrusted user scripts) -* `only_i32` (only 32-bit signed integers) -* `no_float` (no floating point numbers) -* `no_module` (no loading external [modules]) -* `no_function` (no defining [functions]) - -```toml -[dependencies] -rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] } -``` - -The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32`, `i16` or `i64`), -no floating-point, is `Send + Sync` (so it can be safely used across threads), and does not support defining [functions] -nor loading external [modules]. - -This configuration is perfect for an expression parser in a 32-bit embedded system without floating-point hardware. - - -Caveat – Features Are Not Additive ---------------------------------------- - -Most Rhai features are not strictly _additive_ – i.e. they do not only add optional functionalities. - -In fact, most features are _subtractive_ – i.e. they _remove_ functionalities. - -There is a reason for this design, because the _lack_ of a language feature by itself is a feature. - -See [here]({{rootUrl}}/patterns/multiple.md) for more details. diff --git a/doc/src/start/index.md b/doc/src/start/index.md deleted file mode 100644 index f89dfbd0..00000000 --- a/doc/src/start/index.md +++ /dev/null @@ -1,6 +0,0 @@ -Getting Started -=============== - -{{#include ../links.md}} - -This section shows how to install the Rhai crate into a Rust application. diff --git a/doc/src/start/install.md b/doc/src/start/install.md deleted file mode 100644 index 18b75223..00000000 --- a/doc/src/start/install.md +++ /dev/null @@ -1,30 +0,0 @@ -Install the Rhai Crate -===================== - -{{#include ../links.md}} - -In order to use Rhai in a project, the Rhai crate must first be made a dependency. - -The easiest way is to install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/), -starting by looking up the latest version and adding this line under `dependencies` in the project's `Cargo.toml`: - -```toml -[dependencies] -rhai = "{{version}}" # assuming {{version}} is the latest version -``` - -Or to automatically use the latest released crate version on [`crates.io`](https:/crates.io/crates/rhai/): - -```toml -[dependencies] -rhai = "*" -``` - -Crate versions are released on [`crates.io`](https:/crates.io/crates/rhai/) infrequently, -so to track the latest features, enhancements and bug fixes, pull directly from -[GitHub](https://github.com/rhaiscript/rhai): - -```toml -[dependencies] -rhai = { git = "https://github.com/rhaiscript/rhai" } -``` diff --git a/doc/src/start/playground.md b/doc/src/start/playground.md deleted file mode 100644 index 08809805..00000000 --- a/doc/src/start/playground.md +++ /dev/null @@ -1,10 +0,0 @@ -Online Playground -================= - -{{#include ../links.md}} - -Rhai provides an [online playground][playground] to try out its language and engine features -without having to install anything. - -The playground provides a syntax-highlighting script editor with example snippets. -Scripts can be evaluated directly from the editor. diff --git a/doc/src/tools/index.md b/doc/src/tools/index.md deleted file mode 100644 index 9b9eff01..00000000 --- a/doc/src/tools/index.md +++ /dev/null @@ -1,6 +0,0 @@ -External Tools -============== - -{{#include ../links.md}} - -External tools available to work with Rhai. diff --git a/doc/src/tools/playground.md b/doc/src/tools/playground.md deleted file mode 100644 index 91507a3d..00000000 --- a/doc/src/tools/playground.md +++ /dev/null @@ -1,15 +0,0 @@ -Online Playground -================= - -{{#include ../links.md}} - - -The Online Playground runs off a [WASM] build of Rhai and allows evaluating -Rhai scripts directly within a browser editor window. - - -Author : [`@alvinhochun`](https://github.com/alvinhochun) - -Repo : [On GitHub](https://github.com/alvinhochun/rhai-playground) - -URL : [Link to Online Playground][playground] diff --git a/doc/src/tools/rhai-doc.md b/doc/src/tools/rhai-doc.md deleted file mode 100644 index fd32be6a..00000000 --- a/doc/src/tools/rhai-doc.md +++ /dev/null @@ -1,6 +0,0 @@ -Rhai Script Documentation Tool -============================= - -{{#include ../links.md}} - -<< TODO >> \ No newline at end of file diff --git a/doc/theme/favicon.png b/doc/theme/favicon.png deleted file mode 100644 index f5cf9cac4e07a5a5d65d6b6d0607e08fa1159451..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1238 zcmV;{1S$K8P)-T#jd)wBule_LyR5GvSE{HSOb$IxF6ItXj3t{cFw32}6OpM&VIK z)APcU!qcmH&Ejq0P9+sv7Csg3*X4r3x0W6+^NYpFGJjdDM?zy@YZG=Qt2kc8N=nZN z%gb?R(go%BKGsW|iR@fhVvl$?1|fn3a52R=WB3`AzW8N$@G&4OYUF!M`LpCCSCLtx zh|UU0Qsn6uwIJ0K5>?R?GSU>S{{QW(p$_@V)tv!ocrwkmUT|!|_oiun9-8L&5!fH$ zB3sGN9l-Fr=$jSIy$`MHaCTYI;yZA@0bLJTOplc$ySPnN;q?SsqR?>-O^fB8{qA#o z50N$bsw>#tgFZRmy7U8vFK6^uLqgdA000SaNLh0L01FcU01FcV0GgZ_0008{NklA=YA=RILiSwArXA;vWz)z31Hbxp;3TE|lIe!BxK1yJznG-p6;obKk%g zwy*){o7ri7`{MLQIPAY3tiF1F+RV-YNIKHm`Nli{n}F(z=ca*kNcDL$AsuN=yg9Up zp#@aSN5_HBFf-s90MaBNV4}7At?R?^wT2a-@KXvmdAhFf{fgMH9A7Hjl;hN}d_y^q zKc2c5^j&>S2ip7I`=G8rdjRZGv+ch2zIShwauzv|KRUdte(>LjfN*eM9c+kL#Zz4m z{}mvA`1Gz#6QCTYW8u(__G1@+SNPA0gmTQr!a<9LgQoCVbi&In zqI$d_d_J9@90wSkS`v{U)~!zGC-2A8{9sfIP$VasdK9>)DYu#zR?Yf*q($Jw*vUVO zTCgFk&27`#%iZ#s`v;U|;9sB|c_Zhyumym>0HzX~gBPaeB>(^b07*qoM6N<$f;Nv^ AzyJUM diff --git a/doc/theme/favicon.svg b/doc/theme/favicon.svg deleted file mode 100644 index 4d5eaf02..00000000 --- a/doc/theme/favicon.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - From e527fc9e86f6d4677c61ac788194656ffde5b6a6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 7 Jan 2021 22:52:08 +0800 Subject: [PATCH 10/12] Remove doc/book from .gitignore. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index bdd52cb9..6eed6fee 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ target/ Cargo.lock .vscode/ .cargo/ -doc/book/ before* after* From ec18bd26a2cad01e0839b9ba0395af8a83370163 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 7 Jan 2021 22:52:20 +0800 Subject: [PATCH 11/12] Handle no-std without sync. --- src/stdlib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stdlib.rs b/src/stdlib.rs index 165b9068..0c0e0438 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -11,7 +11,10 @@ mod inner { #[cfg(not(target_arch = "wasm32"))] pub use core::{i128, u128}; - pub use alloc::{borrow, boxed, format, rc, string, sync, vec}; + #[cfg(feature = "sync")] + pub use alloc::sync; + + pub use alloc::{borrow, boxed, format, rc, string, vec}; pub use core_error as error; From b96c8321415318b7b081ba38d3bf7aa464836f9e Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 8 Jan 2021 14:29:57 +0800 Subject: [PATCH 12/12] Add EvalAltResult::clear_position(). --- RELEASES.md | 1 + src/bin/rhai-repl.rs | 7 +++---- src/bin/rhai-run.rs | 9 ++++----- src/result.rs | 5 +++++ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 517c82d0..c014d5e6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -16,6 +16,7 @@ Enhancements * Source information is provided when there is an error within a call to a function defined in another module. * Source information is provided to the `NativeCallContext` for native Rust functions. +* `EvalAltResult::clear_position` to clear the position information of an error - useful when only the message is needed and the position doesn't need to be printed out. Version 0.19.9 diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index d5d5c406..67f39957 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -11,9 +11,10 @@ use std::{ }; /// Pretty-print error. -fn print_error(input: &str, err: EvalAltResult) { +fn print_error(input: &str, mut err: EvalAltResult) { let lines: Vec<_> = input.trim().split('\n').collect(); let pos = err.position(); + err.clear_position(); let line_no = if lines.len() > 1 { if pos.is_none() { @@ -26,8 +27,6 @@ fn print_error(input: &str, err: EvalAltResult) { }; // Print error position - let pos_text = format!(" ({})", pos); - if pos.is_none() { // No position println!("{}", err); @@ -40,7 +39,7 @@ fn print_error(input: &str, err: EvalAltResult) { "{0:>1$} {2}", "^", line_no.len() + pos.position().unwrap(), - err.to_string().replace(&pos_text, "") + err ); } } diff --git a/src/bin/rhai-run.rs b/src/bin/rhai-run.rs index 4453f84b..24e60452 100644 --- a/src/bin/rhai-run.rs +++ b/src/bin/rhai-run.rs @@ -5,19 +5,17 @@ use rhai::OptimizationLevel; use std::{env, fs::File, io::Read, process::exit}; -fn eprint_error(input: &str, err: EvalAltResult) { - fn eprint_line(lines: &[&str], pos: Position, err: &str) { +fn eprint_error(input: &str, mut err: EvalAltResult) { + fn eprint_line(lines: &[&str], pos: Position, err_msg: &str) { let line = pos.line().unwrap(); - let line_no = format!("{}: ", line); - let pos_text = format!(" ({})", pos); eprintln!("{}{}", line_no, lines[line - 1]); eprintln!( "{:>1$} {2}", "^", line_no.len() + pos.position().unwrap(), - err.replace(&pos_text, "") + err_msg ); eprintln!(""); } @@ -26,6 +24,7 @@ fn eprint_error(input: &str, err: EvalAltResult) { // Print error let pos = err.position(); + err.clear_position(); if pos.is_none() { // No position diff --git a/src/result.rs b/src/result.rs index 0face85e..d0ca7e52 100644 --- a/src/result.rs +++ b/src/result.rs @@ -366,6 +366,11 @@ impl EvalAltResult { | Self::Return(_, pos) => *pos, } } + /// Clear the [position][Position] information of this error. + pub fn clear_position(&mut self) -> &mut Self { + self.set_position(Position::NONE); + self + } /// Override the [position][Position] of this error. pub fn set_position(&mut self, new_position: Position) { match self {