Make file structures consistent.
This commit is contained in:
parent
aa2e04bd25
commit
42a14ab4cc
19
src/ast.rs
19
src/ast.rs
@ -1,10 +1,10 @@
|
|||||||
//! Module defining the AST (abstract syntax tree).
|
//! Module defining the AST (abstract syntax tree).
|
||||||
|
|
||||||
|
use crate::calc_fn_hash;
|
||||||
use crate::dynamic::Union;
|
use crate::dynamic::Union;
|
||||||
use crate::fn_native::shared_make_mut;
|
use crate::fn_native::shared_make_mut;
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::calc_fn_hash;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, FnNamespace, Identifier, ImmutableString, Module, Position, Shared, StaticVec, INT,
|
Dynamic, FnNamespace, Identifier, ImmutableString, Module, Position, Shared, StaticVec, INT,
|
||||||
};
|
};
|
||||||
@ -1399,6 +1399,15 @@ pub struct CustomExpr {
|
|||||||
pub tokens: StaticVec<Identifier>,
|
pub tokens: StaticVec<Identifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CustomExpr {
|
||||||
|
/// Convert this into a [`Expr::Custom`].
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn into_custom_syntax_expr(self, pos: Position) -> Expr {
|
||||||
|
Expr::Custom(self.into(), pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A binary expression.
|
/// _(INTERNALS)_ A binary expression.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
@ -1564,6 +1573,12 @@ impl FnCallExpr {
|
|||||||
pub fn is_qualified(&self) -> bool {
|
pub fn is_qualified(&self) -> bool {
|
||||||
self.namespace.is_some()
|
self.namespace.is_some()
|
||||||
}
|
}
|
||||||
|
/// Convert this into a [`FnCall`][Expr::FnCall].
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn into_fn_call_expr(self, pos: Position) -> Expr {
|
||||||
|
Expr::FnCall(self.into(), pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type that wraps a floating-point number and implements [`Hash`].
|
/// A type that wraps a floating-point number and implements [`Hash`].
|
||||||
@ -1730,7 +1745,7 @@ pub enum Expr {
|
|||||||
Position,
|
Position,
|
||||||
Box<(
|
Box<(
|
||||||
Option<NonZeroUsize>,
|
Option<NonZeroUsize>,
|
||||||
Option<(u64, NamespaceRef)>,
|
Option<(NamespaceRef, u64)>,
|
||||||
Identifier,
|
Identifier,
|
||||||
)>,
|
)>,
|
||||||
),
|
),
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
//! Main module defining the script evaluation [`Engine`].
|
//! Main module defining the script evaluation [`Engine`].
|
||||||
|
|
||||||
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt};
|
use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt};
|
||||||
|
use crate::custom_syntax::CustomSyntax;
|
||||||
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||||
|
use crate::fn_hash::get_hasher;
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnVarCallback,
|
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnVarCallback,
|
||||||
};
|
};
|
||||||
@ -9,9 +11,7 @@ use crate::module::NamespaceRef;
|
|||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, StandardPackage};
|
use crate::packages::{Package, StandardPackage};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::syntax::CustomSyntax;
|
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::get_hasher;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResult, Scope,
|
Dynamic, EvalAltResult, Identifier, ImmutableString, Module, Position, RhaiResult, Scope,
|
||||||
Shared, StaticVec, INT,
|
Shared, StaticVec, INT,
|
||||||
@ -1102,17 +1102,17 @@ impl Engine {
|
|||||||
// Normal variable access
|
// Normal variable access
|
||||||
(_, None, _) => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
(_, None, _) => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
||||||
// Qualified variable
|
// Qualified variable
|
||||||
(_, Some((hash_var, modules)), var_name) => {
|
(_, Some((namespace, hash_var)), var_name) => {
|
||||||
let module = self.search_imports(mods, state, modules).ok_or_else(|| {
|
let module = self.search_imports(mods, state, namespace).ok_or_else(|| {
|
||||||
EvalAltResult::ErrorModuleNotFound(
|
EvalAltResult::ErrorModuleNotFound(
|
||||||
modules[0].name.to_string(),
|
namespace[0].name.to_string(),
|
||||||
modules[0].pos,
|
namespace[0].pos,
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
||||||
match *err {
|
match *err {
|
||||||
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
|
||||||
*err_name = format!("{}{}", modules, var_name);
|
*err_name = format!("{}{}", namespace, var_name);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use crate::engine::{EvalContext, Imports, State};
|
|||||||
use crate::fn_native::{FnCallArgs, SendSync};
|
use crate::fn_native::{FnCallArgs, SendSync};
|
||||||
use crate::fn_register::RegisterNativeFunction;
|
use crate::fn_register::RegisterNativeFunction;
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::ParseState;
|
use crate::parse::ParseState;
|
||||||
use crate::{
|
use crate::{
|
||||||
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Identifier, Module,
|
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Identifier, Module,
|
||||||
NativeCallContext, ParseError, Position, RhaiResult, Shared, AST,
|
NativeCallContext, ParseError, Position, RhaiResult, Shared, AST,
|
||||||
|
113
src/fn_hash.rs
Normal file
113
src/fn_hash.rs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//! Module containing utilities to hash functions and function calls.
|
||||||
|
|
||||||
|
#[cfg(feature = "no_std")]
|
||||||
|
use std::prelude::v1::*;
|
||||||
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
|
iter::empty,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A hasher that only takes one single [`u64`] and returns it as a hash key.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics when hashing any data type other than a [`u64`].
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
|
pub struct StraightHasher(u64);
|
||||||
|
|
||||||
|
impl Hasher for StraightHasher {
|
||||||
|
#[inline(always)]
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
fn write(&mut self, bytes: &[u8]) {
|
||||||
|
assert_eq!(bytes.len(), 8, "StraightHasher can only hash u64 values");
|
||||||
|
|
||||||
|
let mut key = [0_u8; 8];
|
||||||
|
key.copy_from_slice(bytes);
|
||||||
|
|
||||||
|
self.0 = u64::from_ne_bytes(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A hash builder for `StraightHasher`.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||||
|
pub struct StraightHasherBuilder;
|
||||||
|
|
||||||
|
impl BuildHasher for StraightHasherBuilder {
|
||||||
|
type Hasher = StraightHasher;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn build_hasher(&self) -> Self::Hasher {
|
||||||
|
StraightHasher(42)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an instance of the default hasher.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_hasher() -> ahash::AHasher {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a [`u64`] hash key from a namespace-qualified function name
|
||||||
|
/// and the number of parameters, but no parameter types.
|
||||||
|
///
|
||||||
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
|
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn calc_qualified_fn_hash<'a>(
|
||||||
|
modules: impl Iterator<Item = &'a str>,
|
||||||
|
fn_name: impl AsRef<str>,
|
||||||
|
num: usize,
|
||||||
|
) -> u64 {
|
||||||
|
let s = &mut get_hasher();
|
||||||
|
|
||||||
|
// We always skip the first module
|
||||||
|
let mut len = 0;
|
||||||
|
modules
|
||||||
|
.inspect(|_| len += 1)
|
||||||
|
.skip(1)
|
||||||
|
.for_each(|m| m.hash(s));
|
||||||
|
len.hash(s);
|
||||||
|
fn_name.as_ref().hash(s);
|
||||||
|
num.hash(s);
|
||||||
|
s.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a [`u64`] hash key from a non-namespace-qualified function name
|
||||||
|
/// and the number of parameters, but no parameter types.
|
||||||
|
///
|
||||||
|
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn calc_fn_hash(fn_name: impl AsRef<str>, num: usize) -> u64 {
|
||||||
|
calc_qualified_fn_hash(empty(), fn_name, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a [`u64`] hash key from a list of parameter types.
|
||||||
|
///
|
||||||
|
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
||||||
|
let s = &mut get_hasher();
|
||||||
|
let mut len = 0;
|
||||||
|
params.inspect(|_| len += 1).for_each(|t| t.hash(s));
|
||||||
|
len.hash(s);
|
||||||
|
s.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combine two [`u64`] hashes by taking the XOR of them.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 {
|
||||||
|
a ^ b
|
||||||
|
}
|
@ -1,124 +1,19 @@
|
|||||||
//! Module containing various utility types and functions.
|
//! The `ImmutableString` type.
|
||||||
|
|
||||||
use crate::fn_native::{shared_make_mut, shared_take};
|
use crate::fn_native::{shared_make_mut, shared_take};
|
||||||
use crate::{Identifier, Shared, SmartString};
|
use crate::{Shared, SmartString};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::Hash,
|
||||||
iter::{empty, FromIterator},
|
iter::FromIterator,
|
||||||
ops::{Add, AddAssign, Deref, Sub, SubAssign},
|
ops::{Add, AddAssign, Deref, Sub, SubAssign},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A hasher that only takes one single [`u64`] and returns it as a hash key.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics when hashing any data type other than a [`u64`].
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
|
||||||
pub struct StraightHasher(u64);
|
|
||||||
|
|
||||||
impl Hasher for StraightHasher {
|
|
||||||
#[inline(always)]
|
|
||||||
fn finish(&self) -> u64 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
#[inline(always)]
|
|
||||||
fn write(&mut self, bytes: &[u8]) {
|
|
||||||
assert_eq!(bytes.len(), 8, "StraightHasher can only hash u64 values");
|
|
||||||
|
|
||||||
let mut key = [0_u8; 8];
|
|
||||||
key.copy_from_slice(bytes);
|
|
||||||
|
|
||||||
self.0 = u64::from_ne_bytes(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A hash builder for `StraightHasher`.
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
|
||||||
pub struct StraightHasherBuilder;
|
|
||||||
|
|
||||||
impl BuildHasher for StraightHasherBuilder {
|
|
||||||
type Hasher = StraightHasher;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn build_hasher(&self) -> Self::Hasher {
|
|
||||||
StraightHasher(42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an instance of the default hasher.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn get_hasher() -> ahash::AHasher {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a [`u64`] hash key from a namespace-qualified function name
|
|
||||||
/// and the number of parameters, but no parameter types.
|
|
||||||
///
|
|
||||||
/// Module names are passed in via `&str` references from an iterator.
|
|
||||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub fn calc_qualified_fn_hash<'a>(
|
|
||||||
modules: impl Iterator<Item = &'a str>,
|
|
||||||
fn_name: impl AsRef<str>,
|
|
||||||
num: usize,
|
|
||||||
) -> u64 {
|
|
||||||
let s = &mut get_hasher();
|
|
||||||
|
|
||||||
// We always skip the first module
|
|
||||||
let mut len = 0;
|
|
||||||
modules
|
|
||||||
.inspect(|_| len += 1)
|
|
||||||
.skip(1)
|
|
||||||
.for_each(|m| m.hash(s));
|
|
||||||
len.hash(s);
|
|
||||||
fn_name.as_ref().hash(s);
|
|
||||||
num.hash(s);
|
|
||||||
s.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a [`u64`] hash key from a non-namespace-qualified function name
|
|
||||||
/// and the number of parameters, but no parameter types.
|
|
||||||
///
|
|
||||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn calc_fn_hash(fn_name: impl AsRef<str>, num: usize) -> u64 {
|
|
||||||
calc_qualified_fn_hash(empty(), fn_name, num)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate a [`u64`] hash key from a list of parameter types.
|
|
||||||
///
|
|
||||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
|
||||||
let s = &mut get_hasher();
|
|
||||||
let mut len = 0;
|
|
||||||
params.inspect(|_| len += 1).for_each(|t| t.hash(s));
|
|
||||||
len.hash(s);
|
|
||||||
s.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Combine two [`u64`] hashes by taking the XOR of them.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 {
|
|
||||||
a ^ b
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The system immutable string type.
|
/// The system immutable string type.
|
||||||
///
|
///
|
||||||
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`
|
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`
|
||||||
@ -628,33 +523,3 @@ impl ImmutableString {
|
|||||||
shared_make_mut(&mut self.0)
|
shared_make_mut(&mut self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A factory of identifiers from text strings.
|
|
||||||
///
|
|
||||||
/// When [`SmartString`](https://crates.io/crates/smartstring) is used as [`Identifier`],
|
|
||||||
/// this just returns one because most identifiers in Rhai are short and ASCII-based.
|
|
||||||
///
|
|
||||||
/// When [`ImmutableString`] is used as [`Identifier`], this type acts as an interner which keeps a
|
|
||||||
/// collection of strings and returns shared instances, only creating a new string when it is not
|
|
||||||
/// yet interned.
|
|
||||||
#[derive(Debug, Clone, Default, Hash)]
|
|
||||||
pub struct IdentifierBuilder(
|
|
||||||
#[cfg(feature = "no_smartstring")] std::collections::BTreeSet<Identifier>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl IdentifierBuilder {
|
|
||||||
/// Get an identifier from a text string.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn get(&mut self, text: impl AsRef<str> + Into<Identifier>) -> Identifier {
|
|
||||||
#[cfg(not(feature = "no_smartstring"))]
|
|
||||||
return text.as_ref().into();
|
|
||||||
|
|
||||||
#[cfg(feature = "no_smartstring")]
|
|
||||||
return self.0.get(text.as_ref()).cloned().unwrap_or_else(|| {
|
|
||||||
let s: Identifier = text.into();
|
|
||||||
self.0.insert(s.clone());
|
|
||||||
s
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
23
src/lib.rs
23
src/lib.rs
@ -70,28 +70,29 @@ use std::prelude::v1::*;
|
|||||||
// Internal modules
|
// Internal modules
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
|
mod custom_syntax;
|
||||||
mod dynamic;
|
mod dynamic;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod engine_api;
|
mod engine_api;
|
||||||
mod engine_settings;
|
mod engine_settings;
|
||||||
|
mod error;
|
||||||
|
mod error_parsing;
|
||||||
mod fn_args;
|
mod fn_args;
|
||||||
mod fn_builtin;
|
mod fn_builtin;
|
||||||
mod fn_call;
|
mod fn_call;
|
||||||
mod fn_func;
|
mod fn_func;
|
||||||
|
mod fn_hash;
|
||||||
mod fn_native;
|
mod fn_native;
|
||||||
mod fn_register;
|
mod fn_register;
|
||||||
|
mod immutable_string;
|
||||||
mod module;
|
mod module;
|
||||||
mod optimize;
|
mod optimize;
|
||||||
pub mod packages;
|
pub mod packages;
|
||||||
mod parse_error;
|
mod parse;
|
||||||
mod parser;
|
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
mod result;
|
|
||||||
mod scope;
|
mod scope;
|
||||||
mod syntax;
|
|
||||||
mod token;
|
mod token;
|
||||||
mod r#unsafe;
|
mod r#unsafe;
|
||||||
mod utils;
|
|
||||||
|
|
||||||
type RhaiResult = Result<Dynamic, Box<EvalAltResult>>;
|
type RhaiResult = Result<Dynamic, Box<EvalAltResult>>;
|
||||||
|
|
||||||
@ -126,17 +127,17 @@ pub type FLOAT = f64;
|
|||||||
pub type FLOAT = f32;
|
pub type FLOAT = f32;
|
||||||
|
|
||||||
pub use ast::{FnAccess, AST};
|
pub use ast::{FnAccess, AST};
|
||||||
|
pub use custom_syntax::Expression;
|
||||||
pub use dynamic::Dynamic;
|
pub use dynamic::Dynamic;
|
||||||
pub use engine::{Engine, EvalContext, OP_CONTAINS, OP_EQUALS};
|
pub use engine::{Engine, EvalContext, OP_CONTAINS, OP_EQUALS};
|
||||||
|
pub use error::EvalAltResult;
|
||||||
|
pub use error_parsing::{LexError, ParseError, ParseErrorType};
|
||||||
pub use fn_native::{FnPtr, NativeCallContext};
|
pub use fn_native::{FnPtr, NativeCallContext};
|
||||||
pub use fn_register::RegisterNativeFunction;
|
pub use fn_register::RegisterNativeFunction;
|
||||||
|
pub use immutable_string::ImmutableString;
|
||||||
pub use module::{FnNamespace, Module};
|
pub use module::{FnNamespace, Module};
|
||||||
pub use parse_error::{LexError, ParseError, ParseErrorType};
|
|
||||||
pub use result::EvalAltResult;
|
|
||||||
pub use scope::Scope;
|
pub use scope::Scope;
|
||||||
pub use syntax::Expression;
|
|
||||||
pub use token::Position;
|
pub use token::Position;
|
||||||
pub use utils::ImmutableString;
|
|
||||||
|
|
||||||
/// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most
|
/// An identifier in Rhai. [`SmartString`](https://crates.io/crates/smartstring) is used because most
|
||||||
/// identifiers are ASCII and short, fewer than 23 characters, so they can be stored inline.
|
/// identifiers are ASCII and short, fewer than 23 characters, so they can be stored inline.
|
||||||
@ -169,7 +170,9 @@ pub use fn_native::Shared;
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
use fn_native::Locked;
|
use fn_native::Locked;
|
||||||
|
|
||||||
pub(crate) use utils::{calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes};
|
pub(crate) use fn_hash::{
|
||||||
|
calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes,
|
||||||
|
};
|
||||||
|
|
||||||
pub use rhai_codegen::*;
|
pub use rhai_codegen::*;
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ use crate::ast::{FnAccess, Ident};
|
|||||||
use crate::dynamic::Variant;
|
use crate::dynamic::Variant;
|
||||||
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
|
use crate::fn_native::{shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, SendSync};
|
||||||
use crate::fn_register::RegisterNativeFunction;
|
use crate::fn_register::RegisterNativeFunction;
|
||||||
|
use crate::parse::IdentifierBuilder;
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::IdentifierBuilder;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, EvalAltResult,
|
calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, EvalAltResult,
|
||||||
Identifier, ImmutableString, NativeCallContext, Position, Shared, StaticVec,
|
Identifier, ImmutableString, NativeCallContext, Position, Shared, StaticVec,
|
||||||
|
@ -4,8 +4,8 @@ use crate::ast::{Expr, OpAssignment, Stmt};
|
|||||||
use crate::dynamic::AccessMode;
|
use crate::dynamic::AccessMode;
|
||||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||||
use crate::fn_builtin::get_builtin_binary_op_fn;
|
use crate::fn_builtin::get_builtin_binary_op_fn;
|
||||||
|
use crate::fn_hash::get_hasher;
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::get_hasher;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnPtr, ImmutableString,
|
||||||
Module, Position, Scope, StaticVec, AST,
|
Module, Position, Scope, StaticVec, AST,
|
||||||
@ -729,7 +729,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State, _chaining: bool) {
|
|||||||
// 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();
|
||||||
let mut result = a.remove(*i as usize);
|
let mut result = mem::take(&mut a[*i as usize]);
|
||||||
result.set_position(*pos);
|
result.set_position(*pos);
|
||||||
*expr = result;
|
*expr = result;
|
||||||
}
|
}
|
||||||
@ -740,7 +740,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut State, _chaining: bool) {
|
|||||||
// 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();
|
||||||
let mut result = a.remove(a.len() - i.abs() as usize);
|
let index = a.len() - i.abs() as usize;
|
||||||
|
let mut result = mem::take(&mut a[index]);
|
||||||
result.set_position(*pos);
|
result.set_position(*pos);
|
||||||
*expr = result;
|
*expr = result;
|
||||||
}
|
}
|
||||||
@ -797,9 +798,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State, _chaining: bool) {
|
|||||||
}
|
}
|
||||||
// `... ${ ... } ...`
|
// `... ${ ... } ...`
|
||||||
Expr::InterpolatedString(x) => {
|
Expr::InterpolatedString(x) => {
|
||||||
x.iter_mut().for_each(|expr| optimize_expr(expr, state, false));
|
let mut n = 0;
|
||||||
|
|
||||||
let mut n= 0;
|
|
||||||
|
|
||||||
// Merge consecutive strings
|
// Merge consecutive strings
|
||||||
while n < x.len()-1 {
|
while n < x.len()-1 {
|
||||||
|
@ -9,7 +9,7 @@ use std::prelude::v1::*;
|
|||||||
use crate::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::result::EvalAltResult;
|
use crate::error::EvalAltResult;
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
@ -4,19 +4,18 @@ use crate::ast::{
|
|||||||
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType,
|
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType,
|
||||||
ScriptFnDef, Stmt, StmtBlock,
|
ScriptFnDef, Stmt, StmtBlock,
|
||||||
};
|
};
|
||||||
|
use crate::custom_syntax::{
|
||||||
|
CustomSyntax, MARKER_BLOCK, MARKER_BOOL, MARKER_EXPR, MARKER_IDENT, MARKER_INT, MARKER_STRING,
|
||||||
|
};
|
||||||
use crate::dynamic::{AccessMode, Union};
|
use crate::dynamic::{AccessMode, Union};
|
||||||
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
||||||
use crate::module::NamespaceRef;
|
use crate::module::NamespaceRef;
|
||||||
use crate::optimize::optimize_into_ast;
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::optimize::OptimizationLevel;
|
|
||||||
use crate::syntax::{
|
|
||||||
CustomSyntax, MARKER_BLOCK, MARKER_BOOL, MARKER_EXPR, MARKER_IDENT, MARKER_INT, MARKER_STRING,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use crate::fn_hash::get_hasher;
|
||||||
use crate::token::{
|
use crate::token::{
|
||||||
is_keyword_function, is_valid_identifier, Token, TokenStream, TokenizerControl,
|
is_keyword_function, is_valid_identifier, Token, TokenStream, TokenizerControl,
|
||||||
};
|
};
|
||||||
use crate::utils::{get_hasher, IdentifierBuilder};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_qualified_fn_hash, Dynamic, Engine, Identifier, LexError, ParseError,
|
calc_fn_hash, calc_qualified_fn_hash, Dynamic, Engine, Identifier, LexError, ParseError,
|
||||||
ParseErrorType, Position, Scope, Shared, StaticVec, AST,
|
ParseErrorType, Position, Scope, Shared, StaticVec, AST,
|
||||||
@ -30,7 +29,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::{syntax::MARKER_FLOAT, FLOAT};
|
use crate::{custom_syntax::MARKER_FLOAT, FLOAT};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::FnAccess;
|
use crate::FnAccess;
|
||||||
@ -41,6 +40,36 @@ type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>;
|
|||||||
|
|
||||||
const NEVER_ENDS: &str = "never fails because `TokenStream` never ends";
|
const NEVER_ENDS: &str = "never fails because `TokenStream` never ends";
|
||||||
|
|
||||||
|
/// A factory of identifiers from text strings.
|
||||||
|
///
|
||||||
|
/// When [`SmartString`](https://crates.io/crates/smartstring) is used as [`Identifier`],
|
||||||
|
/// this just returns a copy because most identifiers in Rhai are short and ASCII-based.
|
||||||
|
///
|
||||||
|
/// When [`ImmutableString`] is used as [`Identifier`], this type acts as an interner which keeps a
|
||||||
|
/// collection of strings and returns shared instances, only creating a new string when it is not
|
||||||
|
/// yet interned.
|
||||||
|
#[derive(Debug, Clone, Default, Hash)]
|
||||||
|
pub struct IdentifierBuilder(
|
||||||
|
#[cfg(feature = "no_smartstring")] std::collections::BTreeSet<Identifier>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl IdentifierBuilder {
|
||||||
|
/// Get an identifier from a text string.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub fn get(&mut self, text: impl AsRef<str> + Into<Identifier>) -> Identifier {
|
||||||
|
#[cfg(not(feature = "no_smartstring"))]
|
||||||
|
return text.into();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_smartstring")]
|
||||||
|
return self.0.get(text.as_ref()).cloned().unwrap_or_else(|| {
|
||||||
|
let s: Identifier = text.into();
|
||||||
|
self.0.insert(s.clone());
|
||||||
|
s
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type that encapsulates the current state of the parser.
|
/// A type that encapsulates the current state of the parser.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseState<'e> {
|
pub struct ParseState<'e> {
|
||||||
@ -372,17 +401,15 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
name: state.get_identifier(id),
|
||||||
name: state.get_identifier(id),
|
capture,
|
||||||
capture,
|
namespace,
|
||||||
namespace,
|
hashes,
|
||||||
hashes,
|
args,
|
||||||
args,
|
..Default::default()
|
||||||
..Default::default()
|
}
|
||||||
}),
|
.into_fn_call_expr(settings.pos));
|
||||||
settings.pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
// id...
|
// id...
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -424,17 +451,15 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
name: state.get_identifier(id),
|
||||||
name: state.get_identifier(id),
|
capture,
|
||||||
capture,
|
namespace,
|
||||||
namespace,
|
hashes,
|
||||||
hashes,
|
args,
|
||||||
args,
|
..Default::default()
|
||||||
..Default::default()
|
}
|
||||||
}),
|
.into_fn_call_expr(settings.pos));
|
||||||
settings.pos,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
// id(...args,
|
// id(...args,
|
||||||
(Token::Comma, _) => {
|
(Token::Comma, _) => {
|
||||||
@ -692,7 +717,7 @@ fn parse_array_literal(
|
|||||||
|
|
||||||
arr.shrink_to_fit();
|
arr.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::Array(Box::new(arr), settings.pos))
|
Ok(Expr::Array(arr.into(), settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a map literal.
|
/// Parse a map literal.
|
||||||
@ -1101,7 +1126,7 @@ fn parse_primary(
|
|||||||
}
|
}
|
||||||
|
|
||||||
segments.shrink_to_fit();
|
segments.shrink_to_fit();
|
||||||
Expr::InterpolatedString(Box::new(segments))
|
Expr::InterpolatedString(segments.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array literal
|
// Array literal
|
||||||
@ -1245,14 +1270,14 @@ fn parse_primary(
|
|||||||
|
|
||||||
let (_, namespace, name) = *x;
|
let (_, namespace, name) = *x;
|
||||||
settings.pos = var_pos;
|
settings.pos = var_pos;
|
||||||
let ns = namespace.map(|(_, ns)| ns);
|
let ns = namespace.map(|(ns, _)| ns);
|
||||||
parse_fn_call(input, state, lib, name, true, ns, settings.level_up())?
|
parse_fn_call(input, state, lib, name, true, ns, settings.level_up())?
|
||||||
}
|
}
|
||||||
// Function call
|
// Function call
|
||||||
(Expr::Variable(_, var_pos, x), Token::LeftParen) => {
|
(Expr::Variable(_, var_pos, x), Token::LeftParen) => {
|
||||||
let (_, namespace, name) = *x;
|
let (_, namespace, name) = *x;
|
||||||
settings.pos = var_pos;
|
settings.pos = var_pos;
|
||||||
let ns = namespace.map(|(_, ns)| ns);
|
let ns = namespace.map(|(ns, _)| ns);
|
||||||
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
|
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
|
||||||
}
|
}
|
||||||
// module access
|
// module access
|
||||||
@ -1264,12 +1289,12 @@ fn parse_primary(
|
|||||||
pos: var_pos,
|
pos: var_pos,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some((_, ref mut namespace)) = namespace {
|
if let Some((ref mut namespace, _)) = namespace {
|
||||||
namespace.push(var_name_def);
|
namespace.push(var_name_def);
|
||||||
} else {
|
} else {
|
||||||
let mut ns: NamespaceRef = Default::default();
|
let mut ns: NamespaceRef = Default::default();
|
||||||
ns.push(var_name_def);
|
ns.push(var_name_def);
|
||||||
namespace = Some((42, ns));
|
namespace = Some((ns, 42));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
@ -1322,7 +1347,7 @@ fn parse_primary(
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.map(|x| match x {
|
.map(|x| match x {
|
||||||
(_, Some((hash, namespace)), name) => {
|
(_, Some((namespace, hash)), name) => {
|
||||||
*hash = calc_qualified_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0);
|
*hash = calc_qualified_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -1376,15 +1401,13 @@ fn parse_unary(
|
|||||||
args.push(expr);
|
args.push(expr);
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
name: state.get_identifier("-"),
|
||||||
name: state.get_identifier("-"),
|
hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)),
|
args,
|
||||||
args,
|
..Default::default()
|
||||||
..Default::default()
|
}
|
||||||
}),
|
.into_fn_call_expr(pos))
|
||||||
pos,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1403,15 +1426,13 @@ fn parse_unary(
|
|||||||
args.push(expr);
|
args.push(expr);
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
name: state.get_identifier("+"),
|
||||||
name: state.get_identifier("+"),
|
hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)),
|
args,
|
||||||
args,
|
..Default::default()
|
||||||
..Default::default()
|
}
|
||||||
}),
|
.into_fn_call_expr(pos))
|
||||||
pos,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1422,15 +1443,13 @@ fn parse_unary(
|
|||||||
args.push(parse_unary(input, state, lib, settings.level_up())?);
|
args.push(parse_unary(input, state, lib, settings.level_up())?);
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::FnCall(
|
Ok(FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
name: state.get_identifier("!"),
|
||||||
name: state.get_identifier("!"),
|
hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)),
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)),
|
args,
|
||||||
args,
|
..Default::default()
|
||||||
..Default::default()
|
}
|
||||||
}),
|
.into_fn_call_expr(pos))
|
||||||
pos,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
// <EOF>
|
// <EOF>
|
||||||
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
@ -1587,7 +1606,7 @@ fn make_dot_expr(
|
|||||||
// lhs.module::id - syntax error
|
// lhs.module::id - syntax error
|
||||||
(_, Expr::Variable(_, _, x)) if x.1.is_some() => {
|
(_, Expr::Variable(_, _, x)) if x.1.is_some() => {
|
||||||
return Err(PERR::PropertyExpected
|
return Err(PERR::PropertyExpected
|
||||||
.into_err(x.1.expect("never fails because the namespace is `Some`").1[0].pos))
|
.into_err(x.1.expect("never fails because the namespace is `Some`").0[0].pos))
|
||||||
}
|
}
|
||||||
// lhs.prop
|
// lhs.prop
|
||||||
(lhs, prop @ Expr::Property(_)) => {
|
(lhs, prop @ Expr::Property(_)) => {
|
||||||
@ -1772,19 +1791,17 @@ fn parse_binary_op(
|
|||||||
| Token::PowerOf
|
| Token::PowerOf
|
||||||
| Token::Ampersand
|
| Token::Ampersand
|
||||||
| Token::Pipe
|
| Token::Pipe
|
||||||
| Token::XOr => Expr::FnCall(Box::new(FnCallExpr { args, ..op_base }), pos),
|
| Token::XOr => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
||||||
|
|
||||||
// '!=' defaults to true when passed invalid operands
|
// '!=' defaults to true when passed invalid operands
|
||||||
Token::NotEqualsTo => Expr::FnCall(Box::new(FnCallExpr { args, ..op_base }), pos),
|
Token::NotEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
||||||
|
|
||||||
// Comparison operators default to false when passed invalid operands
|
// Comparison operators default to false when passed invalid operands
|
||||||
Token::EqualsTo
|
Token::EqualsTo
|
||||||
| Token::LessThan
|
| Token::LessThan
|
||||||
| Token::LessThanEqualsTo
|
| Token::LessThanEqualsTo
|
||||||
| Token::GreaterThan
|
| Token::GreaterThan
|
||||||
| Token::GreaterThanEqualsTo => {
|
| Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
|
||||||
Expr::FnCall(Box::new(FnCallExpr { args, ..op_base }), pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
Token::Or => {
|
Token::Or => {
|
||||||
let rhs = args
|
let rhs = args
|
||||||
@ -1823,16 +1840,13 @@ fn parse_binary_op(
|
|||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
|
|
||||||
// Convert into a call to `contains`
|
// Convert into a call to `contains`
|
||||||
let hash = calc_fn_hash(OP_CONTAINS, 2);
|
FnCallExpr {
|
||||||
Expr::FnCall(
|
hashes: FnCallHashes::from_script(calc_fn_hash(OP_CONTAINS, 2)),
|
||||||
Box::new(FnCallExpr {
|
args,
|
||||||
hashes: FnCallHashes::from_script(hash),
|
name: state.get_identifier(OP_CONTAINS),
|
||||||
args,
|
..op_base
|
||||||
name: state.get_identifier(OP_CONTAINS),
|
}
|
||||||
..op_base
|
.into_fn_call_expr(pos)
|
||||||
}),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Custom(s)
|
Token::Custom(s)
|
||||||
@ -1844,18 +1858,16 @@ fn parse_binary_op(
|
|||||||
{
|
{
|
||||||
let hash = calc_fn_hash(&s, 2);
|
let hash = calc_fn_hash(&s, 2);
|
||||||
|
|
||||||
Expr::FnCall(
|
FnCallExpr {
|
||||||
Box::new(FnCallExpr {
|
hashes: if is_valid_identifier(s.chars()) {
|
||||||
hashes: if is_valid_identifier(s.chars()) {
|
FnCallHashes::from_script(hash)
|
||||||
FnCallHashes::from_script(hash)
|
} else {
|
||||||
} else {
|
FnCallHashes::from_native(hash)
|
||||||
FnCallHashes::from_native(hash)
|
},
|
||||||
},
|
args,
|
||||||
args,
|
..op_base
|
||||||
..op_base
|
}
|
||||||
}),
|
.into_fn_call_expr(pos)
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
op_token => return Err(PERR::UnknownOperator(op_token.into()).into_err(pos)),
|
op_token => return Err(PERR::UnknownOperator(op_token.into()).into_err(pos)),
|
||||||
@ -1999,14 +2011,12 @@ fn parse_custom_syntax(
|
|||||||
keywords.shrink_to_fit();
|
keywords.shrink_to_fit();
|
||||||
tokens.shrink_to_fit();
|
tokens.shrink_to_fit();
|
||||||
|
|
||||||
Ok(Expr::Custom(
|
Ok(CustomExpr {
|
||||||
Box::new(CustomExpr {
|
keywords,
|
||||||
keywords,
|
tokens,
|
||||||
tokens,
|
scope_changed: syntax.scope_changed,
|
||||||
scope_changed: syntax.scope_changed,
|
}
|
||||||
}),
|
.into_custom_syntax_expr(pos))
|
||||||
pos,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an expression.
|
/// Parse an expression.
|
||||||
@ -2942,36 +2952,31 @@ fn make_curry_from_externals(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let num_externals = externals.len();
|
let num_externals = externals.len();
|
||||||
let mut args: StaticVec<_> = Default::default();
|
let mut args = StaticVec::with_capacity(externals.len() + 1);
|
||||||
|
|
||||||
args.push(fn_expr);
|
args.push(fn_expr);
|
||||||
|
|
||||||
externals.iter().for_each(|x| {
|
args.extend(
|
||||||
args.push(Expr::Variable(
|
externals
|
||||||
None,
|
.iter()
|
||||||
Position::NONE,
|
.cloned()
|
||||||
Box::new((None, None, x.clone())),
|
.map(|x| Expr::Variable(None, Position::NONE, Box::new((None, None, x)))),
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
args.shrink_to_fit();
|
|
||||||
|
|
||||||
let expr = Expr::FnCall(
|
|
||||||
Box::new(FnCallExpr {
|
|
||||||
name: state.get_identifier(crate::engine::KEYWORD_FN_PTR_CURRY),
|
|
||||||
hashes: FnCallHashes::from_native(calc_fn_hash(
|
|
||||||
crate::engine::KEYWORD_FN_PTR_CURRY,
|
|
||||||
num_externals + 1,
|
|
||||||
)),
|
|
||||||
args,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
pos,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let expr = FnCallExpr {
|
||||||
|
name: state.get_identifier(crate::engine::KEYWORD_FN_PTR_CURRY),
|
||||||
|
hashes: FnCallHashes::from_native(calc_fn_hash(
|
||||||
|
crate::engine::KEYWORD_FN_PTR_CURRY,
|
||||||
|
num_externals + 1,
|
||||||
|
)),
|
||||||
|
args,
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.into_fn_call_expr(pos);
|
||||||
|
|
||||||
// Convert the entire expression into a statement block, then insert the relevant
|
// Convert the entire expression into a statement block, then insert the relevant
|
||||||
// [`Share`][Stmt::Share] statements.
|
// [`Share`][Stmt::Share] statements.
|
||||||
let mut statements: StaticVec<_> = Default::default();
|
let mut statements = StaticVec::with_capacity(externals.len() + 1);
|
||||||
statements.extend(externals.into_iter().map(Stmt::Share));
|
statements.extend(externals.into_iter().map(Stmt::Share));
|
||||||
statements.push(Stmt::Expr(expr));
|
statements.push(Stmt::Expr(expr));
|
||||||
Expr::Stmt(Box::new(StmtBlock::new(statements, pos)))
|
Expr::Stmt(Box::new(StmtBlock::new(statements, pos)))
|
Loading…
Reference in New Issue
Block a user