commit
834d7b602b
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -8,7 +8,7 @@ on:
|
|||||||
pull_request: {}
|
pull_request: {}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
RUST_MSRV: 1.60.0
|
RUST_MSRV: 1.61.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
msrv:
|
msrv:
|
||||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -4,6 +4,8 @@ Rhai Release Notes
|
|||||||
Version 1.10.0
|
Version 1.10.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
The minimum Rust version is now `1.61.0` in order to use some `const` generics.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
@ -36,6 +38,14 @@ Enhancements
|
|||||||
* `Engine::module_resolver` is added to grant access to the `Engine`'s module resolver.
|
* `Engine::module_resolver` is added to grant access to the `Engine`'s module resolver.
|
||||||
|
|
||||||
|
|
||||||
|
Version 1.9.1
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is a bug-fix version that fixes a bug.
|
||||||
|
|
||||||
|
Accessing properties in _Strict Variables Mode_ no longer generates a _variable not found_ error.
|
||||||
|
|
||||||
|
|
||||||
Version 1.9.0
|
Version 1.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@ members = [".", "codegen"]
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "1.9.0"
|
version = "1.9.1"
|
||||||
rust-version = "1.60.0"
|
rust-version = "1.61.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||||
|
@ -26,7 +26,7 @@ Targets and builds
|
|||||||
* All CPU and O/S targets supported by Rust, including:
|
* All CPU and O/S targets supported by Rust, including:
|
||||||
* WebAssembly (WASM)
|
* WebAssembly (WASM)
|
||||||
* `no-std`
|
* `no-std`
|
||||||
* Minimum Rust version 1.60.0
|
* Minimum Rust version 1.61.0
|
||||||
|
|
||||||
|
|
||||||
Standard features
|
Standard features
|
||||||
|
@ -134,10 +134,7 @@ impl Expression<'_> {
|
|||||||
|
|
||||||
Expr::CharConstant(x, ..) => reify!(*x => Option<T>),
|
Expr::CharConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
Expr::StringConstant(x, ..) => reify!(x.clone() => Option<T>),
|
Expr::StringConstant(x, ..) => reify!(x.clone() => Option<T>),
|
||||||
Expr::Variable(x, ..) => {
|
Expr::Variable(x, ..) => reify!(x.3.clone() => Option<T>),
|
||||||
let x: ImmutableString = x.3.clone().into();
|
|
||||||
reify!(x => Option<T>)
|
|
||||||
}
|
|
||||||
Expr::BoolConstant(x, ..) => reify!(*x => Option<T>),
|
Expr::BoolConstant(x, ..) => reify!(*x => Option<T>),
|
||||||
Expr::Unit(..) => reify!(() => Option<T>),
|
Expr::Unit(..) => reify!(() => Option<T>),
|
||||||
|
|
||||||
|
@ -3,9 +3,8 @@
|
|||||||
#![cfg(feature = "metadata")]
|
#![cfg(feature = "metadata")]
|
||||||
|
|
||||||
use crate::module::FuncInfo;
|
use crate::module::FuncInfo;
|
||||||
use crate::plugin::*;
|
|
||||||
use crate::tokenizer::{is_valid_function_name, Token};
|
use crate::tokenizer::{is_valid_function_name, Token};
|
||||||
use crate::{Engine, Module, Scope, INT};
|
use crate::{Engine, FnAccess, Module, Scope, INT};
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -117,19 +116,20 @@ impl Definitions<'_> {
|
|||||||
}
|
}
|
||||||
/// Get the [`Engine`].
|
/// Get the [`Engine`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn engine(&self) -> &Engine {
|
#[must_use]
|
||||||
|
pub const fn engine(&self) -> &Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
/// Get the [`Scope`].
|
/// Get the [`Scope`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn scope(&self) -> Option<&Scope> {
|
pub const fn scope(&self) -> Option<&Scope> {
|
||||||
self.scope
|
self.scope
|
||||||
}
|
}
|
||||||
/// Get the configuration.
|
/// Get the configuration.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn config(&self) -> &DefinitionsConfig {
|
pub(crate) const fn config(&self) -> &DefinitionsConfig {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,7 +348,7 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn register_debugger(
|
pub fn register_debugger(
|
||||||
&mut self,
|
&mut self,
|
||||||
init: impl Fn(&Engine) -> Dynamic + SendSync + 'static,
|
init: impl Fn(&Self) -> Dynamic + SendSync + 'static,
|
||||||
callback: impl Fn(
|
callback: impl Fn(
|
||||||
EvalContext,
|
EvalContext,
|
||||||
crate::eval::DebuggerEvent,
|
crate::eval::DebuggerEvent,
|
||||||
|
@ -102,11 +102,8 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(stripped) = name.strip_prefix("rhai::") {
|
name.strip_prefix("rhai::")
|
||||||
map_std_type_name(stripped, shorthands)
|
.map_or(name, |s| map_std_type_name(s, shorthands))
|
||||||
} else {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
|
@ -167,7 +167,7 @@ impl AST {
|
|||||||
/// Get a reference to the source.
|
/// Get a reference to the source.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn source_raw(&self) -> &Identifier {
|
pub(crate) const fn source_raw(&self) -> &Identifier {
|
||||||
&self.source
|
&self.source
|
||||||
}
|
}
|
||||||
/// Set the source.
|
/// Set the source.
|
||||||
@ -261,7 +261,7 @@ impl AST {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
pub(crate) const fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
||||||
&self.lib
|
&self.lib
|
||||||
}
|
}
|
||||||
/// _(internals)_ Get the internal shared [`Module`][crate::Module] containing all script-defined functions.
|
/// _(internals)_ Get the internal shared [`Module`][crate::Module] containing all script-defined functions.
|
||||||
@ -272,7 +272,7 @@ impl AST {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
pub const fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
||||||
&self.lib
|
&self.lib
|
||||||
}
|
}
|
||||||
/// Get the embedded [module resolver][crate::ModuleResolver].
|
/// Get the embedded [module resolver][crate::ModuleResolver].
|
||||||
@ -280,7 +280,7 @@ impl AST {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn resolver(
|
pub(crate) const fn resolver(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||||
self.resolver.as_ref()
|
self.resolver.as_ref()
|
||||||
@ -293,7 +293,7 @@ impl AST {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn resolver(
|
pub const fn resolver(
|
||||||
&self,
|
&self,
|
||||||
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||||
self.resolver.as_ref()
|
self.resolver.as_ref()
|
||||||
@ -910,7 +910,7 @@ impl<A: AsRef<AST>> Add<A> for &AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Into<AST>> AddAssign<A> for AST {
|
impl<A: Into<Self>> AddAssign<A> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: A) {
|
fn add_assign(&mut self, rhs: A) {
|
||||||
self.combine(rhs.into());
|
self.combine(rhs.into());
|
||||||
|
@ -338,17 +338,7 @@ impl<F: Float> FloatWrapper<F> {
|
|||||||
/// Create a new [`FloatWrapper`].
|
/// Create a new [`FloatWrapper`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(value: F) -> Self {
|
pub const fn new(value: F) -> Self {
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
impl FloatWrapper<crate::FLOAT> {
|
|
||||||
/// Create a new [`FloatWrapper`].
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new_const(value: crate::FLOAT) -> Self {
|
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,7 +590,7 @@ impl Expr {
|
|||||||
Self::FnCall(ref x, ..)
|
Self::FnCall(ref x, ..)
|
||||||
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
|
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
|
||||||
{
|
{
|
||||||
if let Expr::StringConstant(ref s, ..) = x.args[0] {
|
if let Self::StringConstant(ref s, ..) = x.args[0] {
|
||||||
FnPtr::new(s).ok()?.into()
|
FnPtr::new(s).ok()?.into()
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -612,8 +602,8 @@ impl Expr {
|
|||||||
match x.name.as_str() {
|
match x.name.as_str() {
|
||||||
// x..y
|
// x..y
|
||||||
OP_EXCLUSIVE_RANGE => {
|
OP_EXCLUSIVE_RANGE => {
|
||||||
if let Expr::IntegerConstant(ref start, ..) = x.args[0] {
|
if let Self::IntegerConstant(ref start, ..) = x.args[0] {
|
||||||
if let Expr::IntegerConstant(ref end, ..) = x.args[1] {
|
if let Self::IntegerConstant(ref end, ..) = x.args[1] {
|
||||||
(*start..*end).into()
|
(*start..*end).into()
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -624,8 +614,8 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
// x..=y
|
// x..=y
|
||||||
OP_INCLUSIVE_RANGE => {
|
OP_INCLUSIVE_RANGE => {
|
||||||
if let Expr::IntegerConstant(ref start, ..) = x.args[0] {
|
if let Self::IntegerConstant(ref start, ..) = x.args[0] {
|
||||||
if let Expr::IntegerConstant(ref end, ..) = x.args[1] {
|
if let Self::IntegerConstant(ref end, ..) = x.args[1] {
|
||||||
(*start..=*end).into()
|
(*start..=*end).into()
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -940,9 +930,9 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
Self::Index(x, ..)
|
Self::Index(x, ..)
|
||||||
| Self::Dot(x, ..)
|
| Self::Dot(x, ..)
|
||||||
| Expr::And(x, ..)
|
| Self::And(x, ..)
|
||||||
| Expr::Or(x, ..)
|
| Self::Or(x, ..)
|
||||||
| Expr::Coalesce(x, ..) => {
|
| Self::Coalesce(x, ..) => {
|
||||||
if !x.lhs.walk(path, on_node) {
|
if !x.lhs.walk(path, on_node) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ impl FnAccess {
|
|||||||
/// Is this function private?
|
/// Is this function private?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_private(self) -> bool {
|
pub const fn is_private(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Private => true,
|
Self::Private => true,
|
||||||
Self::Public => false,
|
Self::Public => false,
|
||||||
@ -29,7 +29,7 @@ impl FnAccess {
|
|||||||
/// Is this function public?
|
/// Is this function public?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_public(self) -> bool {
|
pub const fn is_public(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Private => false,
|
Self::Private => false,
|
||||||
Self::Public => true,
|
Self::Public => true,
|
||||||
|
@ -60,7 +60,7 @@ impl OpAssignment {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_op_assignment(name: &str, pos: Position) -> Self {
|
pub fn new_op_assignment(name: &str, pos: Position) -> Self {
|
||||||
Self::new_op_assignment_from_token(Token::lookup_from_syntax(name).expect("operator"), pos)
|
Self::new_op_assignment_from_token(&Token::lookup_from_syntax(name).expect("operator"), pos)
|
||||||
}
|
}
|
||||||
/// Create a new [`OpAssignment`] from a [`Token`].
|
/// Create a new [`OpAssignment`] from a [`Token`].
|
||||||
///
|
///
|
||||||
@ -68,7 +68,7 @@ impl OpAssignment {
|
|||||||
///
|
///
|
||||||
/// Panics if the token is not an op-assignment operator.
|
/// Panics if the token is not an op-assignment operator.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_op_assignment_from_token(op: Token, pos: Position) -> Self {
|
pub fn new_op_assignment_from_token(op: &Token, pos: Position) -> Self {
|
||||||
let op_raw = op
|
let op_raw = op
|
||||||
.get_base_op_from_assignment()
|
.get_base_op_from_assignment()
|
||||||
.expect("op-assignment operator")
|
.expect("op-assignment operator")
|
||||||
@ -90,7 +90,7 @@ impl OpAssignment {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_op_assignment_from_base(name: &str, pos: Position) -> Self {
|
pub fn new_op_assignment_from_base(name: &str, pos: Position) -> Self {
|
||||||
Self::new_op_assignment_from_base_token(
|
Self::new_op_assignment_from_base_token(
|
||||||
Token::lookup_from_syntax(name).expect("operator"),
|
&Token::lookup_from_syntax(name).expect("operator"),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -101,8 +101,8 @@ impl OpAssignment {
|
|||||||
/// Panics if the token is cannot be converted into an op-assignment operator.
|
/// Panics if the token is cannot be converted into an op-assignment operator.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_op_assignment_from_base_token(op: Token, pos: Position) -> Self {
|
pub fn new_op_assignment_from_base_token(op: &Token, pos: Position) -> Self {
|
||||||
Self::new_op_assignment_from_token(op.convert_to_op_assignment().expect("operator"), pos)
|
Self::new_op_assignment_from_token(&op.convert_to_op_assignment().expect("operator"), pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,13 +157,13 @@ impl ConditionalExpr {
|
|||||||
/// Is the condition always `true`?
|
/// Is the condition always `true`?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_always_true(&self) -> bool {
|
pub const fn is_always_true(&self) -> bool {
|
||||||
matches!(self.condition, Expr::BoolConstant(true, ..))
|
matches!(self.condition, Expr::BoolConstant(true, ..))
|
||||||
}
|
}
|
||||||
/// Is the condition always `false`?
|
/// Is the condition always `false`?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_always_false(&self) -> bool {
|
pub const fn is_always_false(&self) -> bool {
|
||||||
matches!(self.condition, Expr::BoolConstant(false, ..))
|
matches!(self.condition, Expr::BoolConstant(false, ..))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,12 +228,12 @@ impl RangeCase {
|
|||||||
/// Size of the range.
|
/// Size of the range.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> INT {
|
||||||
match self {
|
match self {
|
||||||
Self::ExclusiveInt(r, ..) if r.is_empty() => 0,
|
Self::ExclusiveInt(r, ..) if r.is_empty() => 0,
|
||||||
Self::ExclusiveInt(r, ..) => (r.end - r.start) as usize,
|
Self::ExclusiveInt(r, ..) => r.end - r.start,
|
||||||
Self::InclusiveInt(r, ..) if r.is_empty() => 0,
|
Self::InclusiveInt(r, ..) if r.is_empty() => 0,
|
||||||
Self::InclusiveInt(r, ..) => (*r.end() - *r.start()) as usize,
|
Self::InclusiveInt(r, ..) => *r.end() - *r.start() + 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is the specified number within this range?
|
/// Is the specified number within this range?
|
||||||
@ -248,7 +248,7 @@ impl RangeCase {
|
|||||||
/// Is the specified range inclusive?
|
/// Is the specified range inclusive?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_inclusive(&self) -> bool {
|
pub const fn is_inclusive(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::ExclusiveInt(..) => false,
|
Self::ExclusiveInt(..) => false,
|
||||||
Self::InclusiveInt(..) => true,
|
Self::InclusiveInt(..) => true,
|
||||||
@ -257,7 +257,7 @@ impl RangeCase {
|
|||||||
/// Get the index to the [`ConditionalExpr`].
|
/// Get the index to the [`ConditionalExpr`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn index(&self) -> usize {
|
pub const fn index(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::ExclusiveInt(.., n) | Self::InclusiveInt(.., n) => *n,
|
Self::ExclusiveInt(.., n) | Self::InclusiveInt(.., n) => *n,
|
||||||
}
|
}
|
||||||
@ -611,14 +611,14 @@ impl From<StmtBlock> for Stmt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: IntoIterator<Item = Stmt>> From<(T, Position, Position)> for Stmt {
|
impl<T: IntoIterator<Item = Self>> From<(T, Position, Position)> for Stmt {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (T, Position, Position)) -> Self {
|
fn from(value: (T, Position, Position)) -> Self {
|
||||||
StmtBlock::new(value.0, value.1, value.2).into()
|
StmtBlock::new(value.0, value.1, value.2).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: IntoIterator<Item = Stmt>> From<(T, Span)> for Stmt {
|
impl<T: IntoIterator<Item = Self>> From<(T, Span)> for Stmt {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (T, Span)) -> Self {
|
fn from(value: (T, Span)) -> Self {
|
||||||
StmtBlock::new_with_span(value.0, value.1).into()
|
StmtBlock::new_with_span(value.0, value.1).into()
|
||||||
@ -765,7 +765,7 @@ impl Stmt {
|
|||||||
Self::Noop(..) => true,
|
Self::Noop(..) => true,
|
||||||
Self::Expr(expr) => expr.is_pure(),
|
Self::Expr(expr) => expr.is_pure(),
|
||||||
Self::If(x, ..) => {
|
Self::If(x, ..) => {
|
||||||
x.0.is_pure() && x.1.iter().all(Stmt::is_pure) && x.2.iter().all(Stmt::is_pure)
|
x.0.is_pure() && x.1.iter().all(Self::is_pure) && x.2.iter().all(Self::is_pure)
|
||||||
}
|
}
|
||||||
Self::Switch(x, ..) => {
|
Self::Switch(x, ..) => {
|
||||||
let (expr, sw) = &**x;
|
let (expr, sw) = &**x;
|
||||||
@ -786,7 +786,7 @@ impl Stmt {
|
|||||||
Self::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => true,
|
Self::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => true,
|
||||||
Self::Do(x, options, ..) if matches!(x.0, Expr::BoolConstant(..)) => match x.0 {
|
Self::Do(x, options, ..) if matches!(x.0, Expr::BoolConstant(..)) => match x.0 {
|
||||||
Expr::BoolConstant(cond, ..) if cond == options.contains(ASTFlags::NEGATED) => {
|
Expr::BoolConstant(cond, ..) if cond == options.contains(ASTFlags::NEGATED) => {
|
||||||
x.1.iter().all(Stmt::is_pure)
|
x.1.iter().all(Self::is_pure)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -796,13 +796,13 @@ impl Stmt {
|
|||||||
|
|
||||||
// For loops can be pure because if the iterable is pure, it is finite,
|
// For loops can be pure because if the iterable is pure, it is finite,
|
||||||
// so infinite loops can never occur.
|
// so infinite loops can never occur.
|
||||||
Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure),
|
Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Self::is_pure),
|
||||||
|
|
||||||
Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false,
|
Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false,
|
||||||
Self::Block(block, ..) => block.iter().all(Stmt::is_pure),
|
Self::Block(block, ..) => block.iter().all(Self::is_pure),
|
||||||
Self::BreakLoop(..) | Self::Return(..) => false,
|
Self::BreakLoop(..) | Self::Return(..) => false,
|
||||||
Self::TryCatch(x, ..) => {
|
Self::TryCatch(x, ..) => {
|
||||||
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure)
|
x.try_block.iter().all(Self::is_pure) && x.catch_block.iter().all(Self::is_pure)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -828,7 +828,7 @@ impl Stmt {
|
|||||||
Self::Var(..) => true,
|
Self::Var(..) => true,
|
||||||
|
|
||||||
Self::Expr(e) => match &**e {
|
Self::Expr(e) => match &**e {
|
||||||
Expr::Stmt(s) => s.iter().all(Stmt::is_block_dependent),
|
Expr::Stmt(s) => s.iter().all(Self::is_block_dependent),
|
||||||
Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL,
|
Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -854,7 +854,7 @@ impl Stmt {
|
|||||||
Self::Var(x, ..) => x.1.is_pure(),
|
Self::Var(x, ..) => x.1.is_pure(),
|
||||||
|
|
||||||
Self::Expr(e) => match &**e {
|
Self::Expr(e) => match &**e {
|
||||||
Expr::Stmt(s) => s.iter().all(Stmt::is_internally_pure),
|
Expr::Stmt(s) => s.iter().all(Self::is_internally_pure),
|
||||||
_ => self.is_pure(),
|
_ => self.is_pure(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -237,13 +237,16 @@ impl Engine {
|
|||||||
{
|
{
|
||||||
engine.print = Box::new(|s| println!("{}", s));
|
engine.print = Box::new(|s| println!("{}", s));
|
||||||
engine.debug = Box::new(|s, source, pos| {
|
engine.debug = Box::new(|s, source, pos| {
|
||||||
if let Some(source) = source {
|
source.map_or_else(
|
||||||
println!("{} @ {:?} | {}", source, pos, s);
|
|| {
|
||||||
} else if pos.is_none() {
|
if pos.is_none() {
|
||||||
println!("{}", s);
|
println!("{}", s);
|
||||||
} else {
|
} else {
|
||||||
println!("{:?} | {}", pos, s);
|
println!("{:?} | {}", pos, s);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|source| println!("{} @ {:?} | {}", source, pos, s),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +319,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
string: impl AsRef<str> + Into<ImmutableString>,
|
string: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
locked_write(&self.interned_strings).get(string).into()
|
locked_write(&self.interned_strings).get(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(internals)_ Get an interned [string][ImmutableString].
|
/// _(internals)_ Get an interned [string][ImmutableString].
|
||||||
@ -331,7 +334,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
string: impl AsRef<str> + Into<ImmutableString>,
|
string: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
locked_write(&self.interned_strings).get(string).into()
|
locked_write(&self.interned_strings).get(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an empty [`ImmutableString`] which refers to a shared instance.
|
/// Get an empty [`ImmutableString`] which refers to a shared instance.
|
||||||
|
@ -152,14 +152,14 @@ impl Engine {
|
|||||||
if let Ok(val) =
|
if let Ok(val) =
|
||||||
self.call_indexer_get(global, caches, lib, target, idx, level)
|
self.call_indexer_get(global, caches, lib, target, idx, level)
|
||||||
{
|
{
|
||||||
let mut res = val.into();
|
let mut val = val.into();
|
||||||
// Run the op-assignment
|
// Run the op-assignment
|
||||||
self.eval_op_assignment(
|
self.eval_op_assignment(
|
||||||
global, caches, lib, op_info, &mut res, root, new_val,
|
global, caches, lib, op_info, &mut val, root, new_val,
|
||||||
level,
|
level,
|
||||||
)?;
|
)?;
|
||||||
// Replace new value
|
// Replace new value
|
||||||
new_val = res.take_or_clone();
|
new_val = val.take_or_clone();
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.check_data_size(&new_val, op_info.pos)?;
|
self.check_data_size(&new_val, op_info.pos)?;
|
||||||
}
|
}
|
||||||
@ -864,13 +864,16 @@ impl Engine {
|
|||||||
map.insert(index.clone().into(), Dynamic::UNIT);
|
map.insert(index.clone().into(), Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = map.get_mut(index.as_str()) {
|
map.get_mut(index.as_str()).map_or_else(
|
||||||
Ok(Target::from(value))
|
|| {
|
||||||
} else if self.fail_on_invalid_map_property() {
|
if self.fail_on_invalid_map_property() {
|
||||||
Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into())
|
Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into())
|
||||||
} else {
|
} else {
|
||||||
Ok(Target::from(Dynamic::UNIT))
|
Ok(Target::from(Dynamic::UNIT))
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|value| Ok(Target::from(value)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -970,21 +973,33 @@ impl Engine {
|
|||||||
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
|
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
|
||||||
|
|
||||||
let (ch, offset) = if index >= 0 {
|
let (ch, offset) = if index >= 0 {
|
||||||
|
if index >= crate::MAX_USIZE_INT {
|
||||||
|
return Err(
|
||||||
|
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let offset = index as usize;
|
let offset = index as usize;
|
||||||
(
|
(
|
||||||
s.chars().nth(offset).ok_or_else(|| {
|
s.chars().nth(offset).ok_or_else(|| {
|
||||||
let chars_len = s.chars().count();
|
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos)
|
||||||
ERR::ErrorStringBounds(chars_len, index, idx_pos)
|
|
||||||
})?,
|
})?,
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let offset = index.unsigned_abs() as usize;
|
let abs_index = index.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_index as u64 > usize::MAX as u64 {
|
||||||
|
return Err(
|
||||||
|
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = abs_index as usize;
|
||||||
(
|
(
|
||||||
// Count from end if negative
|
// Count from end if negative
|
||||||
s.chars().rev().nth(offset - 1).ok_or_else(|| {
|
s.chars().rev().nth(offset - 1).ok_or_else(|| {
|
||||||
let chars_len = s.chars().count();
|
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos)
|
||||||
ERR::ErrorStringBounds(chars_len, index, idx_pos)
|
|
||||||
})?,
|
})?,
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
|
@ -72,7 +72,7 @@ impl Engine {
|
|||||||
|
|
||||||
/// Is there a data size limit set?
|
/// Is there a data size limit set?
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn has_data_size_limit(&self) -> bool {
|
pub(crate) const fn has_data_size_limit(&self) -> bool {
|
||||||
let mut _limited = self.limits.max_string_size.is_some();
|
let mut _limited = self.limits.max_string_size.is_some();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -397,7 +397,7 @@ impl Debugger {
|
|||||||
/// Get the custom state.
|
/// Get the custom state.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn state(&self) -> &Dynamic {
|
pub const fn state(&self) -> &Dynamic {
|
||||||
&self.state
|
&self.state
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the custom state.
|
/// Get a mutable reference to the custom state.
|
||||||
|
@ -74,11 +74,8 @@ impl Engine {
|
|||||||
(_, namespace, hash_var, var_name) => {
|
(_, namespace, hash_var, var_name) => {
|
||||||
// foo:bar::baz::VARIABLE
|
// foo:bar::baz::VARIABLE
|
||||||
if let Some(module) = self.search_imports(global, namespace) {
|
if let Some(module) = self.search_imports(global, namespace) {
|
||||||
return if let Some(mut target) = module.get_qualified_var(*hash_var) {
|
return module.get_qualified_var(*hash_var).map_or_else(
|
||||||
// Module variables are constant
|
|| {
|
||||||
target.set_access_mode(AccessMode::ReadOnly);
|
|
||||||
Ok((target.into(), *_var_pos))
|
|
||||||
} else {
|
|
||||||
let sep = crate::tokenizer::Token::DoubleColon.literal_syntax();
|
let sep = crate::tokenizer::Token::DoubleColon.literal_syntax();
|
||||||
|
|
||||||
Err(ERR::ErrorVariableNotFound(
|
Err(ERR::ErrorVariableNotFound(
|
||||||
@ -86,7 +83,13 @@ impl Engine {
|
|||||||
namespace.position(),
|
namespace.position(),
|
||||||
)
|
)
|
||||||
.into())
|
.into())
|
||||||
};
|
},
|
||||||
|
|mut target| {
|
||||||
|
// Module variables are constant
|
||||||
|
target.set_access_mode(AccessMode::ReadOnly);
|
||||||
|
Ok((target.into(), *_var_pos))
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// global::VARIABLE
|
// global::VARIABLE
|
||||||
@ -141,11 +144,10 @@ impl Engine {
|
|||||||
let (index, var_pos) = match expr {
|
let (index, var_pos) = match expr {
|
||||||
// Check if the variable is `this`
|
// Check if the variable is `this`
|
||||||
Expr::Variable(v, None, pos) if v.0.is_none() && v.3 == KEYWORD_THIS => {
|
Expr::Variable(v, None, pos) if v.0.is_none() && v.3 == KEYWORD_THIS => {
|
||||||
return if let Some(val) = this_ptr {
|
return this_ptr.as_mut().map_or_else(
|
||||||
Ok(((*val).into(), *pos))
|
|| Err(ERR::ErrorUnboundThis(*pos).into()),
|
||||||
} else {
|
|val| Ok(((*val).into(), *pos)),
|
||||||
Err(ERR::ErrorUnboundThis(*pos).into())
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ if global.always_search_scope => (0, expr.start_position()),
|
_ if global.always_search_scope => (0, expr.start_position()),
|
||||||
Expr::Variable(.., Some(i), pos) => (i.get() as usize, *pos),
|
Expr::Variable(.., Some(i), pos) => (i.get() as usize, *pos),
|
||||||
@ -363,7 +365,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, ..) => {
|
Expr::Array(x, ..) => {
|
||||||
let mut arr = crate::Array::with_capacity(x.len());
|
let mut array = crate::Array::with_capacity(x.len());
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
let mut result = Ok(Dynamic::UNIT);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -383,7 +385,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
let val_sizes = Self::calc_data_sizes(&value, true);
|
||||||
|
|
||||||
arr.push(value);
|
array.push(value);
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.has_data_size_limit() {
|
if self.has_data_size_limit() {
|
||||||
@ -396,7 +398,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.map(|_| arr.into())
|
result.map(|_| array.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
@ -484,12 +484,10 @@ impl Engine {
|
|||||||
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
||||||
} else if let Ok(None) = expr_result {
|
} else if let Ok(None) = expr_result {
|
||||||
// Default match clause
|
// Default match clause
|
||||||
if let Some(index) = def_case {
|
def_case.as_ref().map_or(Ok(Dynamic::UNIT), |&index| {
|
||||||
let def_expr = &expressions[*index].expr;
|
let def_expr = &expressions[index].expr;
|
||||||
self.eval_expr(scope, global, caches, lib, this_ptr, def_expr, level)
|
self.eval_expr(scope, global, caches, lib, this_ptr, def_expr, level)
|
||||||
} else {
|
})
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
expr_result.map(|_| Dynamic::UNIT)
|
expr_result.map(|_| Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
@ -631,8 +629,12 @@ impl Engine {
|
|||||||
for (x, iter_value) in func(iter_obj).enumerate() {
|
for (x, iter_value) in func(iter_obj).enumerate() {
|
||||||
// Increment counter
|
// Increment counter
|
||||||
if counter_index < usize::MAX {
|
if counter_index < usize::MAX {
|
||||||
|
// As the variable increments from 0, this should always work
|
||||||
|
// since any overflow will first be caught below.
|
||||||
|
let index_value = x as INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if x > INT::MAX as usize {
|
if index_value > crate::MAX_USIZE_INT {
|
||||||
loop_result = Err(ERR::ErrorArithmetic(
|
loop_result = Err(ERR::ErrorArithmetic(
|
||||||
format!("for-loop counter overflow: {x}"),
|
format!("for-loop counter overflow: {x}"),
|
||||||
counter.pos,
|
counter.pos,
|
||||||
@ -641,10 +643,8 @@ impl Engine {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index_value = Dynamic::from(x as INT);
|
|
||||||
|
|
||||||
*scope.get_mut_by_index(counter_index).write_lock().unwrap() =
|
*scope.get_mut_by_index(counter_index).write_lock().unwrap() =
|
||||||
index_value;
|
Dynamic::from_int(index_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = match iter_value {
|
let value = match iter_value {
|
||||||
|
@ -15,8 +15,13 @@ use std::prelude::v1::*;
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
|
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
length - usize::min(start.unsigned_abs() as usize, length)
|
let abs_start = start.unsigned_abs();
|
||||||
} else if start as usize >= length {
|
if abs_start as u64 > crate::MAX_USIZE_INT as u64 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
length - usize::min(abs_start as usize, length)
|
||||||
|
}
|
||||||
|
} else if start > crate::MAX_USIZE_INT || start as usize >= length {
|
||||||
return (length, 0);
|
return (length, 0);
|
||||||
} else {
|
} else {
|
||||||
start as usize
|
start as usize
|
||||||
@ -24,7 +29,7 @@ pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (us
|
|||||||
|
|
||||||
let len = if len <= 0 {
|
let len = if len <= 0 {
|
||||||
0
|
0
|
||||||
} else if len as usize > length - start {
|
} else if len > crate::MAX_USIZE_INT || len as usize > length - start {
|
||||||
length - start
|
length - start
|
||||||
} else {
|
} else {
|
||||||
len as usize
|
len as usize
|
||||||
@ -59,7 +64,7 @@ pub fn calc_index<E>(
|
|||||||
} else {
|
} else {
|
||||||
err()
|
err()
|
||||||
}
|
}
|
||||||
} else if start as usize >= length {
|
} else if start > crate::MAX_USIZE_INT || start as usize >= length {
|
||||||
err()
|
err()
|
||||||
} else {
|
} else {
|
||||||
Ok(start as usize)
|
Ok(start as usize)
|
||||||
|
@ -700,7 +700,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
} else {
|
}
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
"+=" => Some(|_, args| {
|
||||||
let x = std::mem::take(args[1]);
|
let x = std::mem::take(args[1]);
|
||||||
@ -710,7 +710,6 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
|
@ -68,7 +68,7 @@ impl<'a> ArgBackup<'a> {
|
|||||||
// Replace the first reference with a reference to the clone, force-casting the lifetime.
|
// Replace the first reference with a reference to the clone, force-casting the lifetime.
|
||||||
// Must remember to restore it later with `restore_first_arg`.
|
// Must remember to restore it later with `restore_first_arg`.
|
||||||
//
|
//
|
||||||
// # Safety
|
// SAFETY:
|
||||||
//
|
//
|
||||||
// Blindly casting a reference to another lifetime saves allocation and string cloning,
|
// Blindly casting a reference to another lifetime saves allocation and string cloning,
|
||||||
// but must be used with the utmost care.
|
// but must be used with the utmost care.
|
||||||
@ -608,7 +608,7 @@ impl Engine {
|
|||||||
let num_params = args[1].as_int().expect("`INT`");
|
let num_params = args[1].as_int().expect("`INT`");
|
||||||
|
|
||||||
return Ok((
|
return Ok((
|
||||||
if num_params < 0 {
|
if num_params < 0 || num_params > crate::MAX_USIZE_INT {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
|
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
|
||||||
@ -1100,7 +1100,7 @@ impl Engine {
|
|||||||
.as_int()
|
.as_int()
|
||||||
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
|
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
|
||||||
|
|
||||||
return Ok(if num_params < 0 {
|
return Ok(if num_params < 0 || num_params > crate::MAX_USIZE_INT {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let hash_script = calc_fn_hash(&fn_name, num_params as usize);
|
let hash_script = calc_fn_hash(&fn_name, num_params as usize);
|
||||||
@ -1228,13 +1228,11 @@ impl Engine {
|
|||||||
|
|
||||||
if target_is_shared || target.is_temp_value() {
|
if target_is_shared || target.is_temp_value() {
|
||||||
arg_values.insert(0, target.take_or_clone().flatten());
|
arg_values.insert(0, target.take_or_clone().flatten());
|
||||||
args.extend(arg_values.iter_mut());
|
|
||||||
} else {
|
} else {
|
||||||
// Turn it into a method call only if the object is not shared and not a simple value
|
// Turn it into a method call only if the object is not shared and not a simple value
|
||||||
is_ref_mut = true;
|
is_ref_mut = true;
|
||||||
let obj_ref = target.take_ref().expect("ref");
|
let obj_ref = target.take_ref().expect("ref");
|
||||||
args.push(obj_ref);
|
args.push(obj_ref);
|
||||||
args.extend(arg_values.iter_mut());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// func(..., ...)
|
// func(..., ...)
|
||||||
@ -1246,8 +1244,9 @@ impl Engine {
|
|||||||
.map(|(value, ..)| arg_values.push(value.flatten()))
|
.map(|(value, ..)| arg_values.push(value.flatten()))
|
||||||
})?;
|
})?;
|
||||||
args.extend(curry.iter_mut());
|
args.extend(curry.iter_mut());
|
||||||
args.extend(arg_values.iter_mut());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args.extend(arg_values.iter_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
|
@ -47,9 +47,7 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
|||||||
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
// If T is `&str`, data must be `ImmutableString`, so map directly to it
|
||||||
data.flatten_in_place();
|
data.flatten_in_place();
|
||||||
let ref_str = data.as_str_ref().expect("&str");
|
let ref_str = data.as_str_ref().expect("&str");
|
||||||
// # Safety
|
// SAFETY: We already checked that `T` is `&str`, so it is safe to cast here.
|
||||||
//
|
|
||||||
// We already checked that `T` is `&str`, so it is safe to cast here.
|
|
||||||
return unsafe { mem::transmute_copy::<_, T>(&ref_str) };
|
return unsafe { mem::transmute_copy::<_, T>(&ref_str) };
|
||||||
}
|
}
|
||||||
if TypeId::of::<T>() == TypeId::of::<String>() {
|
if TypeId::of::<T>() == TypeId::of::<String>() {
|
||||||
|
25
src/lib.rs
25
src/lib.rs
@ -58,7 +58,18 @@
|
|||||||
|
|
||||||
#![cfg_attr(feature = "no_std", no_std)]
|
#![cfg_attr(feature = "no_std", no_std)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
// #![warn(clippy::all)]
|
||||||
|
// #![warn(clippy::pedantic)]
|
||||||
|
// #![warn(clippy::nursery)]
|
||||||
|
// #![warn(clippy::cargo)]
|
||||||
|
// #![warn(clippy::undocumented_unsafe_blocks)]
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
#![allow(clippy::missing_errors_doc)]
|
||||||
|
#![allow(clippy::used_underscore_binding)]
|
||||||
|
#![allow(clippy::inline_always)]
|
||||||
|
#![allow(clippy::module_name_repetitions)]
|
||||||
|
#![allow(clippy::negative_feature_names)]
|
||||||
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
@ -123,6 +134,20 @@ type UNSIGNED_INT = u64;
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
type UNSIGNED_INT = u32;
|
type UNSIGNED_INT = u32;
|
||||||
|
|
||||||
|
/// The maximum integer that can fit into a [`usize`].
|
||||||
|
#[cfg(not(target_pointer_width = "32"))]
|
||||||
|
const MAX_USIZE_INT: INT = INT::MAX;
|
||||||
|
|
||||||
|
/// The maximum integer that can fit into a [`usize`].
|
||||||
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
const MAX_USIZE_INT: INT = usize::MAX as INT;
|
||||||
|
|
||||||
|
/// The maximum integer that can fit into a [`usize`].
|
||||||
|
#[cfg(feature = "only_i32")]
|
||||||
|
#[cfg(target_pointer_width = "32")]
|
||||||
|
const MAX_USIZE_INT: INT = INT::MAX;
|
||||||
|
|
||||||
/// Number of bits in [`INT`].
|
/// Number of bits in [`INT`].
|
||||||
///
|
///
|
||||||
/// It is 64 unless the `only_i32` feature is enabled when it will be 32.
|
/// It is 64 unless the `only_i32` feature is enabled when it will be 32.
|
||||||
|
@ -41,7 +41,7 @@ impl FnNamespace {
|
|||||||
/// Is this a module namespace?
|
/// Is this a module namespace?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_module_namespace(self) -> bool {
|
pub const fn is_module_namespace(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Internal => true,
|
Self::Internal => true,
|
||||||
Self::Global => false,
|
Self::Global => false,
|
||||||
@ -50,7 +50,7 @@ impl FnNamespace {
|
|||||||
/// Is this a global namespace?
|
/// Is this a global namespace?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_global_namespace(self) -> bool {
|
pub const fn is_global_namespace(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Internal => false,
|
Self::Internal => false,
|
||||||
Self::Global => true,
|
Self::Global => true,
|
||||||
@ -193,7 +193,6 @@ impl FuncInfo {
|
|||||||
sig.push_str(", ");
|
sig.push_str(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sig.push(')');
|
|
||||||
} else {
|
} else {
|
||||||
let params: StaticVec<_> = self
|
let params: StaticVec<_> = self
|
||||||
.metadata
|
.metadata
|
||||||
@ -215,8 +214,8 @@ impl FuncInfo {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
sig.push_str(¶ms.join(", "));
|
sig.push_str(¶ms.join(", "));
|
||||||
sig.push(')');
|
|
||||||
}
|
}
|
||||||
|
sig.push(')');
|
||||||
|
|
||||||
if !self.func.is_script() && !return_type.is_empty() {
|
if !self.func.is_script() && !return_type.is_empty() {
|
||||||
sig.push_str(" -> ");
|
sig.push_str(" -> ");
|
||||||
|
@ -301,7 +301,7 @@ fn optimize_stmt_block(
|
|||||||
while index < statements.len() {
|
while index < statements.len() {
|
||||||
if preserve_result && index >= statements.len() - 1 {
|
if preserve_result && index >= statements.len() - 1 {
|
||||||
break;
|
break;
|
||||||
} else {
|
}
|
||||||
match statements[index] {
|
match statements[index] {
|
||||||
ref stmt if is_pure(stmt) && index >= first_non_constant => {
|
ref stmt if is_pure(stmt) && index >= first_non_constant => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -317,7 +317,6 @@ fn optimize_stmt_block(
|
|||||||
_ => index += 1,
|
_ => index += 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all pure statements that do not return values at the end of a block.
|
// Remove all pure statements that do not return values at the end of a block.
|
||||||
// We cannot remove anything for non-pure statements due to potential side-effects.
|
// We cannot remove anything for non-pure statements due to potential side-effects.
|
||||||
@ -989,7 +988,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(x, ..) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
Expr::Index(x, ..) if !_chaining => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// array[int]
|
// array[int]
|
||||||
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < a.len() && a.iter().all(Expr::is_pure) => {
|
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && *i <= crate::MAX_USIZE_INT && (*i as usize) < a.len() && a.iter().all(Expr::is_pure) => {
|
||||||
// Array literal where everything is pure - promote the indexed item.
|
// Array literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -998,7 +997,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
*expr = result;
|
*expr = result;
|
||||||
}
|
}
|
||||||
// array[-int]
|
// array[-int]
|
||||||
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= a.len() && a.iter().all(Expr::is_pure) => {
|
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as u64 <= a.len() as u64 && a.iter().all(Expr::is_pure) => {
|
||||||
// Array literal where everything is pure - promote the indexed item.
|
// Array literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -1016,25 +1015,25 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
.map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr });
|
.map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr });
|
||||||
}
|
}
|
||||||
// int[int]
|
// int[int]
|
||||||
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < crate::INT_BITS => {
|
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && *i <= crate::MAX_USIZE_INT && (*i as usize) < crate::INT_BITS => {
|
||||||
// Bit-field literal indexing - get the bit
|
// Bit-field literal indexing - get the bit
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
|
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
|
||||||
}
|
}
|
||||||
// int[-int]
|
// int[-int]
|
||||||
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= crate::INT_BITS => {
|
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as u64 <= crate::INT_BITS as u64 => {
|
||||||
// Bit-field literal indexing - get the bit
|
// Bit-field literal indexing - get the bit
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.unsigned_abs() as usize))) != 0, *pos);
|
*expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.unsigned_abs() as usize))) != 0, *pos);
|
||||||
}
|
}
|
||||||
// string[int]
|
// string[int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && *i <= crate::MAX_USIZE_INT && (*i as usize) < s.chars().count() => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
|
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
|
||||||
}
|
}
|
||||||
// string[-int]
|
// string[-int]
|
||||||
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= s.chars().count() => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as u64 <= s.chars().count() as u64 => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.chars().rev().nth(i.unsigned_abs() as usize - 1).unwrap(), *pos);
|
*expr = Expr::CharConstant(s.chars().rev().nth(i.unsigned_abs() as usize - 1).unwrap(), *pos);
|
||||||
|
@ -5,7 +5,7 @@ use crate::eval::{calc_index, calc_offset_len};
|
|||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
|
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
|
||||||
Position, RhaiResultOf, StaticVec, ERR, INT,
|
Position, RhaiResultOf, StaticVec, ERR, INT, MAX_USIZE_INT,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -217,6 +217,8 @@ pub mod array_functions {
|
|||||||
len: INT,
|
len: INT,
|
||||||
item: Dynamic,
|
item: Dynamic,
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
|
let len = len.min(MAX_USIZE_INT);
|
||||||
|
|
||||||
if len <= 0 || (len as usize) <= array.len() {
|
if len <= 0 || (len as usize) <= array.len() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -369,6 +371,8 @@ pub mod array_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn truncate(array: &mut Array, len: INT) {
|
pub fn truncate(array: &mut Array, len: INT) {
|
||||||
if !array.is_empty() {
|
if !array.is_empty() {
|
||||||
|
let len = len.min(MAX_USIZE_INT);
|
||||||
|
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
array.truncate(len as usize);
|
array.truncate(len as usize);
|
||||||
} else {
|
} else {
|
||||||
@ -396,6 +400,8 @@ pub mod array_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn chop(array: &mut Array, len: INT) {
|
pub fn chop(array: &mut Array, len: INT) {
|
||||||
if !array.is_empty() {
|
if !array.is_empty() {
|
||||||
|
let len = len.min(MAX_USIZE_INT);
|
||||||
|
|
||||||
if len <= 0 {
|
if len <= 0 {
|
||||||
array.clear();
|
array.clear();
|
||||||
} else if (len as usize) < array.len() {
|
} else if (len as usize) < array.len() {
|
||||||
@ -1306,8 +1312,7 @@ pub mod array_functions {
|
|||||||
///
|
///
|
||||||
/// print(x); // prints "[1, 2, 3, 4, 3, 2, 1]"
|
/// print(x); // prints "[1, 2, 3, 4, 3, 2, 1]"
|
||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(return_raw)]
|
pub fn dedup(ctx: NativeCallContext, array: &mut Array) {
|
||||||
pub fn dedup(ctx: NativeCallContext, array: &mut Array) -> RhaiResultOf<()> {
|
|
||||||
let comparer = FnPtr::new_unchecked(OP_EQUALS, StaticVec::new_const());
|
let comparer = FnPtr::new_unchecked(OP_EQUALS, StaticVec::new_const());
|
||||||
dedup_by_comparer(ctx, array, comparer)
|
dedup_by_comparer(ctx, array, comparer)
|
||||||
}
|
}
|
||||||
@ -1334,14 +1339,10 @@ pub mod array_functions {
|
|||||||
///
|
///
|
||||||
/// print(x); // prints "[1, 2, 3, 4]"
|
/// print(x); // prints "[1, 2, 3, 4]"
|
||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "dedup", return_raw)]
|
#[rhai_fn(name = "dedup")]
|
||||||
pub fn dedup_by_comparer(
|
pub fn dedup_by_comparer(ctx: NativeCallContext, array: &mut Array, comparer: FnPtr) {
|
||||||
ctx: NativeCallContext,
|
|
||||||
array: &mut Array,
|
|
||||||
comparer: FnPtr,
|
|
||||||
) -> RhaiResultOf<()> {
|
|
||||||
if array.is_empty() {
|
if array.is_empty() {
|
||||||
return Ok(());
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
array.dedup_by(|x, y| {
|
array.dedup_by(|x, y| {
|
||||||
@ -1351,8 +1352,6 @@ pub mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
/// Remove duplicated _consecutive_ elements from the array that return `true` when applied a
|
/// Remove duplicated _consecutive_ elements from the array that return `true` when applied a
|
||||||
/// function named by `comparer`.
|
/// function named by `comparer`.
|
||||||
@ -1385,7 +1384,7 @@ pub mod array_functions {
|
|||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
comparer: &str,
|
comparer: &str,
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
dedup_by_comparer(ctx, array, FnPtr::new(comparer)?)
|
Ok(dedup_by_comparer(ctx, array, FnPtr::new(comparer)?))
|
||||||
}
|
}
|
||||||
/// Reduce an array by iterating through all elements while applying the `reducer` function.
|
/// Reduce an array by iterating through all elements while applying the `reducer` function.
|
||||||
///
|
///
|
||||||
|
@ -4,7 +4,7 @@ use crate::eval::{calc_index, calc_offset_len};
|
|||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position,
|
def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position,
|
||||||
RhaiResultOf, INT, INT_BYTES,
|
RhaiResultOf, INT, INT_BYTES, MAX_USIZE_INT,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -74,6 +74,7 @@ pub mod blob_functions {
|
|||||||
len: INT,
|
len: INT,
|
||||||
value: INT,
|
value: INT,
|
||||||
) -> RhaiResultOf<Blob> {
|
) -> RhaiResultOf<Blob> {
|
||||||
|
let len = len.min(MAX_USIZE_INT);
|
||||||
let len = if len < 0 { 0 } else { len as usize };
|
let len = if len < 0 { 0 } else { len as usize };
|
||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
@ -342,20 +343,21 @@ pub mod blob_functions {
|
|||||||
if len <= 0 {
|
if len <= 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
|
|
||||||
let value = (value & 0x0000_00ff) as u8;
|
let value = (value & 0x0000_00ff) as u8;
|
||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if blob will be over max size limit
|
// Check if blob will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_array_size() > 0 && (len as usize) > _ctx.engine().max_array_size() {
|
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
||||||
return Err(
|
return Err(
|
||||||
crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(),
|
crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if len as usize > blob.len() {
|
if len > blob.len() {
|
||||||
blob.resize(len as usize, value);
|
blob.resize(len, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -461,7 +463,9 @@ pub mod blob_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn truncate(blob: &mut Blob, len: INT) {
|
pub fn truncate(blob: &mut Blob, len: INT) {
|
||||||
if !blob.is_empty() {
|
if !blob.is_empty() {
|
||||||
if len >= 0 {
|
let len = len.min(MAX_USIZE_INT);
|
||||||
|
|
||||||
|
if len > 0 {
|
||||||
blob.truncate(len as usize);
|
blob.truncate(len as usize);
|
||||||
} else {
|
} else {
|
||||||
blob.clear();
|
blob.clear();
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::eval::calc_index;
|
use crate::eval::calc_index;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS};
|
use crate::{
|
||||||
|
def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS, MAX_USIZE_INT,
|
||||||
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
@ -173,18 +175,13 @@ pub struct CharsStream(Vec<char>, usize);
|
|||||||
|
|
||||||
impl CharsStream {
|
impl CharsStream {
|
||||||
pub fn new(string: &str, from: INT, len: INT) -> Self {
|
pub fn new(string: &str, from: INT, len: INT) -> Self {
|
||||||
if len <= 0 {
|
if len <= 0 || from > MAX_USIZE_INT {
|
||||||
return Self(Vec::new(), 0);
|
return Self(Vec::new(), 0);
|
||||||
}
|
}
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
|
|
||||||
if from >= 0 {
|
if from >= 0 {
|
||||||
return Self(
|
return Self(string.chars().skip(from as usize).take(len).collect(), 0);
|
||||||
string
|
|
||||||
.chars()
|
|
||||||
.skip(from as usize)
|
|
||||||
.take(len as usize)
|
|
||||||
.collect(),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let abs_from = from.unsigned_abs() as usize;
|
let abs_from = from.unsigned_abs() as usize;
|
||||||
@ -194,7 +191,7 @@ impl CharsStream {
|
|||||||
} else {
|
} else {
|
||||||
num_chars - abs_from
|
num_chars - abs_from
|
||||||
};
|
};
|
||||||
Self(string.chars().skip(offset).take(len as usize).collect(), 0)
|
Self(string.chars().skip(offset).take(len).collect(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::types::dynamic::Tag;
|
use crate::types::dynamic::Tag;
|
||||||
use crate::{Dynamic, RhaiResultOf, ERR, INT};
|
use crate::{Dynamic, RhaiResultOf, ERR, INT, MAX_USIZE_INT};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ mod reflection_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "get_fn_metadata_list")]
|
#[rhai_fn(name = "get_fn_metadata_list")]
|
||||||
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array {
|
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array {
|
||||||
if params < 0 {
|
if params < 0 || params > MAX_USIZE_INT {
|
||||||
crate::Array::new()
|
crate::Array::new()
|
||||||
} else {
|
} else {
|
||||||
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
|
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT};
|
use crate::{
|
||||||
|
def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT,
|
||||||
|
MAX_USIZE_INT,
|
||||||
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{any::TypeId, mem};
|
use std::{any::TypeId, mem};
|
||||||
@ -263,10 +266,11 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn truncate(string: &mut ImmutableString, len: INT) {
|
pub fn truncate(string: &mut ImmutableString, len: INT) {
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
let chars: StaticVec<_> = string.chars().collect();
|
let chars: StaticVec<_> = string.chars().collect();
|
||||||
let copy = string.make_mut();
|
let copy = string.make_mut();
|
||||||
copy.clear();
|
copy.clear();
|
||||||
copy.extend(chars.into_iter().take(len as usize));
|
copy.extend(chars.into_iter().take(len));
|
||||||
} else {
|
} else {
|
||||||
clear(string);
|
clear(string);
|
||||||
}
|
}
|
||||||
@ -344,8 +348,9 @@ mod string_functions {
|
|||||||
if string.is_empty() || len <= 0 {
|
if string.is_empty() || len <= 0 {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().get_interned_string("");
|
||||||
}
|
}
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
|
|
||||||
let mut chars = StaticVec::<char>::with_capacity(len as usize);
|
let mut chars = StaticVec::<char>::with_capacity(len);
|
||||||
|
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
match string.make_mut().pop() {
|
match string.make_mut().pop() {
|
||||||
@ -556,7 +561,13 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let abs_start = start.unsigned_abs() as usize;
|
let abs_start = start.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return -1 as INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_start = abs_start as usize;
|
||||||
let chars: Vec<_> = string.chars().collect();
|
let chars: Vec<_> = string.chars().collect();
|
||||||
let num_chars = chars.len();
|
let num_chars = chars.len();
|
||||||
if abs_start > num_chars {
|
if abs_start > num_chars {
|
||||||
@ -570,7 +581,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
} else if start == 0 {
|
} else if start == 0 {
|
||||||
0
|
0
|
||||||
} else if start as usize >= string.chars().count() {
|
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
||||||
return -1 as INT;
|
return -1 as INT;
|
||||||
} else {
|
} else {
|
||||||
string
|
string
|
||||||
@ -632,7 +643,13 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let start = if start < 0 {
|
let start = if start < 0 {
|
||||||
let abs_start = start.unsigned_abs() as usize;
|
let abs_start = start.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return -1 as INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_start = abs_start as usize;
|
||||||
let chars = string.chars().collect::<Vec<_>>();
|
let chars = string.chars().collect::<Vec<_>>();
|
||||||
let num_chars = chars.len();
|
let num_chars = chars.len();
|
||||||
if abs_start > num_chars {
|
if abs_start > num_chars {
|
||||||
@ -646,7 +663,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
} else if start == 0 {
|
} else if start == 0 {
|
||||||
0
|
0
|
||||||
} else if start as usize >= string.chars().count() {
|
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
||||||
return -1 as INT;
|
return -1 as INT;
|
||||||
} else {
|
} else {
|
||||||
string
|
string
|
||||||
@ -704,16 +721,26 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn get(string: &str, index: INT) -> Dynamic {
|
pub fn get(string: &str, index: INT) -> Dynamic {
|
||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
|
if index > MAX_USIZE_INT {
|
||||||
|
return Dynamic::UNIT;
|
||||||
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
.chars()
|
.chars()
|
||||||
.nth(index as usize)
|
.nth(index as usize)
|
||||||
.map_or_else(|| Dynamic::UNIT, Into::into)
|
.map_or_else(|| Dynamic::UNIT, Into::into)
|
||||||
} else {
|
} else {
|
||||||
// Count from end if negative
|
// Count from end if negative
|
||||||
|
let abs_index = index.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_index as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return Dynamic::UNIT;
|
||||||
|
}
|
||||||
|
|
||||||
string
|
string
|
||||||
.chars()
|
.chars()
|
||||||
.rev()
|
.rev()
|
||||||
.nth((index.unsigned_abs() as usize) - 1)
|
.nth((abs_index as usize) - 1)
|
||||||
.map_or_else(|| Dynamic::UNIT, Into::into)
|
.map_or_else(|| Dynamic::UNIT, Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -742,14 +769,25 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn set(string: &mut ImmutableString, index: INT, character: char) {
|
pub fn set(string: &mut ImmutableString, index: INT, character: char) {
|
||||||
if index >= 0 {
|
if index >= 0 {
|
||||||
|
if index > MAX_USIZE_INT {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let index = index as usize;
|
let index = index as usize;
|
||||||
|
|
||||||
*string = string
|
*string = string
|
||||||
.chars()
|
.chars()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, ch)| if i == index { character } else { ch })
|
.map(|(i, ch)| if i == index { character } else { ch })
|
||||||
.collect();
|
.collect();
|
||||||
} else {
|
} else {
|
||||||
let abs_index = index.unsigned_abs() as usize;
|
let abs_index = index.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_index as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_index = abs_index as usize;
|
||||||
let string_len = string.chars().count();
|
let string_len = string.chars().count();
|
||||||
|
|
||||||
if abs_index <= string_len {
|
if abs_index <= string_len {
|
||||||
@ -833,14 +871,20 @@ mod string_functions {
|
|||||||
let offset = if string.is_empty() || len <= 0 {
|
let offset = if string.is_empty() || len <= 0 {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().get_interned_string("");
|
||||||
} else if start < 0 {
|
} else if start < 0 {
|
||||||
let abs_start = start.unsigned_abs() as usize;
|
let abs_start = start.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return ctx.engine().get_interned_string("");
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_start = abs_start as usize;
|
||||||
chars.extend(string.chars());
|
chars.extend(string.chars());
|
||||||
if abs_start > chars.len() {
|
if abs_start > chars.len() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
chars.len() - abs_start
|
chars.len() - abs_start
|
||||||
}
|
}
|
||||||
} else if start as usize >= string.chars().count() {
|
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().get_interned_string("");
|
||||||
} else {
|
} else {
|
||||||
start as usize
|
start as usize
|
||||||
@ -962,14 +1006,20 @@ mod string_functions {
|
|||||||
string.make_mut().clear();
|
string.make_mut().clear();
|
||||||
return;
|
return;
|
||||||
} else if start < 0 {
|
} else if start < 0 {
|
||||||
let abs_start = start.unsigned_abs() as usize;
|
let abs_start = start.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_start = abs_start as usize;
|
||||||
chars.extend(string.chars());
|
chars.extend(string.chars());
|
||||||
if abs_start > chars.len() {
|
if abs_start > chars.len() {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
chars.len() - abs_start
|
chars.len() - abs_start
|
||||||
}
|
}
|
||||||
} else if start as usize >= string.chars().count() {
|
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
||||||
string.make_mut().clear();
|
string.make_mut().clear();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -1131,11 +1181,12 @@ mod string_functions {
|
|||||||
if len <= 0 {
|
if len <= 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(crate::ERR::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
crate::Position::NONE,
|
crate::Position::NONE,
|
||||||
@ -1145,10 +1196,10 @@ mod string_functions {
|
|||||||
|
|
||||||
let orig_len = string.chars().count();
|
let orig_len = string.chars().count();
|
||||||
|
|
||||||
if len as usize > orig_len {
|
if len > orig_len {
|
||||||
let p = string.make_mut();
|
let p = string.make_mut();
|
||||||
|
|
||||||
for _ in 0..(len as usize - orig_len) {
|
for _ in 0..(len - orig_len) {
|
||||||
p.push(character);
|
p.push(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,11 +1243,12 @@ mod string_functions {
|
|||||||
if len <= 0 {
|
if len <= 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
|
||||||
return Err(crate::ERR::ErrorDataTooLarge(
|
return Err(crate::ERR::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
crate::Position::NONE,
|
crate::Position::NONE,
|
||||||
@ -1207,16 +1259,16 @@ mod string_functions {
|
|||||||
let mut str_len = string.chars().count();
|
let mut str_len = string.chars().count();
|
||||||
let padding_len = padding.chars().count();
|
let padding_len = padding.chars().count();
|
||||||
|
|
||||||
if len as usize > str_len {
|
if len > str_len {
|
||||||
let p = string.make_mut();
|
let p = string.make_mut();
|
||||||
|
|
||||||
while str_len < len as usize {
|
while str_len < len {
|
||||||
if str_len + padding_len <= len as usize {
|
if str_len + padding_len <= len {
|
||||||
p.push_str(padding);
|
p.push_str(padding);
|
||||||
str_len += padding_len;
|
str_len += padding_len;
|
||||||
} else {
|
} else {
|
||||||
p.extend(padding.chars().take(len as usize - str_len));
|
p.extend(padding.chars().take(len - str_len));
|
||||||
str_len = len as usize;
|
str_len = len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1263,7 +1315,16 @@ mod string_functions {
|
|||||||
#[rhai_fn(name = "split")]
|
#[rhai_fn(name = "split")]
|
||||||
pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array {
|
pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array {
|
||||||
if index <= 0 {
|
if index <= 0 {
|
||||||
let abs_index = index.unsigned_abs() as usize;
|
let abs_index = index.unsigned_abs();
|
||||||
|
|
||||||
|
if abs_index as u64 > MAX_USIZE_INT as u64 {
|
||||||
|
return vec![
|
||||||
|
ctx.engine().get_interned_string("").into(),
|
||||||
|
string.as_str().into(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
let abs_index = abs_index as usize;
|
||||||
let num_chars = string.chars().count();
|
let num_chars = string.chars().count();
|
||||||
if abs_index > num_chars {
|
if abs_index > num_chars {
|
||||||
vec![
|
vec![
|
||||||
@ -1275,6 +1336,11 @@ mod string_functions {
|
|||||||
let prefix_len = prefix.len();
|
let prefix_len = prefix.len();
|
||||||
vec![prefix.into(), string[prefix_len..].into()]
|
vec![prefix.into(), string[prefix_len..].into()]
|
||||||
}
|
}
|
||||||
|
} else if index > MAX_USIZE_INT {
|
||||||
|
vec![
|
||||||
|
string.as_str().into(),
|
||||||
|
ctx.engine().get_interned_string("").into(),
|
||||||
|
]
|
||||||
} else {
|
} else {
|
||||||
let prefix: String = string.chars().take(index as usize).collect();
|
let prefix: String = string.chars().take(index as usize).collect();
|
||||||
let prefix_len = prefix.len();
|
let prefix_len = prefix.len();
|
||||||
@ -1341,7 +1407,8 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "split")]
|
#[rhai_fn(name = "split")]
|
||||||
pub fn splitn(string: &str, delimiter: &str, segments: INT) -> Array {
|
pub fn splitn(string: &str, delimiter: &str, segments: INT) -> Array {
|
||||||
let pieces: usize = if segments < 1 { 1 } else { segments as usize };
|
let segments = segments.min(MAX_USIZE_INT) as usize;
|
||||||
|
let pieces: usize = if segments < 1 { 1 } else { segments };
|
||||||
string.splitn(pieces, delimiter).map(Into::into).collect()
|
string.splitn(pieces, delimiter).map(Into::into).collect()
|
||||||
}
|
}
|
||||||
/// Split the string into segments based on a `delimiter` character, returning an array of the segments.
|
/// Split the string into segments based on a `delimiter` character, returning an array of the segments.
|
||||||
@ -1371,7 +1438,8 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "split")]
|
#[rhai_fn(name = "split")]
|
||||||
pub fn splitn_char(string: &str, delimiter: char, segments: INT) -> Array {
|
pub fn splitn_char(string: &str, delimiter: char, segments: INT) -> Array {
|
||||||
let pieces: usize = if segments < 1 { 1 } else { segments as usize };
|
let segments = segments.min(MAX_USIZE_INT) as usize;
|
||||||
|
let pieces: usize = if segments < 1 { 1 } else { segments };
|
||||||
string.splitn(pieces, delimiter).map(Into::into).collect()
|
string.splitn(pieces, delimiter).map(Into::into).collect()
|
||||||
}
|
}
|
||||||
/// Split the string into segments based on a `delimiter` string, returning an array of the
|
/// Split the string into segments based on a `delimiter` string, returning an array of the
|
||||||
@ -1402,7 +1470,8 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "split_rev")]
|
#[rhai_fn(name = "split_rev")]
|
||||||
pub fn rsplitn(string: &str, delimiter: &str, segments: INT) -> Array {
|
pub fn rsplitn(string: &str, delimiter: &str, segments: INT) -> Array {
|
||||||
let pieces: usize = if segments < 1 { 1 } else { segments as usize };
|
let segments = segments.min(MAX_USIZE_INT) as usize;
|
||||||
|
let pieces: usize = if segments < 1 { 1 } else { segments };
|
||||||
string.rsplitn(pieces, delimiter).map(Into::into).collect()
|
string.rsplitn(pieces, delimiter).map(Into::into).collect()
|
||||||
}
|
}
|
||||||
/// Split the string into segments based on a `delimiter` character, returning an array of
|
/// Split the string into segments based on a `delimiter` character, returning an array of
|
||||||
@ -1433,7 +1502,8 @@ mod string_functions {
|
|||||||
/// ```
|
/// ```
|
||||||
#[rhai_fn(name = "split_rev")]
|
#[rhai_fn(name = "split_rev")]
|
||||||
pub fn rsplitn_char(string: &str, delimiter: char, segments: INT) -> Array {
|
pub fn rsplitn_char(string: &str, delimiter: char, segments: INT) -> Array {
|
||||||
let pieces: usize = if segments < 1 { 1 } else { segments as usize };
|
let segments = segments.min(MAX_USIZE_INT) as usize;
|
||||||
|
let pieces: usize = if segments < 1 { 1 } else { segments };
|
||||||
string.rsplitn(pieces, delimiter).map(Into::into).collect()
|
string.rsplitn(pieces, delimiter).map(Into::into).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,10 @@ pub type ParseResult<T> = Result<T, ParseError>;
|
|||||||
|
|
||||||
type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>;
|
type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>;
|
||||||
|
|
||||||
|
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
|
||||||
|
|
||||||
|
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
|
||||||
|
|
||||||
/// Invalid variable name that acts as a search barrier in a [`Scope`].
|
/// Invalid variable name that acts as a search barrier in a [`Scope`].
|
||||||
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
|
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
|
||||||
|
|
||||||
@ -41,8 +45,9 @@ const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
|
|||||||
const NEVER_ENDS: &str = "`Token`";
|
const NEVER_ENDS: &str = "`Token`";
|
||||||
|
|
||||||
/// Unroll `switch` ranges no larger than this.
|
/// Unroll `switch` ranges no larger than this.
|
||||||
const SMALL_SWITCH_RANGE: usize = 16;
|
const SMALL_SWITCH_RANGE: INT = 16;
|
||||||
|
|
||||||
|
/// Number of string interners used: two additional for property getters/setters if not `no_object`
|
||||||
const NUM_INTERNERS: usize = if cfg!(feature = "no_object") { 1 } else { 3 };
|
const NUM_INTERNERS: usize = if cfg!(feature = "no_object") { 1 } else { 3 };
|
||||||
|
|
||||||
/// _(internals)_ A type that encapsulates the current state of the parser.
|
/// _(internals)_ A type that encapsulates the current state of the parser.
|
||||||
@ -899,13 +904,13 @@ impl Engine {
|
|||||||
let mut settings = settings;
|
let mut settings = settings;
|
||||||
settings.pos = eat_token(input, Token::LeftBracket);
|
settings.pos = eat_token(input, Token::LeftBracket);
|
||||||
|
|
||||||
let mut arr = StaticVec::new_const();
|
let mut array = StaticVec::new_const();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
const MISSING_RBRACKET: &str = "to end this array literal";
|
const MISSING_RBRACKET: &str = "to end this array literal";
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.max_array_size() > 0 && arr.len() >= self.max_array_size() {
|
if self.max_array_size() > 0 && array.len() >= self.max_array_size() {
|
||||||
return Err(PERR::LiteralTooLarge(
|
return Err(PERR::LiteralTooLarge(
|
||||||
"Size of array literal".to_string(),
|
"Size of array literal".to_string(),
|
||||||
self.max_array_size(),
|
self.max_array_size(),
|
||||||
@ -927,7 +932,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
let expr = self.parse_expr(input, state, lib, settings.level_up())?;
|
||||||
arr.push(expr);
|
array.push(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,9 +959,9 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.shrink_to_fit();
|
array.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::Array(arr.into(), settings.pos))
|
Ok(Expr::Array(array.into(), settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a map literal.
|
/// Parse a map literal.
|
||||||
@ -1306,6 +1311,7 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
|
is_property: bool,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> ParseResult<Expr> {
|
) -> ParseResult<Expr> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -1446,11 +1452,11 @@ impl Engine {
|
|||||||
|crate::ast::Ident { name, pos }| {
|
|crate::ast::Ident { name, pos }| {
|
||||||
let (index, is_func) = state.access_var(name, lib, *pos);
|
let (index, is_func) = state.access_var(name, lib, *pos);
|
||||||
|
|
||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if !is_func
|
||||||
&& !settings.in_closure
|
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
|
&& !settings.in_closure
|
||||||
|
&& settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& !state.scope.contains(name)
|
&& !state.scope.contains(name)
|
||||||
&& !is_func
|
|
||||||
{
|
{
|
||||||
// If the parent scope is not inside another capturing closure
|
// If the parent scope is not inside another capturing closure
|
||||||
// then we can conclude that the captured variable doesn't exist.
|
// then we can conclude that the captured variable doesn't exist.
|
||||||
@ -1583,20 +1589,18 @@ impl Engine {
|
|||||||
// Once the identifier consumed we must enable next variables capturing
|
// Once the identifier consumed we must enable next variables capturing
|
||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(
|
let name = state.get_interned_string(s);
|
||||||
(None, ns, 0, state.get_interned_string(s)).into(),
|
Expr::Variable((None, ns, 0, name).into(), None, settings.pos)
|
||||||
None,
|
|
||||||
settings.pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
_ => {
|
_ => {
|
||||||
let (index, is_func) = state.access_var(&s, lib, settings.pos);
|
let (index, is_func) = state.access_var(&s, lib, settings.pos);
|
||||||
|
|
||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if !is_property
|
||||||
&& index.is_none()
|
|
||||||
&& !state.scope.contains(&s)
|
|
||||||
&& !is_func
|
&& !is_func
|
||||||
|
&& index.is_none()
|
||||||
|
&& settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
|
&& !state.scope.contains(&s)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(
|
||||||
PERR::VariableUndefined(s.to_string()).into_err(settings.pos)
|
PERR::VariableUndefined(s.to_string()).into_err(settings.pos)
|
||||||
@ -1610,11 +1614,8 @@ impl Engine {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Expr::Variable(
|
let name = state.get_interned_string(s);
|
||||||
(index, ns, 0, state.get_interned_string(s)).into(),
|
Expr::Variable((index, ns, 0, name).into(), short_index, settings.pos)
|
||||||
short_index,
|
|
||||||
settings.pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1801,7 +1802,7 @@ impl Engine {
|
|||||||
(.., pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
|
(.., pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs = self.parse_primary(input, state, lib, settings.level_up())?;
|
let rhs = self.parse_primary(input, state, lib, true, settings.level_up())?;
|
||||||
let op_flags = match op {
|
let op_flags = match op {
|
||||||
Token::Period => ASTFlags::NONE,
|
Token::Period => ASTFlags::NONE,
|
||||||
Token::Elvis => ASTFlags::NEGATED,
|
Token::Elvis => ASTFlags::NEGATED,
|
||||||
@ -1971,7 +1972,7 @@ impl Engine {
|
|||||||
// <EOF>
|
// <EOF>
|
||||||
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
// All other tokens
|
// All other tokens
|
||||||
_ => self.parse_primary(input, state, lib, settings.level_up()),
|
_ => self.parse_primary(input, state, lib, false, settings.level_up()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2010,7 +2011,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let op_info = if let Some(op) = op {
|
let op_info = if let Some(ref op) = op {
|
||||||
OpAssignment::new_op_assignment_from_token(op, op_pos)
|
OpAssignment::new_op_assignment_from_token(op, op_pos)
|
||||||
} else {
|
} else {
|
||||||
OpAssignment::new_assignment(op_pos)
|
OpAssignment::new_assignment(op_pos)
|
||||||
@ -2605,9 +2606,6 @@ impl Engine {
|
|||||||
inputs.shrink_to_fit();
|
inputs.shrink_to_fit();
|
||||||
tokens.shrink_to_fit();
|
tokens.shrink_to_fit();
|
||||||
|
|
||||||
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
|
|
||||||
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
|
|
||||||
|
|
||||||
let self_terminated = matches!(
|
let self_terminated = matches!(
|
||||||
required_token.as_str(),
|
required_token.as_str(),
|
||||||
// It is self-terminating if the last symbol is a block
|
// It is self-terminating if the last symbol is a block
|
||||||
@ -2912,7 +2910,7 @@ impl Engine {
|
|||||||
Ok(true) => (),
|
Ok(true) => (),
|
||||||
Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
|
Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
|
||||||
Err(err) => match *err {
|
Err(err) => match *err {
|
||||||
EvalAltResult::ErrorParsing(perr, pos) => return Err(perr.into_err(pos)),
|
EvalAltResult::ErrorParsing(e, pos) => return Err(e.into_err(pos)),
|
||||||
_ => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
|
_ => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! reify {
|
macro_rules! reify {
|
||||||
($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{
|
($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{
|
||||||
|
#[allow(clippy::redundant_else)]
|
||||||
if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) {
|
if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) {
|
||||||
// SAFETY: This is safe because we already checked to make sure the two types
|
// SAFETY: This is safe because we already checked to make sure the two types
|
||||||
// are actually the same.
|
// are actually the same.
|
||||||
|
@ -22,7 +22,7 @@ impl<'de> DynamicDeserializer<'de> {
|
|||||||
/// The reference is necessary because the deserialized type may hold references
|
/// The reference is necessary because the deserialized type may hold references
|
||||||
/// (especially `&str`) to the source [`Dynamic`][crate::Dynamic].
|
/// (especially `&str`) to the source [`Dynamic`][crate::Dynamic].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_dynamic(value: &'de Dynamic) -> Self {
|
pub const fn from_dynamic(value: &'de Dynamic) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
/// Shortcut for a type conversion error.
|
/// Shortcut for a type conversion error.
|
||||||
@ -449,7 +449,9 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
visitor.visit_enum(s.as_str().into_deserializer())
|
visitor.visit_enum(s.as_str().into_deserializer())
|
||||||
} else {
|
} else {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
if let Some(map) = self.value.downcast_ref::<crate::Map>() {
|
return self.value.downcast_ref::<crate::Map>().map_or_else(
|
||||||
|
|| self.type_error(),
|
||||||
|
|map| {
|
||||||
let mut iter = map.iter();
|
let mut iter = map.iter();
|
||||||
let first = iter.next();
|
let first = iter.next();
|
||||||
let second = iter.next();
|
let second = iter.next();
|
||||||
@ -461,9 +463,8 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
} else {
|
} else {
|
||||||
self.type_error()
|
self.type_error()
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
self.type_error()
|
);
|
||||||
}
|
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return self.type_error();
|
return self.type_error();
|
||||||
}
|
}
|
||||||
@ -488,7 +489,7 @@ struct IterateDynamicArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateDynamicArray<'a, ITER> {
|
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateDynamicArray<'a, ITER> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(iter: ITER) -> Self {
|
pub const fn new(iter: ITER) -> Self {
|
||||||
Self { iter }
|
Self { iter }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -525,7 +526,7 @@ struct IterateMap<'a, K: Iterator<Item = &'a str>, V: Iterator<Item = &'a Dynami
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
impl<'a, K: Iterator<Item = &'a str>, V: Iterator<Item = &'a Dynamic>> IterateMap<'a, K, V> {
|
impl<'a, K: Iterator<Item = &'a str>, V: Iterator<Item = &'a Dynamic>> IterateMap<'a, K, V> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(keys: K, values: V) -> Self {
|
pub const fn new(keys: K, values: V) -> Self {
|
||||||
Self { keys, values }
|
Self { keys, values }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ impl PartialOrd for FnMetadata<'_> {
|
|||||||
|
|
||||||
impl Ord for FnMetadata<'_> {
|
impl Ord for FnMetadata<'_> {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
match self.name.cmp(&other.name) {
|
match self.name.cmp(other.name) {
|
||||||
Ordering::Equal => self.num_params.cmp(&other.num_params),
|
Ordering::Equal => self.num_params.cmp(&other.num_params),
|
||||||
cmp => cmp,
|
cmp => cmp,
|
||||||
}
|
}
|
||||||
@ -79,8 +79,8 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> {
|
|||||||
base_hash,
|
base_hash,
|
||||||
full_hash,
|
full_hash,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace: info.metadata.namespace.into(),
|
namespace: info.metadata.namespace,
|
||||||
access: info.metadata.access.into(),
|
access: info.metadata.access,
|
||||||
name: &info.metadata.name,
|
name: &info.metadata.name,
|
||||||
typ,
|
typ,
|
||||||
num_params: info.metadata.params,
|
num_params: info.metadata.params,
|
||||||
@ -150,7 +150,7 @@ impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> {
|
|||||||
functions.sort();
|
functions.sort();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
doc: module.doc().into(),
|
doc: module.doc(),
|
||||||
modules: module
|
modules: module
|
||||||
.iter_sub_modules()
|
.iter_sub_modules()
|
||||||
.map(|(name, m)| (name, m.as_ref().into()))
|
.map(|(name, m)| (name, m.as_ref().into()))
|
||||||
@ -206,7 +206,7 @@ pub fn gen_metadata_to_json(
|
|||||||
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
if let Some(ast) = _ast {
|
if let Some(ast) = _ast {
|
||||||
global.doc = ast.doc().into();
|
global.doc = ast.doc();
|
||||||
}
|
}
|
||||||
|
|
||||||
serde_json::to_string_pretty(&global)
|
serde_json::to_string_pretty(&global)
|
||||||
|
@ -20,7 +20,7 @@ struct DynamicSerializer {
|
|||||||
impl DynamicSerializer {
|
impl DynamicSerializer {
|
||||||
/// Create a [`DynamicSerializer`] from a [`Dynamic`][crate::Dynamic] value.
|
/// Create a [`DynamicSerializer`] from a [`Dynamic`][crate::Dynamic] value.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(_value: Dynamic) -> Self {
|
pub const fn new(_value: Dynamic) -> Self {
|
||||||
Self {
|
Self {
|
||||||
_key: Dynamic::UNIT,
|
_key: Dynamic::UNIT,
|
||||||
_value,
|
_value,
|
||||||
|
@ -14,7 +14,7 @@ pub struct StringSliceDeserializer<'a> {
|
|||||||
impl<'a> StringSliceDeserializer<'a> {
|
impl<'a> StringSliceDeserializer<'a> {
|
||||||
/// Create an `ImmutableStringDeserializer` from an `&str` reference.
|
/// Create an `ImmutableStringDeserializer` from an `&str` reference.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_str(value: &'a str) -> Self {
|
pub const fn from_str(value: &'a str) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
/// Shortcut for a type conversion error.
|
/// Shortcut for a type conversion error.
|
||||||
|
@ -1701,11 +1701,11 @@ fn get_next_token_inner(
|
|||||||
// letter or underscore ...
|
// letter or underscore ...
|
||||||
#[cfg(not(feature = "unicode-xid-ident"))]
|
#[cfg(not(feature = "unicode-xid-ident"))]
|
||||||
('a'..='z' | '_' | 'A'..='Z', ..) => {
|
('a'..='z' | '_' | 'A'..='Z', ..) => {
|
||||||
return get_identifier(stream, pos, start_pos, c);
|
return Some(get_identifier(stream, pos, start_pos, c));
|
||||||
}
|
}
|
||||||
#[cfg(feature = "unicode-xid-ident")]
|
#[cfg(feature = "unicode-xid-ident")]
|
||||||
(ch, ..) if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' => {
|
(ch, ..) if unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' => {
|
||||||
return get_identifier(stream, pos, start_pos, c);
|
return Some(get_identifier(stream, pos, start_pos, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
// " - string literal
|
// " - string literal
|
||||||
@ -2178,7 +2178,7 @@ fn get_identifier(
|
|||||||
pos: &mut Position,
|
pos: &mut Position,
|
||||||
start_pos: Position,
|
start_pos: Position,
|
||||||
first_char: char,
|
first_char: char,
|
||||||
) -> Option<(Token, Position)> {
|
) -> (Token, Position) {
|
||||||
let mut result = smallvec::SmallVec::<[char; 8]>::new();
|
let mut result = smallvec::SmallVec::<[char; 8]>::new();
|
||||||
result.push(first_char);
|
result.push(first_char);
|
||||||
|
|
||||||
@ -2197,17 +2197,17 @@ fn get_identifier(
|
|||||||
let identifier: String = result.into_iter().collect();
|
let identifier: String = result.into_iter().collect();
|
||||||
|
|
||||||
if let Some(token) = Token::lookup_from_syntax(&identifier) {
|
if let Some(token) = Token::lookup_from_syntax(&identifier) {
|
||||||
return Some((token, start_pos));
|
return (token, start_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_valid_identifier {
|
if !is_valid_identifier {
|
||||||
return Some((
|
return (
|
||||||
Token::LexError(LERR::MalformedIdentifier(identifier).into()),
|
Token::LexError(LERR::MalformedIdentifier(identifier).into()),
|
||||||
start_pos,
|
start_pos,
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((Token::Identifier(identifier.into()), start_pos))
|
(Token::Identifier(identifier.into()), start_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is a keyword allowed as a function?
|
/// Is a keyword allowed as a function?
|
||||||
@ -2272,7 +2272,7 @@ pub fn is_id_continue(x: char) -> bool {
|
|||||||
#[cfg(not(feature = "unicode-xid-ident"))]
|
#[cfg(not(feature = "unicode-xid-ident"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_id_first_alphabetic(x: char) -> bool {
|
pub const fn is_id_first_alphabetic(x: char) -> bool {
|
||||||
x.is_ascii_alphabetic()
|
x.is_ascii_alphabetic()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2280,7 +2280,7 @@ pub fn is_id_first_alphabetic(x: char) -> bool {
|
|||||||
#[cfg(not(feature = "unicode-xid-ident"))]
|
#[cfg(not(feature = "unicode-xid-ident"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_id_continue(x: char) -> bool {
|
pub const fn is_id_continue(x: char) -> bool {
|
||||||
x.is_ascii_alphanumeric() || x == '_'
|
x.is_ascii_alphanumeric() || x == '_'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2315,15 +2315,15 @@ impl InputStream for MultiInputsStream<'_> {
|
|||||||
if self.index >= self.streams.len() {
|
if self.index >= self.streams.len() {
|
||||||
// No more streams
|
// No more streams
|
||||||
return None;
|
return None;
|
||||||
} else if let Some(ch) = self.streams[self.index].next() {
|
}
|
||||||
|
if let Some(ch) = self.streams[self.index].next() {
|
||||||
// Next character in current stream
|
// Next character in current stream
|
||||||
return Some(ch);
|
return Some(ch);
|
||||||
} else {
|
}
|
||||||
// Jump to the next stream
|
// Jump to the next stream
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
fn peek_next(&mut self) -> Option<char> {
|
fn peek_next(&mut self) -> Option<char> {
|
||||||
if let Some(ch) = self.buf {
|
if let Some(ch) = self.buf {
|
||||||
return Some(ch);
|
return Some(ch);
|
||||||
@ -2333,15 +2333,15 @@ impl InputStream for MultiInputsStream<'_> {
|
|||||||
if self.index >= self.streams.len() {
|
if self.index >= self.streams.len() {
|
||||||
// No more streams
|
// No more streams
|
||||||
return None;
|
return None;
|
||||||
} else if let Some(&ch) = self.streams[self.index].peek() {
|
}
|
||||||
|
if let Some(&ch) = self.streams[self.index].peek() {
|
||||||
// Next character in current stream
|
// Next character in current stream
|
||||||
return Some(ch);
|
return Some(ch);
|
||||||
} else {
|
}
|
||||||
// Jump to the next stream
|
// Jump to the next stream
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(internals)_ An iterator on a [`Token`] stream.
|
/// _(internals)_ An iterator on a [`Token`] stream.
|
||||||
|
@ -936,7 +936,7 @@ impl Dynamic {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn from_float(value: crate::FLOAT) -> Self {
|
pub const fn from_float(value: crate::FLOAT) -> Self {
|
||||||
Self(Union::Float(
|
Self(Union::Float(
|
||||||
crate::ast::FloatWrapper::new_const(value),
|
crate::ast::FloatWrapper::new(value),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -1166,7 +1166,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
reify!(value, |v: crate::Blob| {
|
reify!(value, |v: crate::Blob| {
|
||||||
// don't use blob.into() because it'll be converted into an Array
|
// don't use blob.into() because it'll be converted into an Array
|
||||||
return Dynamic::from_blob(v);
|
return Self::from_blob(v);
|
||||||
});
|
});
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
reify!(value, |v: crate::Map| return v.into());
|
reify!(value, |v: crate::Map| return v.into());
|
||||||
@ -1175,7 +1175,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
reify!(value, |v: Instant| return v.into());
|
reify!(value, |v: Instant| return v.into());
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
reify!(value, |v: crate::Shared<crate::Locked<Dynamic>>| return v
|
reify!(value, |v: crate::Shared<crate::Locked<Self>>| return v
|
||||||
.into());
|
.into());
|
||||||
|
|
||||||
Self(Union::Variant(
|
Self(Union::Variant(
|
||||||
@ -1444,7 +1444,7 @@ impl Dynamic {
|
|||||||
let value = crate::func::locked_read(cell);
|
let value = crate::func::locked_read(cell);
|
||||||
|
|
||||||
return if (*value).type_id() != TypeId::of::<T>()
|
return if (*value).type_id() != TypeId::of::<T>()
|
||||||
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
&& TypeId::of::<Self>() != TypeId::of::<T>()
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -1476,7 +1476,7 @@ impl Dynamic {
|
|||||||
let guard = crate::func::locked_write(cell);
|
let guard = crate::func::locked_write(cell);
|
||||||
|
|
||||||
return if (*guard).type_id() != TypeId::of::<T>()
|
return if (*guard).type_id() != TypeId::of::<T>()
|
||||||
&& TypeId::of::<Dynamic>() != TypeId::of::<T>()
|
&& TypeId::of::<Self>() != TypeId::of::<T>()
|
||||||
{
|
{
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
@ -1577,7 +1577,7 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Self>() {
|
||||||
return self.as_any().downcast_ref::<T>();
|
return self.as_any().downcast_ref::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1675,7 +1675,7 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Self>() {
|
||||||
return self.as_any_mut().downcast_mut::<T>();
|
return self.as_any_mut().downcast_mut::<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1962,7 +1962,7 @@ impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: Vec<T>) -> Self {
|
fn from(value: Vec<T>) -> Self {
|
||||||
Self(Union::Array(
|
Self(Union::Array(
|
||||||
Box::new(value.into_iter().map(Dynamic::from).collect()),
|
Box::new(value.into_iter().map(Self::from).collect()),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -1973,7 +1973,7 @@ impl<T: Variant + Clone> From<&[T]> for Dynamic {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: &[T]) -> Self {
|
fn from(value: &[T]) -> Self {
|
||||||
Self(Union::Array(
|
Self(Union::Array(
|
||||||
Box::new(value.iter().cloned().map(Dynamic::from).collect()),
|
Box::new(value.iter().cloned().map(Self::from).collect()),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -1984,7 +1984,7 @@ impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
|
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
|
||||||
Self(Union::Array(
|
Self(Union::Array(
|
||||||
Box::new(iter.into_iter().map(Dynamic::from).collect()),
|
Box::new(iter.into_iter().map(Self::from).collect()),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -2001,7 +2001,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::Hash
|
|||||||
Box::new(
|
Box::new(
|
||||||
value
|
value
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (k.into(), Dynamic::from(v)))
|
.map(|(k, v)| (k.into(), Self::from(v)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
@ -2015,12 +2015,7 @@ impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: std::collections::HashSet<K>) -> Self {
|
fn from(value: std::collections::HashSet<K>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
|
||||||
value
|
|
||||||
.into_iter()
|
|
||||||
.map(|k| (k.into(), Dynamic::UNIT))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -2036,7 +2031,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTre
|
|||||||
Box::new(
|
Box::new(
|
||||||
value
|
value
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| (k.into(), Dynamic::from(v)))
|
.map(|(k, v)| (k.into(), Self::from(v)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
@ -2049,12 +2044,7 @@ impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: std::collections::BTreeSet<K>) -> Self {
|
fn from(value: std::collections::BTreeSet<K>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(value.into_iter().map(|k| (k.into(), Self::UNIT)).collect()),
|
||||||
value
|
|
||||||
.into_iter()
|
|
||||||
.map(|k| (k.into(), Dynamic::UNIT))
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
DEFAULT_TAG_VALUE,
|
DEFAULT_TAG_VALUE,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
))
|
))
|
||||||
@ -2074,7 +2064,7 @@ impl From<Instant> for Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
impl From<crate::Shared<crate::Locked<Dynamic>>> for Dynamic {
|
impl From<crate::Shared<crate::Locked<Self>>> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
|
fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
|
||||||
Self(Union::Shared(value, DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::Shared(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
@ -2084,12 +2074,12 @@ impl From<crate::Shared<crate::Locked<Dynamic>>> for Dynamic {
|
|||||||
impl From<ExclusiveRange> for Dynamic {
|
impl From<ExclusiveRange> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: ExclusiveRange) -> Self {
|
fn from(value: ExclusiveRange) -> Self {
|
||||||
Dynamic::from(value)
|
Self::from(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<InclusiveRange> for Dynamic {
|
impl From<InclusiveRange> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: InclusiveRange) -> Self {
|
fn from(value: InclusiveRange) -> Self {
|
||||||
Dynamic::from(value)
|
Self::from(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,9 +368,6 @@ impl EvalAltResult {
|
|||||||
map.insert("function".into(), f.into());
|
map.insert("function".into(), f.into());
|
||||||
map.insert("source".into(), s.into());
|
map.insert("source".into(), s.into());
|
||||||
}
|
}
|
||||||
Self::ErrorInModule(m, ..) => {
|
|
||||||
map.insert("module".into(), m.into());
|
|
||||||
}
|
|
||||||
Self::ErrorMismatchDataType(r, a, ..) | Self::ErrorMismatchOutputType(r, a, ..) => {
|
Self::ErrorMismatchDataType(r, a, ..) | Self::ErrorMismatchOutputType(r, a, ..) => {
|
||||||
map.insert("requested".into(), r.into());
|
map.insert("requested".into(), r.into());
|
||||||
map.insert("actual".into(), a.into());
|
map.insert("actual".into(), a.into());
|
||||||
@ -381,9 +378,6 @@ impl EvalAltResult {
|
|||||||
map.insert("length".into(), (*n as INT).into());
|
map.insert("length".into(), (*n as INT).into());
|
||||||
map.insert("index".into(), (*i as INT).into());
|
map.insert("index".into(), (*i as INT).into());
|
||||||
}
|
}
|
||||||
Self::ErrorIndexingType(t, ..) => {
|
|
||||||
map.insert("type".into(), t.into());
|
|
||||||
}
|
|
||||||
Self::ErrorVariableExists(v, ..)
|
Self::ErrorVariableExists(v, ..)
|
||||||
| Self::ErrorForbiddenVariable(v, ..)
|
| Self::ErrorForbiddenVariable(v, ..)
|
||||||
| Self::ErrorVariableNotFound(v, ..)
|
| Self::ErrorVariableNotFound(v, ..)
|
||||||
@ -395,14 +389,14 @@ impl EvalAltResult {
|
|||||||
Self::ErrorIndexNotFound(v, ..) => {
|
Self::ErrorIndexNotFound(v, ..) => {
|
||||||
map.insert("index".into(), v.clone());
|
map.insert("index".into(), v.clone());
|
||||||
}
|
}
|
||||||
Self::ErrorModuleNotFound(m, ..) => {
|
Self::ErrorInModule(m, ..) | Self::ErrorModuleNotFound(m, ..) => {
|
||||||
map.insert("module".into(), m.into());
|
map.insert("module".into(), m.into());
|
||||||
}
|
}
|
||||||
Self::ErrorDotExpr(p, ..) => {
|
Self::ErrorDotExpr(p, ..) => {
|
||||||
map.insert("property".into(), p.into());
|
map.insert("property".into(), p.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::ErrorDataTooLarge(t, ..) => {
|
Self::ErrorIndexingType(t, ..) | Self::ErrorDataTooLarge(t, ..) => {
|
||||||
map.insert("type".into(), t.into());
|
map.insert("type".into(), t.into());
|
||||||
}
|
}
|
||||||
Self::ErrorTerminated(t, ..) => {
|
Self::ErrorTerminated(t, ..) => {
|
||||||
|
@ -264,9 +264,9 @@ impl Add<ImmutableString> for &ImmutableString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<&ImmutableString> for ImmutableString {
|
impl AddAssign<&Self> for ImmutableString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, rhs: &ImmutableString) {
|
fn add_assign(&mut self, rhs: &Self) {
|
||||||
if !rhs.is_empty() {
|
if !rhs.is_empty() {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
self.0 = rhs.0.clone();
|
self.0 = rhs.0.clone();
|
||||||
@ -277,9 +277,9 @@ impl AddAssign<&ImmutableString> for ImmutableString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<ImmutableString> for ImmutableString {
|
impl AddAssign<Self> for ImmutableString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, rhs: ImmutableString) {
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
if !rhs.is_empty() {
|
if !rhs.is_empty() {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
self.0 = rhs.0;
|
self.0 = rhs.0;
|
||||||
@ -431,9 +431,9 @@ impl Sub for &ImmutableString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubAssign<&ImmutableString> for ImmutableString {
|
impl SubAssign<&Self> for ImmutableString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub_assign(&mut self, rhs: &ImmutableString) {
|
fn sub_assign(&mut self, rhs: &Self) {
|
||||||
if !rhs.is_empty() {
|
if !rhs.is_empty() {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
self.0 = rhs.0.clone();
|
self.0 = rhs.0.clone();
|
||||||
@ -445,9 +445,9 @@ impl SubAssign<&ImmutableString> for ImmutableString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubAssign<ImmutableString> for ImmutableString {
|
impl SubAssign<Self> for ImmutableString {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn sub_assign(&mut self, rhs: ImmutableString) {
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
if !rhs.is_empty() {
|
if !rhs.is_empty() {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
self.0 = rhs.0;
|
self.0 = rhs.0;
|
||||||
|
@ -64,7 +64,7 @@ impl StringsInterner<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get<S: AsRef<str> + Into<ImmutableString>>(&mut self, text: S) -> ImmutableString {
|
pub fn get<S: AsRef<str> + Into<ImmutableString>>(&mut self, text: S) -> ImmutableString {
|
||||||
self.get_with_mapper(|s| s.into(), text)
|
self.get_with_mapper(Into::into, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an identifier from a text string, adding it to the interner if necessary.
|
/// Get an identifier from a text string, adding it to the interner if necessary.
|
||||||
|
@ -302,13 +302,13 @@ impl ParseError {
|
|||||||
/// Get the [type][ParseErrorType] of this parse error.
|
/// Get the [type][ParseErrorType] of this parse error.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn err_type(&self) -> &ParseErrorType {
|
pub const fn err_type(&self) -> &ParseErrorType {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
/// Get the [position][Position] of this parse error.
|
/// Get the [position][Position] of this parse error.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn position(&self) -> Position {
|
pub const fn position(&self) -> Position {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -323,7 +323,7 @@ impl From<ParseErrorType> for RhaiError {
|
|||||||
impl From<ParseErrorType> for ERR {
|
impl From<ParseErrorType> for ERR {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(err: ParseErrorType) -> Self {
|
fn from(err: ParseErrorType) -> Self {
|
||||||
ERR::ErrorParsing(err, Position::NONE)
|
Self::ErrorParsing(err, Position::NONE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,6 +337,6 @@ impl From<ParseError> for RhaiError {
|
|||||||
impl From<ParseError> for ERR {
|
impl From<ParseError> for ERR {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(err: ParseError) -> Self {
|
fn from(err: ParseError) -> Self {
|
||||||
ERR::ErrorParsing(*err.0, err.1)
|
Self::ErrorParsing(*err.0, err.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use rhai::{CustomType, Engine, EvalAltResult, Position, TypeBuilder, INT};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_type() -> Result<(), Box<EvalAltResult>> {
|
fn build_type() -> Result<(), Box<EvalAltResult>> {
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
struct Vec3 {
|
struct Vec3 {
|
||||||
x: INT,
|
x: INT,
|
||||||
y: INT,
|
y: INT,
|
||||||
@ -60,7 +60,8 @@ fn build_type() -> Result<(), Box<EvalAltResult>> {
|
|||||||
.with_name("Vec3")
|
.with_name("Vec3")
|
||||||
.is_iterable()
|
.is_iterable()
|
||||||
.with_fn("vec3", Self::new)
|
.with_fn("vec3", Self::new)
|
||||||
.is_iterable()
|
.with_fn("==", |x: &mut Vec3, y: Vec3| *x == y)
|
||||||
|
.with_fn("!=", |x: &mut Vec3, y: Vec3| *x != y)
|
||||||
.with_get_set("x", Self::get_x, Self::set_x)
|
.with_get_set("x", Self::get_x, Self::set_x)
|
||||||
.with_get_set("y", Self::get_y, Self::set_y)
|
.with_get_set("y", Self::get_y, Self::set_y)
|
||||||
.with_get_set("z", Self::get_z, Self::set_z);
|
.with_get_set("z", Self::get_z, Self::set_z);
|
||||||
|
@ -56,10 +56,6 @@ fn test_options_allow() -> Result<(), Box<EvalAltResult>> {
|
|||||||
fn test_options_strict_var() -> Result<(), Box<EvalAltResult>> {
|
fn test_options_strict_var() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
let mut scope = Scope::new();
|
|
||||||
scope.push("x", 42 as INT);
|
|
||||||
scope.push_constant("y", 0 as INT);
|
|
||||||
|
|
||||||
engine.compile("let x = if y { z } else { w };")?;
|
engine.compile("let x = if y { z } else { w };")?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
@ -78,9 +74,17 @@ fn test_options_strict_var() -> Result<(), Box<EvalAltResult>> {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
engine.compile("let f = |y| x * y;")?;
|
engine.compile("let f = |y| x * y;")?;
|
||||||
|
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
scope.push("x", 42 as INT);
|
||||||
|
scope.push_constant("y", 0 as INT);
|
||||||
|
|
||||||
engine.set_strict_variables(true);
|
engine.set_strict_variables(true);
|
||||||
|
|
||||||
assert!(engine.compile("let x = if y { z } else { w };").is_err());
|
assert!(engine.compile("let x = if y { z } else { w };").is_err());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
engine.compile_with_scope(&mut scope, "if x.abs() { y } else { x + y.len };")?;
|
||||||
|
|
||||||
engine.compile("let y = 42; let x = y;")?;
|
engine.compile("let y = 42; let x = y;")?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user