Merge pull request #200 from schungx/master

Documentation improvements and syncing up.
This commit is contained in:
Stephen Chung 2020-07-25 16:19:48 +08:00 committed by GitHub
commit fc891dcdac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 298 additions and 48 deletions

29
.github/workflows/benchmark.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Benchmark
on:
push:
branches:
- master
jobs:
benchmark:
name: Run Rust benchmark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: rustup toolchain update nightly && rustup default nightly
- name: Run benchmark
run: cargo +nightly bench | tee output.txt
- name: Store benchmark result
uses: rhysd/github-action-benchmark@v1
with:
name: Rust Benchmark
tool: 'cargo'
output-file-path: output.txt
# Use personal access token instead of GITHUB_TOKEN due to https://github.community/t5/GitHub-Actions/Github-action-not-triggering-gh-pages-upon-push/td-p/26869/highlight/false
github-token: ${{ secrets.RHAI }}
auto-push: true
# Show alert with commit comment on detecting possible performance regression
alert-threshold: '200%'
comment-on-alert: true
fail-on-alert: true
alert-comment-cc-users: '@schungx'

View File

@ -75,3 +75,6 @@ optional = true
[target.'cfg(target_arch = "wasm32")'.dependencies] [target.'cfg(target_arch = "wasm32")'.dependencies]
instant= { version = "0.1.4", features = ["wasm-bindgen"] } # WASM implementation of std::time::Instant instant= { version = "0.1.4", features = ["wasm-bindgen"] } # WASM implementation of std::time::Instant
[package.metadata.docs.rs]
features = [ "serde", "internals" ]

View File

@ -68,9 +68,13 @@ Scripts can be evaluated directly from the editor.
License License
------- -------
Licensed under either of <a href="LICENSE-APACHE.txt">Apache License, Version Licensed under either:
2.0</a> or <a href="LICENSE-MIT.txt">MIT license</a> at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted * [Apache License, Version 2.0](https://github.com/jonathandturner/rhai/blob/master/LICENSE-APACHE.txt), or
for inclusion in this crate by you, as defined in the Apache-2.0 license, shall * [MIT license](https://github.com/jonathandturner/rhai/blob/master/LICENSE-MIT.txt)
be dual licensed as above, without any additional terms or conditions.
at your option.
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.

View File

@ -18,6 +18,7 @@ New features
* Anonymous functions in the syntax of a closure, e.g. `|x, y, z| x + y - z`. * Anonymous functions in the syntax of a closure, e.g. `|x, y, z| x + y - z`.
* Custom syntax now works even without the `internals` feature. * Custom syntax now works even without the `internals` feature.
* Currying of function pointers is supported via the `curry` keyword. * Currying of function pointers is supported via the `curry` keyword.
* `Module::set_indexer_get_set_fn` is added as a shorthand of both `Module::set_indexer_get_fn` and `Module::set_indexer_set_fn`.
Breaking changes Breaking changes
---------------- ----------------

View File

@ -34,9 +34,9 @@ mod private {
use crate::fn_native::SendSync; use crate::fn_native::SendSync;
use crate::stdlib::any::Any; use crate::stdlib::any::Any;
/// A sealed trait that prevents other crates from implementing [Variant]. /// A sealed trait that prevents other crates from implementing [`Variant`].
/// ///
/// [Variant]: super::Variant /// [`Variant`]: super::Variant
pub trait Sealed {} pub trait Sealed {}
impl<T: Any + Clone + SendSync> Sealed for T {} impl<T: Any + Clone + SendSync> Sealed for T {}
@ -810,8 +810,3 @@ impl From<Box<FnPtr>> for Dynamic {
Self(Union::FnPtr(value)) Self(Union::FnPtr(value))
} }
} }
/// Private type which ensures that `rhai::Any` and `rhai::AnyExt` can only
/// be implemented by this crate.
#[doc(hidden)]
pub struct _Private;

View File

