From c245fe88fdfba692fcb1c2e0ff48103776fae139 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 24 Jan 2021 21:21:15 +0800 Subject: [PATCH 1/9] Allow stacking ! operators. --- Cargo.toml | 3 ++- RELEASES.md | 1 + src/parser.rs | 2 +- tests/internal_fn.rs | 6 +++--- tests/not.rs | 3 +-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2b12fb19..4404a367 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,10 @@ license = "MIT OR Apache-2.0" include = [ "**/*.rs", "scripts/*.rhai", + "**/*.md", "Cargo.toml" ] -keywords = [ "scripting" ] +keywords = [ "scripting", "scripting-engine", "scripting language", "embedded" ] categories = [ "no-std", "embedded", "wasm", "parser-implementations" ] [dependencies] diff --git a/RELEASES.md b/RELEASES.md index 904627bc..90876d33 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -19,6 +19,7 @@ Bug fixes * Parameters passed to plugin module functions were sometimes erroneously consumed. This is now fixed. * Fixes compilation errors in `metadata` feature build. +* Stacking `!` operators now work properly. New features ------------ diff --git a/src/parser.rs b/src/parser.rs index fbf17165..12eb9649 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1338,7 +1338,7 @@ fn parse_unary( Token::Bang => { let pos = eat_token(input, Token::Bang); let mut args = StaticVec::new(); - let expr = parse_primary(input, state, lib, settings.level_up())?; + let expr = parse_unary(input, state, lib, settings.level_up())?; args.push(expr); let op = "!"; diff --git a/tests/internal_fn.rs b/tests/internal_fn.rs index 80d904e7..70a94a7c 100644 --- a/tests/internal_fn.rs +++ b/tests/internal_fn.rs @@ -62,9 +62,9 @@ fn test_internal_fn_overloading() -> Result<(), Box> { *engine .compile( r" - fn abc(x) { x + 42 } - fn abc(x) { x - 42 } - " + fn abc(x) { x + 42 } + fn abc(x) { x - 42 } + " ) .expect_err("should error") .0, diff --git a/tests/not.rs b/tests/not.rs index ffc1d21d..41220389 100644 --- a/tests/not.rs +++ b/tests/not.rs @@ -12,8 +12,7 @@ fn test_not() -> Result<(), Box> { #[cfg(not(feature = "no_function"))] assert_eq!(engine.eval::("fn not(x) { !x } not(false)")?, true); - // TODO - do we allow stacking unary operators directly? e.g '!!!!!!!true' - assert_eq!(engine.eval::("!(!(!(!(true))))")?, true); + assert_eq!(engine.eval::("!!!!true")?, true); Ok(()) } From ab317bec4e79ff7b391b05cacd7df5d2932de4d9 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Sun, 24 Jan 2021 21:33:05 +0800 Subject: [PATCH 2/9] Add test for NativeCallContext. --- tests/native.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/native.rs diff --git a/tests/native.rs b/tests/native.rs new file mode 100644 index 00000000..d0e669fc --- /dev/null +++ b/tests/native.rs @@ -0,0 +1,34 @@ +use rhai::{Dynamic, Engine, EvalAltResult, NativeCallContext, RegisterFn, INT}; +use std::any::TypeId; + +#[test] +fn test_native_context() -> Result<(), Box> { + fn add_double( + context: NativeCallContext, + args: &mut [&mut Dynamic], + ) -> Result> { + let x = args[0].as_int().unwrap(); + let y = args[1].as_int().unwrap(); + Ok(format!("{}_{}", context.fn_name(), x + 2 * y).into()) + } + + let mut engine = Engine::new(); + + engine + .register_raw_fn( + "add_double", + &[TypeId::of::(), TypeId::of::()], + add_double, + ) + .register_raw_fn( + "adbl", + &[TypeId::of::(), TypeId::of::()], + add_double, + ); + + assert_eq!(engine.eval::("add_double(40, 1)")?, "add_double_42"); + + assert_eq!(engine.eval::("adbl(40, 1)")?, "adbl_42"); + + Ok(()) +} From e902c740736df6e0784bbe6546ea549b91039a0e Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 25 Jan 2021 11:31:54 +0800 Subject: [PATCH 3/9] Add threading example. --- examples/threading.rs | 51 +++++++++++++++++++++++++++++++++++++++++++ src/fn_args.rs | 2 +- src/parser.rs | 38 ++++++++++---------------------- tests/native.rs | 2 +- 4 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 examples/threading.rs diff --git a/examples/threading.rs b/examples/threading.rs new file mode 100644 index 00000000..9e115f0a --- /dev/null +++ b/examples/threading.rs @@ -0,0 +1,51 @@ +use rhai::{Engine, RegisterFn, INT}; + +fn main() { + // Channel: Script -> Master + let (tx_script, rx_master) = std::sync::mpsc::channel(); + // Channel: Master -> Script + let (tx_master, rx_script) = std::sync::mpsc::channel(); + + // Spawn thread with Engine + std::thread::spawn(move || { + // Create Engine + let mut engine = Engine::new(); + + // Register API + // Notice that the API functions are blocking + engine + .register_fn("get", move || rx_script.recv().unwrap()) + .register_fn("put", move |v: INT| tx_script.send(v).unwrap()); + + // Run script + engine + .consume( + r#" + print("Starting script loop..."); + + loop { + let x = get(); + print("Script Read: " + x); + x += 1; + print("Script Write: " + x); + put(x); + } + "#, + ) + .unwrap(); + }); + + // This is the main processing thread + + println!("Starting main loop..."); + + let mut value: INT = 0; + + while value < 10 { + println!("Value: {}", value); + // Send value to script + tx_master.send(value).unwrap(); + // Receive value from script + value = rx_master.recv().unwrap(); + } +} diff --git a/src/fn_args.rs b/src/fn_args.rs index 876c59ba..eeb53a1a 100644 --- a/src/fn_args.rs +++ b/src/fn_args.rs @@ -19,7 +19,7 @@ macro_rules! impl_args { ($($p:ident),*) => { impl<$($p: Variant + Clone),*> FuncArgs for ($($p,)*) { - #[inline] + #[inline(always)] fn into_vec(self) -> StaticVec { let ($($p,)*) = self; diff --git a/src/parser.rs b/src/parser.rs index 12eb9649..ae8ece87 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2870,7 +2870,9 @@ fn parse_fn( /// Creates a curried expression from a list of external variables #[cfg(not(feature = "no_function"))] +#[cfg(not(feature = "no_closure"))] fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec, pos: Position) -> Expr { + // If there are no captured variables, no need to curry if externals.is_empty() { return fn_expr; } @@ -2880,14 +2882,8 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec, pos: Po args.push(fn_expr); - #[cfg(not(feature = "no_closure"))] externals.iter().for_each(|x| { - args.push(Expr::Variable(Box::new((None, None, x.clone().into())))); - }); - - #[cfg(feature = "no_closure")] - externals.into_iter().for_each(|x| { - args.push(Expr::Variable(Box::new((None, None, x.clone().into())))); + args.push(Expr::Variable(Box::new((None, None, x.clone())))); }); let curry_func = crate::engine::KEYWORD_FN_PTR_CURRY; @@ -2904,21 +2900,12 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec, pos: Po pos, ); - // If there are captured variables, convert the entire expression into a statement block, - // then insert the relevant `Share` statements. - #[cfg(not(feature = "no_closure"))] - { - // Statement block - let mut statements: StaticVec<_> = Default::default(); - // Insert `Share` statements - statements.extend(externals.into_iter().map(|x| Stmt::Share(x))); - // Final expression - statements.push(Stmt::Expr(expr)); - Expr::Stmt(Box::new(statements), pos) - } - - #[cfg(feature = "no_closure")] - return expr; + // Convert the entire expression into a statement block, then insert the relevant + // [`Share`][Stmt::Share] statements. + let mut statements: StaticVec<_> = Default::default(); + statements.extend(externals.into_iter().map(Stmt::Share)); + statements.push(Stmt::Expr(expr)); + Expr::Stmt(Box::new(statements), pos) } /// Parse an anonymous function definition. @@ -3029,11 +3016,8 @@ fn parse_anon_fn( let expr = Expr::FnPointer(fn_name, settings.pos); - let expr = if cfg!(not(feature = "no_closure")) { - make_curry_from_externals(expr, externals, settings.pos) - } else { - expr - }; + #[cfg(not(feature = "no_closure"))] + let expr = make_curry_from_externals(expr, externals, settings.pos); Ok((expr, script)) } diff --git a/tests/native.rs b/tests/native.rs index d0e669fc..209c4a57 100644 --- a/tests/native.rs +++ b/tests/native.rs @@ -1,4 +1,4 @@ -use rhai::{Dynamic, Engine, EvalAltResult, NativeCallContext, RegisterFn, INT}; +use rhai::{Dynamic, Engine, EvalAltResult, NativeCallContext, INT}; use std::any::TypeId; #[test] From 2a209b82e9d668ed6824798fb5d739ae76ab9c69 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 25 Jan 2021 12:55:10 +0800 Subject: [PATCH 4/9] Fix threading example for sync. --- examples/threading.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/threading.rs b/examples/threading.rs index 9e115f0a..527b9214 100644 --- a/examples/threading.rs +++ b/examples/threading.rs @@ -6,6 +6,12 @@ fn main() { // Channel: Master -> Script let (tx_master, rx_script) = std::sync::mpsc::channel(); + #[cfg(feature = "sync")] + let (tx_script, rx_script) = ( + std::sync::Mutex::new(tx_script), + std::sync::Mutex::new(rx_script), + ); + // Spawn thread with Engine std::thread::spawn(move || { // Create Engine @@ -13,10 +19,19 @@ fn main() { // Register API // Notice that the API functions are blocking + + #[cfg(not(feature = "sync"))] engine .register_fn("get", move || rx_script.recv().unwrap()) .register_fn("put", move |v: INT| tx_script.send(v).unwrap()); + #[cfg(feature = "sync")] + engine + .register_fn("get", move || rx_script.lock().unwrap().recv().unwrap()) + .register_fn("put", move |v: INT| { + tx_script.lock().unwrap().send(v).unwrap() + }); + // Run script engine .consume( From d14168a4192ee1e814d7e61cb295debd1e20ae8f Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 27 Jan 2021 18:34:32 +0800 Subject: [PATCH 5/9] Refine Dynamic::take_immutable_string when shared. --- src/dynamic.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/dynamic.rs b/src/dynamic.rs index 07346620..c89c1250 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -1337,22 +1337,14 @@ impl Dynamic { #[cfg(not(feature = "no_closure"))] Union::Shared(cell, _) => { #[cfg(not(feature = "sync"))] - { - let inner = cell.borrow(); - match &inner.0 { - Union::Str(s, _) => Ok(s.clone()), - Union::FnPtr(f, _) => Ok(f.clone().take_data().0), - _ => Err((*inner).type_name()), - } - } + let data = cell.borrow(); #[cfg(feature = "sync")] - { - let inner = cell.read().unwrap(); - match &inner.0 { - Union::Str(s, _) => Ok(s.clone()), - Union::FnPtr(f, _) => Ok(f.clone().take_data().0), - _ => Err((*inner).type_name()), - } + let data = cell.read().unwrap(); + + match &data.0 { + Union::Str(s, _) => Ok(s.clone()), + Union::FnPtr(f, _) => Ok(f.get_fn_name().clone()), + _ => Err((*data).type_name()), } } _ => Err(self.type_name()), From f76daadcba3b15fd491463621899c658f7479ac3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 28 Jan 2021 15:29:55 +0800 Subject: [PATCH 6/9] Refine FuncArgs trait. --- src/engine_api.rs | 3 ++- src/fn_args.rs | 60 ++++++++++++++++++++++++++++++++++++++++------ src/lib.rs | 1 + tests/call_fn.rs | 60 ++++++++++++++++++++++++++++++++-------------- tests/functions.rs | 16 +++++++++++++ 5 files changed, 114 insertions(+), 26 deletions(-) diff --git a/src/engine_api.rs b/src/engine_api.rs index 4f899fd7..b861c06c 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1650,7 +1650,8 @@ impl Engine { name: &str, args: impl crate::fn_args::FuncArgs, ) -> Result> { - let mut arg_values = args.into_vec(); + let mut arg_values: crate::StaticVec<_> = Default::default(); + args.parse(&mut arg_values); let mut args: crate::StaticVec<_> = arg_values.as_mut().iter_mut().collect(); let result = diff --git a/src/fn_args.rs b/src/fn_args.rs index eeb53a1a..5e9761d8 100644 --- a/src/fn_args.rs +++ b/src/fn_args.rs @@ -3,14 +3,60 @@ #![allow(non_snake_case)] use crate::dynamic::Variant; +use crate::stdlib::vec::Vec; use crate::{Dynamic, StaticVec}; -/// Trait that represents arguments to a function call. -/// Any data type that can be converted into a [`Vec`]`<`[`Dynamic`]`>` can be used -/// as arguments to a function call. +/// Trait that parses arguments to a function call. +/// +/// Any data type can implement this trait in order to pass arguments to a function call. pub trait FuncArgs { - /// Convert to a [`StaticVec`]`<`[`Dynamic`]`>` of the function call arguments. - fn into_vec(self) -> StaticVec; + /// Parse function call arguments into a container. + /// + /// # Example + /// + /// ``` + /// use rhai::{Engine, Dynamic, FuncArgs, Scope}; + /// + /// // A struct containing function arguments + /// struct Options { + /// pub foo: bool, + /// pub bar: String, + /// pub baz: i64, + /// } + /// + /// impl FuncArgs for Options { + /// fn parse>(self, container: &mut C) { + /// container.extend(std::iter::once(self.foo.into())); + /// container.extend(std::iter::once(self.bar.into())); + /// container.extend(std::iter::once(self.baz.into())); + /// } + /// } + /// + /// # fn main() -> Result<(), Box> { + /// let options = Options { foo: false, bar: "world".to_string(), baz: 42 }; + /// + /// let engine = Engine::new(); + /// let mut scope = Scope::new(); + /// + /// let ast = engine.compile(r#" + /// fn hello(x, y, z) { + /// if x { "hello " + y } else { y + z } + /// } + /// "#)?; + /// + /// let result: String = engine.call_fn(&mut scope, &ast, "hello", options)?; + /// + /// assert_eq!(result, "world42"); + /// # Ok(()) + /// # } + /// ``` + fn parse>(self, container: &mut T); +} + +impl FuncArgs for Vec { + fn parse>(self, container: &mut C) { + container.extend(self.into_iter().map(Variant::into_dynamic)); + } } /// Macro to implement [`FuncArgs`] for tuples of standard types (each can be @@ -20,13 +66,13 @@ macro_rules! impl_args { impl<$($p: Variant + Clone),*> FuncArgs for ($($p,)*) { #[inline(always)] - fn into_vec(self) -> StaticVec { + fn parse>(self, container: &mut CONTAINER) { let ($($p,)*) = self; let mut _v = StaticVec::new(); $(_v.push($p.into_dynamic());)* - _v + container.extend(_v.into_iter()); } } diff --git a/src/lib.rs b/src/lib.rs index 8cb99223..b73119c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,6 +122,7 @@ pub type FLOAT = f32; pub use ast::{FnAccess, ScriptFnMetadata, AST}; pub use dynamic::Dynamic; pub use engine::{Engine, EvalContext}; +pub use fn_args::FuncArgs; pub use fn_native::{FnPtr, NativeCallContext, Shared}; pub use fn_register::{RegisterFn, RegisterResultFn}; pub use module::{FnNamespace, Module}; diff --git a/tests/call_fn.rs b/tests/call_fn.rs index c95e2853..552ae48f 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -1,22 +1,6 @@ #![cfg(not(feature = "no_function"))] -use rhai::{Engine, EvalAltResult, FnPtr, Func, ParseErrorType, RegisterFn, Scope, INT}; -use std::any::TypeId; - -#[test] -fn test_fn() -> Result<(), Box> { - let engine = Engine::new(); - - // Expect duplicated parameters error - assert_eq!( - *engine - .compile("fn hello(x, x) { x }") - .expect_err("should be error") - .0, - ParseErrorType::FnDuplicatedParam("hello".to_string(), "x".to_string()) - ); - - Ok(()) -} +use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Func, FuncArgs, RegisterFn, Scope, INT}; +use std::{any::TypeId, iter::once}; #[test] fn test_call_fn() -> Result<(), Box> { @@ -69,6 +53,46 @@ fn test_call_fn() -> Result<(), Box> { Ok(()) } +struct Options { + pub foo: bool, + pub bar: String, + pub baz: INT, +} + +impl FuncArgs for Options { + fn parse>(self, container: &mut C) { + container.extend(once(self.foo.into())); + container.extend(once(self.bar.into())); + container.extend(once(self.baz.into())); + } +} + +#[test] +fn test_call_fn_args() -> Result<(), Box> { + let options = Options { + foo: false, + bar: "world".to_string(), + baz: 42, + }; + + let engine = Engine::new(); + let mut scope = Scope::new(); + + let ast = engine.compile( + r#" + fn hello(x, y, z) { + if x { "hello " + y } else { y + z } + } + "#, + )?; + + let result: String = engine.call_fn(&mut scope, &ast, "hello", options)?; + + assert_eq!(result, "world42"); + + Ok(()) +} + #[test] fn test_call_fn_private() -> Result<(), Box> { let engine = Engine::new(); diff --git a/tests/functions.rs b/tests/functions.rs index 68b8a214..f5624fbf 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -51,6 +51,22 @@ fn test_functions() -> Result<(), Box> { Ok(()) } +#[test] +fn test_functions_params() -> Result<(), Box> { + let engine = Engine::new(); + + // Expect duplicated parameters error + assert_eq!( + *engine + .compile("fn hello(x, x) { x }") + .expect_err("should be error") + .0, + ParseErrorType::FnDuplicatedParam("hello".to_string(), "x".to_string()) + ); + + Ok(()) +} + #[cfg(not(feature = "no_function"))] #[test] fn test_functions_namespaces() -> Result<(), Box> { From cef61bc9247d8e173852630881b974bee10d1b2b Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 28 Jan 2021 16:48:56 +0800 Subject: [PATCH 7/9] Fix no_function build. --- src/fn_args.rs | 1 + src/fn_func.rs | 1 + src/lib.rs | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/fn_args.rs b/src/fn_args.rs index 5e9761d8..90a5d3f3 100644 --- a/src/fn_args.rs +++ b/src/fn_args.rs @@ -1,5 +1,6 @@ //! Helper module which defines [`FuncArgs`] to make function calling easier. +#![cfg(not(feature = "no_function"))] #![allow(non_snake_case)] use crate::dynamic::Variant; diff --git a/src/fn_func.rs b/src/fn_func.rs index e4b2d4ed..22eadf5f 100644 --- a/src/fn_func.rs +++ b/src/fn_func.rs @@ -8,6 +8,7 @@ use crate::stdlib::{boxed::Box, string::ToString}; use crate::{Engine, EvalAltResult, ParseError, Scope, AST}; /// Trait to create a Rust closure from a script. +/// Not available under `no_function`. pub trait Func { type Output; diff --git a/src/lib.rs b/src/lib.rs index b73119c2..34fed243 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,7 +122,6 @@ pub type FLOAT = f32; pub use ast::{FnAccess, ScriptFnMetadata, AST}; pub use dynamic::Dynamic; pub use engine::{Engine, EvalContext}; -pub use fn_args::FuncArgs; pub use fn_native::{FnPtr, NativeCallContext, Shared}; pub use fn_register::{RegisterFn, RegisterResultFn}; pub use module::{FnNamespace, Module}; @@ -147,6 +146,9 @@ pub use rhai_codegen::*; #[cfg(not(feature = "no_function"))] pub use fn_func::Func; +#[cfg(not(feature = "no_function"))] +pub use fn_args::FuncArgs; + /// Variable-sized array of [`Dynamic`] values. /// /// Not available under `no_index`. @@ -164,7 +166,7 @@ pub use module::ModuleResolver; /// Module containing all built-in _module resolvers_ available to Rhai. #[cfg(not(feature = "no_module"))] -pub use crate::module::resolvers as module_resolvers; +pub use module::resolvers as module_resolvers; /// _(SERDE)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde). /// Exported under the `serde` feature. From 903b6d6795a846464bc37fd8e1a213177a8b102b Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 28 Jan 2021 16:59:19 +0800 Subject: [PATCH 8/9] Rename set_doc_comments to enable_doc_comments. --- RELEASES.md | 1 + src/engine.rs | 9 +++++++-- src/engine_settings.rs | 2 +- src/fn_func.rs | 1 + tests/comments.rs | 10 +++++----- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 90876d33..3d57b32e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,7 @@ Breaking changes * Rust compiler requirement raised to 1.49. * `NativeCallContext::new` taker an additional parameter containing the name of the function called. +* `Engine::set_doc_comments` is renamed `Engine::enable_doc_comments`. Bug fixes --------- diff --git a/src/engine.rs b/src/engine.rs index 150a8eb5..21f65fa3 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -545,32 +545,37 @@ impl State { #[derive(Debug, Clone, Eq, PartialEq, Hash)] 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. + /// + /// Not available under `no_function`. #[cfg(not(feature = "no_function"))] pub max_call_stack_depth: usize, /// 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: 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]. + /// + /// Not available under `no_module`. #[cfg(not(feature = "no_module"))] pub max_modules: usize, /// 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: Option, /// Maximum number of properties in an [object map][Map]. + /// /// Not available under `no_object`. #[cfg(not(feature = "no_object"))] pub max_map_size: Option, diff --git a/src/engine_settings.rs b/src/engine_settings.rs index 396c155e..7d36b5da 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -34,7 +34,7 @@ impl Engine { } /// Enable/disable doc-comments. #[inline(always)] - pub fn set_doc_comments(&mut self, enable: bool) -> &mut Self { + pub fn enable_doc_comments(&mut self, enable: bool) -> &mut Self { self.disable_doc_comments = !enable; self } diff --git a/src/fn_func.rs b/src/fn_func.rs index 22eadf5f..aea3923e 100644 --- a/src/fn_func.rs +++ b/src/fn_func.rs @@ -8,6 +8,7 @@ use crate::stdlib::{boxed::Box, string::ToString}; use crate::{Engine, EvalAltResult, ParseError, Scope, AST}; /// Trait to create a Rust closure from a script. +/// /// Not available under `no_function`. pub trait Func { type Output; diff --git a/tests/comments.rs b/tests/comments.rs index 81aa2369..72f64aed 100644 --- a/tests/comments.rs +++ b/tests/comments.rs @@ -12,10 +12,10 @@ fn test_comments() -> Result<(), Box> { assert_eq!( engine.eval::( r#" - let /* I am a - multi-line - comment, yay! - */ x = 42; x + let /* I am a + multi-line + comment, yay! + */ x = 42; x "# )?, 42 @@ -88,7 +88,7 @@ fn test_comments_doc() -> Result<(), Box> { ) .is_err()); - engine.set_doc_comments(false); + engine.enable_doc_comments(false); engine.compile( r" From bb925a697c9b81fa9ada9b2b123e24a648a8b7a0 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 29 Jan 2021 22:29:36 +0800 Subject: [PATCH 9/9] Fix bug in Array::insert. --- RELEASES.md | 15 ++++++++------- src/packages/array_basic.rs | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 3d57b32e..0f3e37d5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,19 +8,20 @@ This version streamlines compiling for WASM. Rust compiler minimum version is raised to 1.49. -Breaking changes ----------------- - -* Rust compiler requirement raised to 1.49. -* `NativeCallContext::new` taker an additional parameter containing the name of the function called. -* `Engine::set_doc_comments` is renamed `Engine::enable_doc_comments`. - Bug fixes --------- * Parameters passed to plugin module functions were sometimes erroneously consumed. This is now fixed. * Fixes compilation errors in `metadata` feature build. * Stacking `!` operators now work properly. +* Off-by-one error in `insert` method for arrays is fixed. + +Breaking changes +---------------- + +* Rust compiler requirement raised to 1.49. +* `NativeCallContext::new` taker an additional parameter containing the name of the function called. +* `Engine::set_doc_comments` is renamed `Engine::enable_doc_comments`. New features ------------ diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 6247e881..95b61dcc 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -29,7 +29,7 @@ macro_rules! gen_array_functions { pub fn insert(list: &mut Array, position: INT, item: $arg_type) { if position <= 0 { list.insert(0, Dynamic::from(item)); - } else if (position as usize) >= list.len() - 1 { + } else if (position as usize) >= list.len() { push(list, item); } else { list.insert(position as usize, Dynamic::from(item));