Merge branch 'master' into plugins
This commit is contained in:
commit
d278f3725c
@ -5,9 +5,7 @@ set -ex
|
|||||||
cargo build --verbose
|
cargo build --verbose
|
||||||
cargo test --verbose
|
cargo test --verbose
|
||||||
|
|
||||||
if [ "$TRAVIS_RUST_VERSION" = "nightly" ]
|
if [[ $TRAVIS_RUST_VERSION == "nightly" ]]; then
|
||||||
then
|
|
||||||
cargo build --verbose --features no_std
|
cargo build --verbose --features no_std
|
||||||
cargo test --verbose --features no_std
|
cargo test --verbose --features no_std
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -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" ]
|
||||||
|
@ -174,28 +174,3 @@
|
|||||||
of your accepting any such warranty or additional liability.
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
23
LICENSE-MIT.txt
Normal file
23
LICENSE-MIT.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Permission is hereby granted, free of charge, to any
|
||||||
|
person obtaining a copy of this software and associated
|
||||||
|
documentation files (the "Software"), to deal in the
|
||||||
|
Software without restriction, including without
|
||||||
|
limitation the rights to use, copy, modify, merge,
|
||||||
|
publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice
|
||||||
|
shall be included in all copies or substantial portions
|
||||||
|
of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||||
|
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
14
README.md
14
README.md
@ -64,3 +64,17 @@ Playground
|
|||||||
|
|
||||||
An [Online Playground](https://alvinhochun.github.io/rhai-demo/) is available with syntax-highlighting editor.
|
An [Online Playground](https://alvinhochun.github.io/rhai-demo/) is available with syntax-highlighting editor.
|
||||||
Scripts can be evaluated directly from the editor.
|
Scripts can be evaluated directly from the editor.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
Licensed under either:
|
||||||
|
|
||||||
|
* [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)
|
||||||
|
|
||||||
|
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.
|
||||||
|
@ -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
|
||||||
----------------
|
----------------
|
||||||
|
32
src/any.rs
32
src/any.rs
@ -30,12 +30,24 @@ use crate::stdlib::time::Instant;
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
|
|
||||||
|
mod private {
|
||||||
|
use crate::fn_native::SendSync;
|
||||||
|
use crate::stdlib::any::Any;
|
||||||
|
|
||||||
|
/// A sealed trait that prevents other crates from implementing [`Variant`].
|
||||||
|
///
|
||||||
|
/// [`Variant`]: super::Variant
|
||||||
|
pub trait Sealed {}
|
||||||
|
|
||||||
|
impl<T: Any + Clone + SendSync> Sealed for T {}
|
||||||
|
}
|
||||||
|
|
||||||
/// Trait to represent any type.
|
/// Trait to represent any type.
|
||||||
///
|
///
|
||||||
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
|
/// Currently, `Variant` is not `Send` nor `Sync`, so it can practically be any type.
|
||||||
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
|
/// Turn on the `sync` feature to restrict it to only types that implement `Send + Sync`.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub trait Variant: Any {
|
pub trait Variant: Any + private::Sealed {
|
||||||
/// Convert this `Variant` trait object to `&dyn Any`.
|
/// Convert this `Variant` trait object to `&dyn Any`.
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
@ -53,10 +65,6 @@ pub trait Variant: Any {
|
|||||||
|
|
||||||
/// Clone into `Dynamic`.
|
/// Clone into `Dynamic`.
|
||||||
fn clone_into_dynamic(&self) -> Dynamic;
|
fn clone_into_dynamic(&self) -> Dynamic;
|
||||||
|
|
||||||
/// This trait may only be implemented by `rhai`.
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn _closed(&self) -> _Private;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to represent any type.
|
/// Trait to represent any type.
|
||||||
@ -64,7 +72,7 @@ pub trait Variant: Any {
|
|||||||
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
|
/// `From<_>` is implemented for `i64` (`i32` if `only_i32`), `f64` (if not `no_float`),
|
||||||
/// `bool`, `String`, `char`, `Vec<T>` (into `Array`) and `HashMap<String, T>` (into `Map`).
|
/// `bool`, `String`, `char`, `Vec<T>` (into `Array`) and `HashMap<String, T>` (into `Map`).
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub trait Variant: Any + Send + Sync {
|
pub trait Variant: Any + Send + Sync + private::Sealed {
|
||||||
/// Convert this `Variant` trait object to `&dyn Any`.
|
/// Convert this `Variant` trait object to `&dyn Any`.
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
@ -82,10 +90,6 @@ pub trait Variant: Any + Send + Sync {
|
|||||||
|
|
||||||
/// Clone into `Dynamic`.
|
/// Clone into `Dynamic`.
|
||||||
fn clone_into_dynamic(&self) -> Dynamic;
|
fn clone_into_dynamic(&self) -> Dynamic;
|
||||||
|
|
||||||
/// This trait may only be implemented by `rhai`.
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn _closed(&self) -> _Private;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Any + Clone + SendSync> Variant for T {
|
impl<T: Any + Clone + SendSync> Variant for T {
|
||||||
@ -107,9 +111,6 @@ impl<T: Any + Clone + SendSync> Variant for T {
|
|||||||
fn clone_into_dynamic(&self) -> Dynamic {
|
fn clone_into_dynamic(&self) -> Dynamic {
|
||||||
Dynamic::from(self.clone())
|
Dynamic::from(self.clone())
|
||||||
}
|
}
|
||||||
fn _closed(&self) -> _Private {
|
|
||||||
_Private
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl dyn Variant {
|
impl dyn Variant {
|
||||||
@ -809,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;
|
|
||||||
|
@ -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,19 +1060,20 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
_ => {
|
_ => {
|
||||||
let type_name = self.map_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(|_| {
|
.map_err(|err| match *err {
|
||||||
Box::new(EvalAltResult::ErrorIndexingType(
|
EvalAltResult::ErrorFunctionNotFound(_, _) => Box::new(
|
||||||
type_name.into(),
|
EvalAltResult::ErrorIndexingType(type_name.into(), Position::none()),
|
||||||
Position::none(),
|
),
|
||||||
))
|
_ => err,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -10,7 +10,9 @@ 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")]
|
||||||
|
@ -170,7 +170,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")]
|
||||||
|
@ -738,18 +738,18 @@ impl Module {
|
|||||||
/// });
|
/// });
|
||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone>(
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
||||||
let b = mem::take(args[1]).cast::<B>();
|
let b = mem::take(args[1]).cast::<B>();
|
||||||
let c = mem::take(args[2]).cast::<A>();
|
let c = mem::take(args[2]).cast::<C>();
|
||||||
let a = args[0].downcast_mut::<A>().unwrap();
|
let a = args[0].downcast_mut::<A>().unwrap();
|
||||||
|
|
||||||
func(a, b, c).map(Dynamic::from)
|
func(a, b, c).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<A>()];
|
let arg_types = [TypeId::of::<A>(), TypeId::of::<B>(), TypeId::of::<C>()];
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
FN_IDX_SET,
|
FN_IDX_SET,
|
||||||
Public,
|
Public,
|
||||||
@ -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>);
|
||||||
|
|
||||||
|
@ -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")]
|
||||||
|
@ -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>);
|
||||||
|
|
||||||
@ -592,11 +609,20 @@ impl fmt::Debug for CustomExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for CustomExpr {
|
impl Hash for CustomExpr {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.0.hash(state);
|
self.0.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [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))
|
||||||
}
|
}
|
||||||
|
@ -162,10 +162,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
Union::Variant(value) if value.is::<i16>() => self.deserialize_i16(visitor),
|
Union::Variant(value) if value.is::<i16>() => self.deserialize_i16(visitor),
|
||||||
Union::Variant(value) if value.is::<i32>() => self.deserialize_i32(visitor),
|
Union::Variant(value) if value.is::<i32>() => self.deserialize_i32(visitor),
|
||||||
Union::Variant(value) if value.is::<i64>() => self.deserialize_i64(visitor),
|
Union::Variant(value) if value.is::<i64>() => self.deserialize_i64(visitor),
|
||||||
|
Union::Variant(value) if value.is::<i128>() => self.deserialize_i128(visitor),
|
||||||
Union::Variant(value) if value.is::<u8>() => self.deserialize_u8(visitor),
|
Union::Variant(value) if value.is::<u8>() => self.deserialize_u8(visitor),
|
||||||
Union::Variant(value) if value.is::<u16>() => self.deserialize_u16(visitor),
|
Union::Variant(value) if value.is::<u16>() => self.deserialize_u16(visitor),
|
||||||
Union::Variant(value) if value.is::<u32>() => self.deserialize_u32(visitor),
|
Union::Variant(value) if value.is::<u32>() => self.deserialize_u32(visitor),
|
||||||
Union::Variant(value) if value.is::<u64>() => self.deserialize_u64(visitor),
|
Union::Variant(value) if value.is::<u64>() => self.deserialize_u64(visitor),
|
||||||
|
Union::Variant(value) if value.is::<u128>() => self.deserialize_u128(visitor),
|
||||||
|
|
||||||
Union::Variant(_) => self.type_error(),
|
Union::Variant(_) => self.type_error(),
|
||||||
}
|
}
|
||||||
@ -219,6 +221,18 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else if cfg!(not(feature = "only_i32")) {
|
||||||
|
self.type_error()
|
||||||
|
} else {
|
||||||
|
self.value
|
||||||
|
.downcast_ref::<i128>()
|
||||||
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
if let Ok(v) = self.value.as_int() {
|
if let Ok(v) = self.value.as_int() {
|
||||||
self.deserialize_int(v, visitor)
|
self.deserialize_int(v, visitor)
|
||||||
@ -259,6 +273,16 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
if let Ok(v) = self.value.as_int() {
|
||||||
|
self.deserialize_int(v, visitor)
|
||||||
|
} else {
|
||||||
|
self.value
|
||||||
|
.downcast_ref::<u128>()
|
||||||
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return self
|
return self
|
||||||
|
@ -150,6 +150,21 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
if v > i64::MAX as i128 {
|
||||||
|
return Ok(Dynamic::from(v));
|
||||||
|
} else {
|
||||||
|
return self.serialize_i64(v as i64);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "only_i32")]
|
||||||
|
if v > i32::MAX as i128 {
|
||||||
|
return Ok(Dynamic::from(v));
|
||||||
|
} else {
|
||||||
|
return self.serialize_i32(v as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
return self.serialize_i64(i64::from(v));
|
return self.serialize_i64(i64::from(v));
|
||||||
@ -190,6 +205,21 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
if v > i64::MAX as u128 {
|
||||||
|
return Ok(Dynamic::from(v));
|
||||||
|
} else {
|
||||||
|
return self.serialize_i64(v as i64);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "only_i32")]
|
||||||
|
if v > i32::MAX as u128 {
|
||||||
|
return Ok(Dynamic::from(v));
|
||||||
|
} else {
|
||||||
|
return self.serialize_i32(v as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
Ok(Dynamic::from(v))
|
Ok(Dynamic::from(v))
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ use crate::token::{is_valid_identifier, Position, Token};
|
|||||||
use crate::utils::StaticVec;
|
use crate::utils::StaticVec;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
fmt,
|
boxed::Box,
|
||||||
|
fmt, format,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
167
src/token.rs
167
src/token.rs
@ -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,
|
||||||
@ -810,6 +922,32 @@ pub fn get_next_token(
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if the given character is a hex character.
|
||||||
|
fn is_hex_char(c: char) -> bool {
|
||||||
|
match c {
|
||||||
|
'a'..='f' => true,
|
||||||
|
'A'..='F' => true,
|
||||||
|
'0'..='9' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if the given character is an octal character.
|
||||||
|
fn is_octal_char(c: char) -> bool {
|
||||||
|
match c {
|
||||||
|
'0'..='7' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if the given character is a binary character.
|
||||||
|
fn is_binary_char(c: char) -> bool {
|
||||||
|
match c {
|
||||||
|
'0' | '1' => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next token.
|
/// Get the next token.
|
||||||
fn get_next_token_inner(
|
fn get_next_token_inner(
|
||||||
stream: &mut impl InputStream,
|
stream: &mut impl InputStream,
|
||||||
@ -872,18 +1010,9 @@ fn get_next_token_inner(
|
|||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
|
|
||||||
let valid = match ch {
|
let valid = match ch {
|
||||||
'x' | 'X' => [
|
'x' | 'X' => is_hex_char,
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F',
|
'o' | 'O' => is_octal_char,
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_',
|
'b' | 'B' => is_binary_char,
|
||||||
],
|
|
||||||
'o' | 'O' => [
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '_', '_', '_', '_',
|
|
||||||
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
|
|
||||||
],
|
|
||||||
'b' | 'B' => [
|
|
||||||
'0', '1', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
|
|
||||||
'_', '_', '_', '_', '_', '_', '_', '_', '_', '_', '_',
|
|
||||||
],
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -895,7 +1024,7 @@ fn get_next_token_inner(
|
|||||||
});
|
});
|
||||||
|
|
||||||
while let Some(next_char_in_escape_seq) = stream.peek_next() {
|
while let Some(next_char_in_escape_seq) = stream.peek_next() {
|
||||||
if !valid.contains(&next_char_in_escape_seq) {
|
if !valid(next_char_in_escape_seq) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ fn test_hex_literal() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0xf; x")?, 15);
|
assert_eq!(engine.eval::<INT>("let x = 0xf; x")?, 15);
|
||||||
|
assert_eq!(engine.eval::<INT>("let x = 0Xf; x")?, 15);
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0xff; x")?, 255);
|
assert_eq!(engine.eval::<INT>("let x = 0xff; x")?, 255);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -24,6 +25,7 @@ fn test_octal_literal() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0o77; x")?, 63);
|
assert_eq!(engine.eval::<INT>("let x = 0o77; x")?, 63);
|
||||||
|
assert_eq!(engine.eval::<INT>("let x = 0O77; x")?, 63);
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0o1234; x")?, 668);
|
assert_eq!(engine.eval::<INT>("let x = 0o1234; x")?, 668);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -34,6 +36,7 @@ fn test_binary_literal() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
assert_eq!(engine.eval::<INT>("let x = 0b1111; x")?, 15);
|
assert_eq!(engine.eval::<INT>("let x = 0b1111; x")?, 15);
|
||||||
|
assert_eq!(engine.eval::<INT>("let x = 0B1111; x")?, 15);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("let x = 0b0011_1100_1010_0101; x")?,
|
engine.eval::<INT>("let x = 0b0011_1100_1010_0101; x")?,
|
||||||
15525
|
15525
|
||||||
|
Loading…
Reference in New Issue
Block a user