@ -11,7 +11,7 @@ use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, St
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::{CustomSyntax, EvalContext, Expression}; use crate::syntax::{CustomSyntax, EvalContext};
use crate::token::Position; use crate::token::Position;
use crate::utils::StaticVec; use crate::utils::StaticVec;
@ -38,7 +38,12 @@ pub type Array = Vec<Dynamic>;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub type Map = HashMap<ImmutableString, Dynamic>; pub type Map = HashMap<ImmutableString, Dynamic>;
/// A stack of imported modules. /// [INTERNALS] A stack of imported modules.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub type Imports<'a> = Vec<(Cow<'a, str>, Module)>; pub type Imports<'a> = Vec<(Cow<'a, str>, Module)>;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -189,12 +194,17 @@ impl<T: Into<Dynamic>> From<T> for Target<'_> {
} }
} }
/// A type that holds all the current states of the Engine. /// [INTERNALS] A type that holds all the current states of the Engine.
/// Exported under the `internals` feature only.
/// ///
/// # Safety /// # Safety
/// ///
/// This type uses some unsafe code, mainly for avoiding cloning of local variable names via /// This type uses some unsafe code, mainly for avoiding cloning of local variable names via
/// direct lifetime casting. /// direct lifetime casting.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)] #[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub struct State { pub struct State {
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup. /// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
@ -1020,7 +1030,7 @@ impl Engine {
map.entry(index).or_insert(Default::default()).into() map.entry(index).or_insert(Default::default()).into()
} else { } else {
let index = idx let index = idx
.downcast_ref::<String>() .downcast_ref::<ImmutableString>()
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?; .ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
map.get_mut(index.as_str()) map.get_mut(index.as_str())
@ -1050,22 +1060,20 @@ impl Engine {
} }
} }
#[cfg(not(feature = "no_object"))]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
_ => { _ => {
let val_type_name = val.type_name(); let type_name = val.type_name();
let args = &mut [val, &mut idx]; let args = &mut [val, &mut idx];
self.exec_fn_call( self.exec_fn_call(
state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level, state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level,
) )
.map(|(v, _)| v.into()) .map(|(v, _)| v.into())
.map_err(|e| match *e { .map_err(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(..) => { EvalAltResult::ErrorFunctionNotFound(_, _) => Box::new(
Box::new(EvalAltResult::ErrorIndexingType( EvalAltResult::ErrorIndexingType(type_name.into(), Position::none()),
self.map_type_name(val_type_name).into(), ),
Position::none(), _ => err,
))
}
_ => e,
}) })
} }

View File

@ -10,7 +10,12 @@ use crate::stdlib::{
string::{String, ToString}, string::{String, ToString},
}; };
/// Error when tokenizing the script text. /// [INTERNALS] Error encountered when tokenizing the script text.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[non_exhaustive] #[non_exhaustive]
pub enum LexError { pub enum LexError {

View File

@ -5,12 +5,13 @@ use crate::engine::Engine;
use crate::module::{FuncReturn, Module}; use crate::module::{FuncReturn, Module};
use crate::parser::ScriptFnDef; use crate::parser::ScriptFnDef;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::stdlib::vec::Vec;
use crate::token::{is_valid_identifier, Position}; use crate::token::{is_valid_identifier, Position};
use crate::utils::{ImmutableString, StaticVec}; use crate::utils::{ImmutableString, StaticVec};
use crate::Scope; use crate::Scope;
use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc}; use crate::stdlib::{
boxed::Box, convert::TryFrom, fmt, mem, rc::Rc, string::String, sync::Arc, vec::Vec,
};
/// Trait that maps to `Send + Sync` only under the `sync` feature. /// Trait that maps to `Send + Sync` only under the `sync` feature.
#[cfg(feature = "sync")] #[cfg(feature = "sync")]

View File

@ -166,7 +166,7 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")] #[deprecated(note = "this type is volatile and may change")]
pub use parser::{CustomExpr, Expr, ReturnType, ScriptFnDef, Stmt}; pub use parser::{CustomExpr, Expr, FloatWrapper, ReturnType, ScriptFnDef, Stmt};
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")] #[deprecated(note = "this type is volatile and may change")]

View File

@ -758,6 +758,40 @@ impl Module {
) )
} }
/// Set a pair of Rust index getter and setter functions, returning both hash keys.
/// This is a shorthand for `set_indexer_get_fn` and `set_indexer_set_fn`.
///
/// If there are similar existing Rust functions, they are replaced.
///
/// # Examples
///
/// ```
/// use rhai::{Module, ImmutableString};
///
/// let mut module = Module::new();
/// let (hash_get, hash_set) = module.set_indexer_get_set_fn(
/// |x: &mut i64, y: ImmutableString| {
/// Ok(*x + y.len() as i64)
/// },
/// |x: &mut i64, y: ImmutableString, value: i64| {
/// *x = y.len() as i64 + value;
/// Ok(())
/// }
/// );
/// assert!(module.contains_fn(hash_get));
/// assert!(module.contains_fn(hash_set));
/// ```
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
&mut self,
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
setter: impl Fn(&mut A, B, T) -> FuncReturn<()> + SendSync + 'static,
) -> (u64, u64) {
(
self.set_indexer_get_fn(getter),
self.set_indexer_set_fn(setter),
)
}
/// Set a Rust function taking four parameters into the module, returning a hash key. /// Set a Rust function taking four parameters into the module, returning a hash key.
/// ///
/// If there is a similar existing Rust function, it is replaced. /// If there is a similar existing Rust function, it is replaced.
@ -1094,11 +1128,17 @@ impl Module {
} }
} }
/// A chain of module names to qualify a variable or function call. /// [INTERNALS] A chain of module names to qualify a variable or function call.
/// A `u64` hash key is kept for quick search purposes. /// Exported under the `internals` feature only.
///
/// A `u64` hash key is cached for quick search purposes.
/// ///
/// A `StaticVec` is used because most module-level access contains only one level, /// A `StaticVec` is used because most module-level access contains only one level,
/// and it is wasteful to always allocate a `Vec` with one element. /// and it is wasteful to always allocate a `Vec` with one element.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Clone, Eq, PartialEq, Default, Hash)] #[derive(Clone, Eq, PartialEq, Default, Hash)]
pub struct ModuleRef(StaticVec<(String, Position)>, Option<NonZeroUsize>); pub struct ModuleRef(StaticVec<(String, Position)>, Option<NonZeroUsize>);

View File

@ -456,7 +456,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// "xxx" in "xxxxx" // "xxx" in "xxxxx"
(Expr::StringConstant(a), Expr::StringConstant(b)) => { (Expr::StringConstant(a), Expr::StringConstant(b)) => {
state.set_dirty(); state.set_dirty();
if b.0.contains(a.0.as_ref()) { Expr::True(a.1) } else { Expr::False(a.1) } if b.0.contains(a.0.as_str()) { Expr::True(a.1) } else { Expr::False(a.1) }
} }
// 'x' in "xxxxx" // 'x' in "xxxxx"
(Expr::CharConstant(a), Expr::StringConstant(b)) => { (Expr::CharConstant(a), Expr::StringConstant(b)) => {
@ -560,7 +560,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| { let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
if !f.is_script() { return false; } if !f.is_script() { return false; }
let fn_def = f.get_fn_def(); let fn_def = f.get_fn_def();
&fn_def.name == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len()) fn_def.name.as_str() == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
}).is_some(); }).is_some();
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]

View File

@ -342,11 +342,16 @@ impl fmt::Display for FnAccess {
} }
} }
/// A scripted function definition. /// [INTERNALS] A type containing information on a scripted function.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub struct ScriptFnDef { pub struct ScriptFnDef {
/// Function name. /// Function name.
pub name: String, pub name: ImmutableString,
/// Function access mode. /// Function access mode.
pub access: FnAccess, pub access: FnAccess,
/// Names of function parameters. /// Names of function parameters.
@ -376,7 +381,12 @@ impl fmt::Display for ScriptFnDef {
} }
} }
/// `return`/`throw` statement. /// [INTERNALS] A type encapsulating the mode of a `return`/`throw` statement.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
pub enum ReturnType { pub enum ReturnType {
/// `return` statement. /// `return` statement.
@ -477,7 +487,8 @@ impl ParseSettings {
} }
} }
/// A statement. /// [INTERNALS] A Rhai statement.
/// Exported under the `internals` feature only.
/// ///
/// Each variant is at most one pointer in size (for speed), /// Each variant is at most one pointer in size (for speed),
/// with everything being allocated together in one single tuple. /// with everything being allocated together in one single tuple.
@ -582,6 +593,12 @@ impl Stmt {
} }
} }
/// [INTERNALS] A type wrapping a custom syntax definition.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Clone)] #[derive(Clone)]
pub struct CustomExpr(pub StaticVec<Expr>, pub Shared<FnCustomSyntaxEval>); pub struct CustomExpr(pub StaticVec<Expr>, pub Shared<FnCustomSyntaxEval>);
@ -597,6 +614,15 @@ impl Hash for CustomExpr {
} }
} }
/// [INTERNALS] A type wrapping a floating-point number.
/// Exported under the `internals` feature only.
///
/// This type is mainly used to provide a standard `Hash` implementation
/// to floating-point numbers, allowing `Expr` to derive `Hash` automatically.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[derive(Debug, PartialEq, PartialOrd, Clone)] #[derive(Debug, PartialEq, PartialOrd, Clone)]
pub struct FloatWrapper(pub FLOAT, pub Position); pub struct FloatWrapper(pub FLOAT, pub Position);
@ -609,10 +635,15 @@ impl Hash for FloatWrapper {
} }
} }
/// An expression. /// [INTERNALS] An expression sub-tree.
/// Exported under the `internals` feature only.
/// ///
/// Each variant is at most one pointer in size (for speed), /// Each variant is at most one pointer in size (for speed),
/// with everything being allocated together in one single tuple. /// with everything being allocated together in one single tuple.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub enum Expr { pub enum Expr {
/// Integer constant. /// Integer constant.
@ -2852,7 +2883,7 @@ fn parse_fn(
let params = params.into_iter().map(|(p, _)| p).collect(); let params = params.into_iter().map(|(p, _)| p).collect();
Ok(ScriptFnDef { Ok(ScriptFnDef {
name, name: name.into(),
access, access,
params, params,
body, body,
@ -2940,7 +2971,7 @@ fn parse_anon_fn(
let hash = s.finish(); let hash = s.finish();
// Create unique function name // Create unique function name
let fn_name = format!("{}{}", FN_ANONYMOUS, hash); let fn_name: ImmutableString = format!("{}{:16x}", FN_ANONYMOUS, hash).into();
let script = ScriptFnDef { let script = ScriptFnDef {
name: fn_name.clone(), name: fn_name.clone(),
@ -2950,7 +2981,7 @@ fn parse_anon_fn(
pos: settings.pos, pos: settings.pos,
}; };
let expr = Expr::FnPointer(Box::new((fn_name.into(), settings.pos))); let expr = Expr::FnPointer(Box::new((fn_name, settings.pos)));
Ok((expr, script)) Ok((expr, script))
} }

View File

@ -136,89 +136,181 @@ impl fmt::Debug for Position {
} }
} }
/// Tokens. /// [INTERNALS] A Rhai language token.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Token { pub enum Token {
/// An `INT` constant.
IntegerConstant(INT), IntegerConstant(INT),
/// A `FLOAT` constaint.
///
/// Never appears under the `no_float` feature.
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
FloatConstant(FLOAT), FloatConstant(FLOAT),
/// An identifier.
Identifier(String), Identifier(String),
/// A character constant.
CharConstant(char), CharConstant(char),
/// A string constant.
StringConstant(String), StringConstant(String),
/// `{`
LeftBrace, LeftBrace,
/// `}`
RightBrace, RightBrace,
/// `(`
LeftParen, LeftParen,
/// `)`
RightParen, RightParen,
/// `[`
LeftBracket, LeftBracket,
/// `]`
RightBracket, RightBracket,
/// `+`
Plus, Plus,
/// `+` (unary)
UnaryPlus, UnaryPlus,
/// `-`
Minus, Minus,
/// `-` (unary)
UnaryMinus, UnaryMinus,
/// `*`
Multiply, Multiply,
/// `/`
Divide, Divide,
/// `%`
Modulo, Modulo,
/// `~`
PowerOf, PowerOf,
/// `<<`
LeftShift, LeftShift,
/// `>>`
RightShift, RightShift,
/// `;`
SemiColon, SemiColon,
/// `:`
Colon, Colon,
/// `::`
DoubleColon, DoubleColon,
/// `,`
Comma, Comma,
/// `.`
Period, Period,
/// `#{`
MapStart, MapStart,
/// `=`
Equals, Equals,
/// `true`
True, True,
/// `false`
False, False,
/// `let`
Let, Let,
/// `const`
Const, Const,
/// `if`
If, If,
/// `else`
Else, Else,
/// `while`
While, While,
/// `loop`
Loop, Loop,
/// `for`
For, For,
/// `in`
In, In,
/// `<`
LessThan, LessThan,
/// `>`
GreaterThan, GreaterThan,
/// `<=`
LessThanEqualsTo, LessThanEqualsTo,
/// `>=`
GreaterThanEqualsTo, GreaterThanEqualsTo,
/// `==`
EqualsTo, EqualsTo,
/// `!=`
NotEqualsTo, NotEqualsTo,
/// `!`
Bang, Bang,
/// `|`
Pipe, Pipe,
/// `||`
Or, Or,
/// `^`
XOr, XOr,
/// `&`
Ampersand, Ampersand,
/// `&&`
And, And,
/// `fn`
///
/// Never appears under the `no_function` feature.
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Fn, Fn,
/// `continue`
Continue, Continue,
/// `break`
Break, Break,
/// `return`
Return, Return,
/// `throw`
Throw, Throw,
/// `+=`
PlusAssign, PlusAssign,
/// `-=`
MinusAssign, MinusAssign,
/// `*=`
MultiplyAssign, MultiplyAssign,
/// `/=`
DivideAssign, DivideAssign,
/// `<<=`
LeftShiftAssign, LeftShiftAssign,
/// `>>=`
RightShiftAssign, RightShiftAssign,
/// `&=`
AndAssign, AndAssign,
/// `|=`
OrAssign, OrAssign,
/// `^=`
XOrAssign, XOrAssign,
/// `%=`
ModuloAssign, ModuloAssign,
/// `~=`
PowerOfAssign, PowerOfAssign,
/// `private`
///
/// Never appears under the `no_function` feature.
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Private, Private,
/// `import`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Import, Import,
/// `export`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Export, Export,
/// `as`
///
/// Never appears under the `no_module` feature.
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
As, As,
/// A lexer error.
LexError(Box<LexError>), LexError(Box<LexError>),
/// A comment block.
Comment(String), Comment(String),
/// A reserved symbol.
Reserved(String), Reserved(String),
/// A custom keyword.
Custom(String), Custom(String),
/// End of the input stream.
EOF, EOF,
} }
@ -566,7 +658,7 @@ impl Token {
} }
} }
/// Is this token a reserved keyword? /// Is this token a reserved symbol?
pub fn is_reserved(&self) -> bool { pub fn is_reserved(&self) -> bool {
match self { match self {
Self::Reserved(_) => true, Self::Reserved(_) => true,
@ -589,7 +681,12 @@ impl From<Token> for String {
} }
} }
/// State of the tokenizer. /// [INTERNALS] State of the tokenizer.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct TokenizeState { pub struct TokenizeState {
/// Maximum length of a string (0 = unlimited). /// Maximum length of a string (0 = unlimited).
@ -604,7 +701,12 @@ pub struct TokenizeState {
pub include_comments: bool, pub include_comments: bool,
} }
/// Trait that encapsulates a peekable character input stream. /// [INTERNALS] Trait that encapsulates a peekable character input stream.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This trait is volatile and may change.
pub trait InputStream { pub trait InputStream {
/// Get the next character /// Get the next character
fn get_next(&mut self) -> Option<char>; fn get_next(&mut self) -> Option<char>;
@ -628,7 +730,12 @@ pub fn is_valid_identifier(name: impl Iterator<Item = char>) -> bool {
first_alphabetic first_alphabetic
} }
/// Parse a string literal wrapped by `enclosing_char`. /// [INTERNALS] Parse a string literal wrapped by `enclosing_char`.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub fn parse_string_literal( pub fn parse_string_literal(
stream: &mut impl InputStream, stream: &mut impl InputStream,
state: &mut TokenizeState, state: &mut TokenizeState,
@ -794,7 +901,12 @@ fn scan_comment(
} }
} }
/// Get the next token. /// [INTERNALS] Get the next token from the `InputStream`.
/// Exported under the `internals` feature only.
///
/// ## WARNING
///
/// This type is volatile and may change.
pub fn get_next_token( pub fn get_next_token(
stream: &mut impl InputStream, stream: &mut impl InputStream,
state: &mut TokenizeState, state: &mut TokenizeState,

View File

@ -92,9 +92,12 @@ pub fn calc_fn_spec<'a>(
s.finish() s.finish()
} }
/// A type to hold a number of values in static storage for no-allocation, quick access. /// [INTERNALS] An array-like type that holds a number of values in static storage for no-allocation, quick access.
/// Exported under the `internals` feature only.
///
/// If too many items are stored, it converts into using a `Vec`. /// If too many items are stored, it converts into using a `Vec`.
/// ///
///
/// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate. /// This is essentially a knock-off of the [`staticvec`](https://crates.io/crates/staticvec) crate.
/// This simplified implementation here is to avoid pulling in another crate. /// This simplified implementation here is to avoid pulling in another crate.
/// ///
@ -130,6 +133,10 @@ pub fn calc_fn_spec<'a>(
/// # Safety /// # Safety
/// ///
/// This type uses some unsafe code (mainly for uninitialized/unused array slots) for efficiency. /// This type uses some unsafe code (mainly for uninitialized/unused array slots) for efficiency.
///
/// ## WARNING
///
/// This type is volatile and may change.
// //
// TODO - remove unsafe code // TODO - remove unsafe code
pub struct StaticVec<T> { pub struct StaticVec<T> {

View File

@ -104,5 +104,19 @@ fn test_function_pointers() -> Result<(), Box<EvalAltResult>> {
42 42
); );
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<INT>(
r#"
fn foo(x) { this.data += x; }
let x = #{ data: 40, action: Fn("foo") };
x.action(2);
x.data
"#
)?,
42
);
Ok(()) Ok(())
} }