Use tokens to speed up function name lookup.
This commit is contained in:
parent
ece522ce2f
commit
bf02d040e2
@ -193,7 +193,7 @@ pub struct FnCallExpr {
|
|||||||
/// Does this function call capture the parent scope?
|
/// Does this function call capture the parent scope?
|
||||||
pub capture_parent_scope: bool,
|
pub capture_parent_scope: bool,
|
||||||
/// Is this function call a native operator?
|
/// Is this function call a native operator?
|
||||||
pub is_native_operator: bool,
|
pub operator_token: Option<Token>,
|
||||||
/// [Position] of the function name.
|
/// [Position] of the function name.
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -208,8 +208,8 @@ impl fmt::Debug for FnCallExpr {
|
|||||||
if self.capture_parent_scope {
|
if self.capture_parent_scope {
|
||||||
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
||||||
}
|
}
|
||||||
if self.is_native_operator {
|
if let Some(ref token) = self.operator_token {
|
||||||
ff.field("is_native_operator", &self.is_native_operator);
|
ff.field("operator_token", token);
|
||||||
}
|
}
|
||||||
ff.field("hash", &self.hashes)
|
ff.field("hash", &self.hashes)
|
||||||
.field("name", &self.name)
|
.field("name", &self.name)
|
||||||
@ -673,7 +673,7 @@ impl Expr {
|
|||||||
hashes: calc_fn_hash(None, f.fn_name(), 1).into(),
|
hashes: calc_fn_hash(None, f.fn_name(), 1).into(),
|
||||||
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(),
|
||||||
capture_parent_scope: false,
|
capture_parent_scope: false,
|
||||||
is_native_operator: false,
|
operator_token: None,
|
||||||
pos,
|
pos,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -19,16 +19,16 @@ use std::{
|
|||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
/// This type may hold a straight assignment (i.e. not an op-assignment).
|
/// This type may hold a straight assignment (i.e. not an op-assignment).
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Clone, PartialEq, Hash)]
|
||||||
pub struct OpAssignment {
|
pub struct OpAssignment {
|
||||||
/// Hash of the op-assignment call.
|
/// Hash of the op-assignment call.
|
||||||
pub hash_op_assign: u64,
|
pub hash_op_assign: u64,
|
||||||
/// Hash of the underlying operator call (for fallback).
|
/// Hash of the underlying operator call (for fallback).
|
||||||
pub hash_op: u64,
|
pub hash_op: u64,
|
||||||
/// Op-assignment operator.
|
/// Op-assignment operator.
|
||||||
pub op_assign: &'static str,
|
pub op_assign: Token,
|
||||||
/// Underlying operator.
|
/// Underlying operator.
|
||||||
pub op: &'static str,
|
pub op: Token,
|
||||||
/// [Position] of the op-assignment operator.
|
/// [Position] of the op-assignment operator.
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -41,8 +41,8 @@ impl OpAssignment {
|
|||||||
Self {
|
Self {
|
||||||
hash_op_assign: 0,
|
hash_op_assign: 0,
|
||||||
hash_op: 0,
|
hash_op: 0,
|
||||||
op_assign: "=",
|
op_assign: Token::Equals,
|
||||||
op: "=",
|
op: Token::Equals,
|
||||||
pos,
|
pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,12 +71,11 @@ impl OpAssignment {
|
|||||||
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");
|
||||||
.literal_syntax();
|
|
||||||
Self {
|
Self {
|
||||||
hash_op_assign: calc_fn_hash(None, op.literal_syntax(), 2),
|
hash_op_assign: calc_fn_hash(None, op.literal_syntax(), 2),
|
||||||
hash_op: calc_fn_hash(None, op_raw, 2),
|
hash_op: calc_fn_hash(None, op_raw.literal_syntax(), 2),
|
||||||
op_assign: op.literal_syntax(),
|
op_assign: op.clone(),
|
||||||
op: op_raw,
|
op: op_raw,
|
||||||
pos,
|
pos,
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ impl Engine {
|
|||||||
idx_values: &mut FnArgsVec<Dynamic>,
|
idx_values: &mut FnArgsVec<Dynamic>,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<(Dynamic, OpAssignment)>,
|
new_val: Option<(Dynamic, &OpAssignment)>,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
let is_ref_mut = target.is_ref();
|
let is_ref_mut = target.is_ref();
|
||||||
|
|
||||||
@ -558,7 +558,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<(Dynamic, OpAssignment)>,
|
new_val: Option<(Dynamic, &OpAssignment)>,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let chain_type = ChainType::from(expr);
|
let chain_type = ChainType::from(expr);
|
||||||
let (crate::ast::BinaryExpr { lhs, rhs }, options, op_pos) = match expr {
|
let (crate::ast::BinaryExpr { lhs, rhs }, options, op_pos) = match expr {
|
||||||
|
@ -219,11 +219,15 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let FnCallExpr {
|
let FnCallExpr {
|
||||||
name, hashes, args, ..
|
name,
|
||||||
|
hashes,
|
||||||
|
args,
|
||||||
|
operator_token,
|
||||||
|
..
|
||||||
} = expr;
|
} = expr;
|
||||||
|
|
||||||
// Short-circuit native binary operator call if under Fast Operators mode
|
// Short-circuit native binary operator call if under Fast Operators mode
|
||||||
if expr.is_native_operator && self.fast_operators() && args.len() == 2 {
|
if operator_token.is_some() && self.fast_operators() && args.len() == 2 {
|
||||||
let mut lhs = self
|
let mut lhs = self
|
||||||
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
.get_arg_value(scope, global, caches, lib, this_ptr, &args[0], level)?
|
||||||
.0
|
.0
|
||||||
@ -236,7 +240,9 @@ impl Engine {
|
|||||||
|
|
||||||
let operands = &mut [&mut lhs, &mut rhs];
|
let operands = &mut [&mut lhs, &mut rhs];
|
||||||
|
|
||||||
if let Some(func) = get_builtin_binary_op_fn(name, operands[0], operands[1]) {
|
if let Some(func) =
|
||||||
|
get_builtin_binary_op_fn(operator_token.as_ref().unwrap(), operands[0], operands[1])
|
||||||
|
{
|
||||||
// Built-in found
|
// Built-in found
|
||||||
let context = (self, name, None, &*global, lib, pos, level + 1).into();
|
let context = (self, name, None, &*global, lib, pos, level + 1).into();
|
||||||
let result = func(context, operands);
|
let result = func(context, operands);
|
||||||
@ -278,7 +284,7 @@ impl Engine {
|
|||||||
args,
|
args,
|
||||||
*hashes,
|
*hashes,
|
||||||
expr.capture_parent_scope,
|
expr.capture_parent_scope,
|
||||||
expr.is_native_operator,
|
expr.operator_token.as_ref(),
|
||||||
pos,
|
pos,
|
||||||
level,
|
level,
|
||||||
)
|
)
|
||||||
@ -384,9 +390,9 @@ impl Engine {
|
|||||||
|
|
||||||
op_info.pos = expr.start_position();
|
op_info.pos = expr.start_position();
|
||||||
|
|
||||||
if let Err(err) = self
|
if let Err(err) = self.eval_op_assignment(
|
||||||
.eval_op_assignment(global, caches, lib, op_info, target, root, item, level)
|
global, caches, lib, &op_info, target, root, item, level,
|
||||||
{
|
) {
|
||||||
result = Err(err);
|
result = Err(err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ impl Engine {
|
|||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
caches: &mut Caches,
|
caches: &mut Caches,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
op_info: OpAssignment,
|
op_info: &OpAssignment,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
root: (&str, Position),
|
root: (&str, Position),
|
||||||
new_val: Dynamic,
|
new_val: Dynamic,
|
||||||
@ -141,14 +141,15 @@ impl Engine {
|
|||||||
|
|
||||||
let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
|
let mut lock_guard = target.write_lock::<Dynamic>().unwrap();
|
||||||
|
|
||||||
let hash = hash_op_assign;
|
let hash = *hash_op_assign;
|
||||||
let args = &mut [&mut *lock_guard, &mut new_val];
|
let args = &mut [&mut *lock_guard, &mut new_val];
|
||||||
let level = level + 1;
|
let level = level + 1;
|
||||||
|
|
||||||
if self.fast_operators() {
|
if self.fast_operators() {
|
||||||
if let Some(func) = get_builtin_op_assignment_fn(op_assign, args[0], args[1]) {
|
if let Some(func) = get_builtin_op_assignment_fn(op_assign, args[0], args[1]) {
|
||||||
// Built-in found
|
// Built-in found
|
||||||
let context = (self, op_assign, None, &*global, lib, op_pos, level).into();
|
let op = op_assign.literal_syntax();
|
||||||
|
let context = (self, op, None, &*global, lib, *op_pos, level).into();
|
||||||
let result = func(context, args).map(|_| ());
|
let result = func(context, args).map(|_| ());
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -158,8 +159,11 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let op_assign = op_assign.literal_syntax();
|
||||||
|
let op = op.literal_syntax();
|
||||||
|
|
||||||
match self.call_native_fn(
|
match self.call_native_fn(
|
||||||
global, caches, lib, op_assign, hash, args, true, true, op_pos, level,
|
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -170,7 +174,7 @@ impl Engine {
|
|||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
*args[0] = self
|
*args[0] = self
|
||||||
.call_native_fn(
|
.call_native_fn(
|
||||||
global, caches, lib, op, hash_op, args, true, false, op_pos, level,
|
global, caches, lib, op, *hash_op, args, true, false, *op_pos, level,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(op_info.pos))?
|
.map_err(|err| err.fill_position(op_info.pos))?
|
||||||
.0
|
.0
|
||||||
@ -279,7 +283,7 @@ impl Engine {
|
|||||||
let lhs_ptr = &mut lhs_ptr;
|
let lhs_ptr = &mut lhs_ptr;
|
||||||
|
|
||||||
self.eval_op_assignment(
|
self.eval_op_assignment(
|
||||||
global, caches, lib, *op_info, lhs_ptr, root, rhs_val, level,
|
global, caches, lib, op_info, lhs_ptr, root, rhs_val, level,
|
||||||
)
|
)
|
||||||
.map(|_| Dynamic::UNIT)
|
.map(|_| Dynamic::UNIT)
|
||||||
} else {
|
} else {
|
||||||
@ -303,7 +307,7 @@ impl Engine {
|
|||||||
rhs_val
|
rhs_val
|
||||||
};
|
};
|
||||||
|
|
||||||
let _new_val = Some((rhs_val, *op_info));
|
let _new_val = Some((rhs_val, op_info));
|
||||||
|
|
||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
match lhs {
|
match lhs {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use super::call::FnCallArgs;
|
use super::call::FnCallArgs;
|
||||||
use super::native::FnBuiltin;
|
use super::native::FnBuiltin;
|
||||||
use crate::engine::OP_CONTAINS;
|
use crate::tokenizer::Token;
|
||||||
use crate::{Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, INT};
|
use crate::{Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, INT};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -67,7 +67,7 @@ fn is_numeric(type_id: TypeId) -> bool {
|
|||||||
///
|
///
|
||||||
/// The return function will be registered as a _method_, so the first parameter cannot be consumed.
|
/// The return function will be registered as a _method_, so the first parameter cannot be consumed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<FnBuiltin> {
|
pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<FnBuiltin> {
|
||||||
let type1 = x.type_id();
|
let type1 = x.type_id();
|
||||||
let type2 = y.type_id();
|
let type2 = y.type_id();
|
||||||
|
|
||||||
@ -131,46 +131,46 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
"+" => return Some(impl_op!(INT => add(as_int, as_int))),
|
Token::Plus => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||||
"-" => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
Token::Minus => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||||
"*" => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
Token::Multiply => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||||
"/" => return Some(impl_op!(INT => divide(as_int, as_int))),
|
Token::Divide => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||||
"%" => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
Token::Modulo => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||||
"**" => return Some(impl_op!(INT => power(as_int, as_int))),
|
Token::PowerOf => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||||
">>" => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
Token::RightShift => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
||||||
"<<" => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
Token::LeftShift => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
"+" => return Some(impl_op!(INT => as_int + as_int)),
|
Token::Plus => return Some(impl_op!(INT => as_int + as_int)),
|
||||||
"-" => return Some(impl_op!(INT => as_int - as_int)),
|
Token::Minus => return Some(impl_op!(INT => as_int - as_int)),
|
||||||
"*" => return Some(impl_op!(INT => as_int * as_int)),
|
Token::Multiply => return Some(impl_op!(INT => as_int * as_int)),
|
||||||
"/" => return Some(impl_op!(INT => as_int / as_int)),
|
Token::Divide => return Some(impl_op!(INT => as_int / as_int)),
|
||||||
"%" => return Some(impl_op!(INT => as_int % as_int)),
|
Token::Modulo => return Some(impl_op!(INT => as_int % as_int)),
|
||||||
"**" => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
Token::PowerOf => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||||
">>" => return Some(impl_op!(INT => as_int >> as_int)),
|
Token::RightShift => return Some(impl_op!(INT => as_int >> as_int)),
|
||||||
"<<" => return Some(impl_op!(INT => as_int << as_int)),
|
Token::LeftShift => return Some(impl_op!(INT => as_int << as_int)),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(impl_op!(INT => as_int == as_int)),
|
Token::EqualsTo => Some(impl_op!(INT => as_int == as_int)),
|
||||||
"!=" => Some(impl_op!(INT => as_int != as_int)),
|
Token::NotEqualsTo => Some(impl_op!(INT => as_int != as_int)),
|
||||||
">" => Some(impl_op!(INT => as_int > as_int)),
|
Token::GreaterThan => Some(impl_op!(INT => as_int > as_int)),
|
||||||
">=" => Some(impl_op!(INT => as_int >= as_int)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(INT => as_int >= as_int)),
|
||||||
"<" => Some(impl_op!(INT => as_int < as_int)),
|
Token::LessThan => Some(impl_op!(INT => as_int < as_int)),
|
||||||
"<=" => Some(impl_op!(INT => as_int <= as_int)),
|
Token::LessThanEqualsTo => Some(impl_op!(INT => as_int <= as_int)),
|
||||||
"&" => Some(impl_op!(INT => as_int & as_int)),
|
Token::Ampersand => Some(impl_op!(INT => as_int & as_int)),
|
||||||
"|" => Some(impl_op!(INT => as_int | as_int)),
|
Token::Pipe => Some(impl_op!(INT => as_int | as_int)),
|
||||||
"^" => Some(impl_op!(INT => as_int ^ as_int)),
|
Token::XOr => Some(impl_op!(INT => as_int ^ as_int)),
|
||||||
".." => Some(|_, args| {
|
Token::ExclusiveRange => Some(|_, args| {
|
||||||
let x = args[0].as_int().expect(BUILTIN);
|
let x = args[0].as_int().expect(BUILTIN);
|
||||||
let y = args[1].as_int().expect(BUILTIN);
|
let y = args[1].as_int().expect(BUILTIN);
|
||||||
Ok((x..y).into())
|
Ok((x..y).into())
|
||||||
}),
|
}),
|
||||||
"..=" => Some(|_, args| {
|
Token::InclusiveRange => Some(|_, args| {
|
||||||
let x = args[0].as_int().expect(BUILTIN);
|
let x = args[0].as_int().expect(BUILTIN);
|
||||||
let y = args[1].as_int().expect(BUILTIN);
|
let y = args[1].as_int().expect(BUILTIN);
|
||||||
Ok((x..=y).into())
|
Ok((x..=y).into())
|
||||||
@ -181,47 +181,46 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
|
|
||||||
if type1 == TypeId::of::<bool>() {
|
if type1 == TypeId::of::<bool>() {
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(impl_op!(bool => as_bool == as_bool)),
|
Token::EqualsTo => Some(impl_op!(bool => as_bool == as_bool)),
|
||||||
"!=" => Some(impl_op!(bool => as_bool != as_bool)),
|
Token::NotEqualsTo => Some(impl_op!(bool => as_bool != as_bool)),
|
||||||
">" => Some(impl_op!(bool => as_bool > as_bool)),
|
Token::GreaterThan => Some(impl_op!(bool => as_bool > as_bool)),
|
||||||
">=" => Some(impl_op!(bool => as_bool >= as_bool)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(bool => as_bool >= as_bool)),
|
||||||
"<" => Some(impl_op!(bool => as_bool < as_bool)),
|
Token::LessThan => Some(impl_op!(bool => as_bool < as_bool)),
|
||||||
"<=" => Some(impl_op!(bool => as_bool <= as_bool)),
|
Token::LessThanEqualsTo => Some(impl_op!(bool => as_bool <= as_bool)),
|
||||||
"&" => Some(impl_op!(bool => as_bool & as_bool)),
|
Token::Ampersand => Some(impl_op!(bool => as_bool & as_bool)),
|
||||||
"|" => Some(impl_op!(bool => as_bool | as_bool)),
|
Token::Pipe => Some(impl_op!(bool => as_bool | as_bool)),
|
||||||
"^" => Some(impl_op!(bool => as_bool ^ as_bool)),
|
Token::XOr => Some(impl_op!(bool => as_bool ^ as_bool)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<ImmutableString>() {
|
if type1 == TypeId::of::<ImmutableString>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(impl_op!(ImmutableString + ImmutableString)),
|
Token::Plus => Some(impl_op!(ImmutableString + ImmutableString)),
|
||||||
"-" => Some(impl_op!(ImmutableString - ImmutableString)),
|
Token::Minus => Some(impl_op!(ImmutableString - ImmutableString)),
|
||||||
"==" => Some(impl_op!(ImmutableString == ImmutableString)),
|
Token::EqualsTo => Some(impl_op!(ImmutableString == ImmutableString)),
|
||||||
"!=" => Some(impl_op!(ImmutableString != ImmutableString)),
|
Token::NotEqualsTo => Some(impl_op!(ImmutableString != ImmutableString)),
|
||||||
">" => Some(impl_op!(ImmutableString > ImmutableString)),
|
Token::GreaterThan => Some(impl_op!(ImmutableString > ImmutableString)),
|
||||||
">=" => Some(impl_op!(ImmutableString >= ImmutableString)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(ImmutableString >= ImmutableString)),
|
||||||
"<" => Some(impl_op!(ImmutableString < ImmutableString)),
|
Token::LessThan => Some(impl_op!(ImmutableString < ImmutableString)),
|
||||||
"<=" => Some(impl_op!(ImmutableString <= ImmutableString)),
|
Token::LessThanEqualsTo => Some(impl_op!(ImmutableString <= ImmutableString)),
|
||||||
OP_CONTAINS => Some(impl_op!(ImmutableString.contains(ImmutableString.as_str()))),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<char>() {
|
if type1 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| {
|
Token::Plus => Some(|_, args| {
|
||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok(format!("{x}{y}").into())
|
Ok(format!("{x}{y}").into())
|
||||||
}),
|
}),
|
||||||
"==" => Some(impl_op!(char => as_char == as_char)),
|
Token::EqualsTo => Some(impl_op!(char => as_char == as_char)),
|
||||||
"!=" => Some(impl_op!(char => as_char != as_char)),
|
Token::NotEqualsTo => Some(impl_op!(char => as_char != as_char)),
|
||||||
">" => Some(impl_op!(char => as_char > as_char)),
|
Token::GreaterThan => Some(impl_op!(char => as_char > as_char)),
|
||||||
">=" => Some(impl_op!(char => as_char >= as_char)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(char => as_char >= as_char)),
|
||||||
"<" => Some(impl_op!(char => as_char < as_char)),
|
Token::LessThan => Some(impl_op!(char => as_char < as_char)),
|
||||||
"<=" => Some(impl_op!(char => as_char <= as_char)),
|
Token::LessThanEqualsTo => Some(impl_op!(char => as_char <= as_char)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -231,7 +230,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| {
|
Token::Plus => Some(|_, args| {
|
||||||
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
||||||
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
||||||
|
|
||||||
@ -245,16 +244,20 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
blob
|
blob
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
"==" => Some(impl_op!(Blob == Blob)),
|
Token::EqualsTo => Some(impl_op!(Blob == Blob)),
|
||||||
"!=" => Some(impl_op!(Blob != Blob)),
|
Token::NotEqualsTo => Some(impl_op!(Blob != Blob)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<()>() {
|
if type1 == TypeId::of::<()>() {
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(|_, _| Ok(Dynamic::TRUE)),
|
Token::EqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
"!=" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::NotEqualsTo
|
||||||
|
| Token::GreaterThan
|
||||||
|
| Token::GreaterThanEqualsTo
|
||||||
|
| Token::LessThan
|
||||||
|
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -265,18 +268,18 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(impl_op!(FLOAT => $xx + $yy)),
|
Token::Plus => Some(impl_op!(FLOAT => $xx + $yy)),
|
||||||
"-" => Some(impl_op!(FLOAT => $xx - $yy)),
|
Token::Minus => Some(impl_op!(FLOAT => $xx - $yy)),
|
||||||
"*" => Some(impl_op!(FLOAT => $xx * $yy)),
|
Token::Multiply => Some(impl_op!(FLOAT => $xx * $yy)),
|
||||||
"/" => Some(impl_op!(FLOAT => $xx / $yy)),
|
Token::Divide => Some(impl_op!(FLOAT => $xx / $yy)),
|
||||||
"%" => Some(impl_op!(FLOAT => $xx % $yy)),
|
Token::Modulo => Some(impl_op!(FLOAT => $xx % $yy)),
|
||||||
"**" => Some(impl_op!(FLOAT => $xx.powf($yy as FLOAT))),
|
Token::PowerOf => Some(impl_op!(FLOAT => $xx.powf($yy as FLOAT))),
|
||||||
"==" => Some(impl_op!(FLOAT => $xx == $yy)),
|
Token::EqualsTo => Some(impl_op!(FLOAT => $xx == $yy)),
|
||||||
"!=" => Some(impl_op!(FLOAT => $xx != $yy)),
|
Token::NotEqualsTo => Some(impl_op!(FLOAT => $xx != $yy)),
|
||||||
">" => Some(impl_op!(FLOAT => $xx > $yy)),
|
Token::GreaterThan => Some(impl_op!(FLOAT => $xx > $yy)),
|
||||||
">=" => Some(impl_op!(FLOAT => $xx >= $yy)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(FLOAT => $xx >= $yy)),
|
||||||
"<" => Some(impl_op!(FLOAT => $xx < $yy)),
|
Token::LessThan => Some(impl_op!(FLOAT => $xx < $yy)),
|
||||||
"<=" => Some(impl_op!(FLOAT => $xx <= $yy)),
|
Token::LessThanEqualsTo => Some(impl_op!(FLOAT => $xx <= $yy)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -299,12 +302,12 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
"+" => return Some(impl_op!(from Decimal => add($xx, $yy))),
|
Token::Plus => return Some(impl_op!(from Decimal => add($xx, $yy))),
|
||||||
"-" => return Some(impl_op!(from Decimal => subtract($xx, $yy))),
|
Token::Minus => return Some(impl_op!(from Decimal => subtract($xx, $yy))),
|
||||||
"*" => return Some(impl_op!(from Decimal => multiply($xx, $yy))),
|
Token::Multiply => return Some(impl_op!(from Decimal => multiply($xx, $yy))),
|
||||||
"/" => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
Token::Divide => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
||||||
"%" => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
Token::Modulo => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
||||||
"**" => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
Token::PowerOf => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,22 +316,22 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
"+" => return Some(impl_op!(from Decimal => $xx + $yy)),
|
Token::Plus => return Some(impl_op!(from Decimal => $xx + $yy)),
|
||||||
"-" => return Some(impl_op!(from Decimal => $xx - $yy)),
|
Token::Minus => return Some(impl_op!(from Decimal => $xx - $yy)),
|
||||||
"*" => return Some(impl_op!(from Decimal => $xx * $yy)),
|
Token::Multiply => return Some(impl_op!(from Decimal => $xx * $yy)),
|
||||||
"/" => return Some(impl_op!(from Decimal => $xx / $yy)),
|
Token::Divide => return Some(impl_op!(from Decimal => $xx / $yy)),
|
||||||
"%" => return Some(impl_op!(from Decimal => $xx % $yy)),
|
Token::Modulo => return Some(impl_op!(from Decimal => $xx % $yy)),
|
||||||
"**" => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
Token::PowerOf => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(impl_op!(from Decimal => $xx == $yy)),
|
Token::EqualsTo => Some(impl_op!(from Decimal => $xx == $yy)),
|
||||||
"!=" => Some(impl_op!(from Decimal => $xx != $yy)),
|
Token::NotEqualsTo => Some(impl_op!(from Decimal => $xx != $yy)),
|
||||||
">" => Some(impl_op!(from Decimal => $xx > $yy)),
|
Token::GreaterThan => Some(impl_op!(from Decimal => $xx > $yy)),
|
||||||
">=" => Some(impl_op!(from Decimal => $xx >= $yy)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(from Decimal => $xx >= $yy)),
|
||||||
"<" => Some(impl_op!(from Decimal => $xx < $yy)),
|
Token::LessThan => Some(impl_op!(from Decimal => $xx < $yy)),
|
||||||
"<=" => Some(impl_op!(from Decimal => $xx <= $yy)),
|
Token::LessThanEqualsTo => Some(impl_op!(from Decimal => $xx <= $yy)),
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -354,17 +357,17 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| {
|
Token::Plus => Some(|_, args| {
|
||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
Ok(format!("{x}{y}").into())
|
Ok(format!("{x}{y}").into())
|
||||||
}),
|
}),
|
||||||
"==" => Some(impl_op!(get_s1s2(==))),
|
Token::EqualsTo => Some(impl_op!(get_s1s2(==))),
|
||||||
"!=" => Some(impl_op!(get_s1s2(!=))),
|
Token::NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
||||||
">" => Some(impl_op!(get_s1s2(>))),
|
Token::GreaterThan => Some(impl_op!(get_s1s2(>))),
|
||||||
">=" => Some(impl_op!(get_s1s2(>=))),
|
Token::GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
||||||
"<" => Some(impl_op!(get_s1s2(<))),
|
Token::LessThan => Some(impl_op!(get_s1s2(<))),
|
||||||
"<=" => Some(impl_op!(get_s1s2(<=))),
|
Token::LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -380,45 +383,48 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| {
|
Token::Plus => Some(|_, args| {
|
||||||
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok((x + y).into())
|
Ok((x + y).into())
|
||||||
}),
|
}),
|
||||||
"-" => Some(|_, args| {
|
Token::Minus => Some(|_, args| {
|
||||||
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok((x - y).into())
|
Ok((x - y).into())
|
||||||
}),
|
}),
|
||||||
"==" => Some(impl_op!(get_s1s2(==))),
|
Token::EqualsTo => Some(impl_op!(get_s1s2(==))),
|
||||||
"!=" => Some(impl_op!(get_s1s2(!=))),
|
Token::NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
||||||
">" => Some(impl_op!(get_s1s2(>))),
|
Token::GreaterThan => Some(impl_op!(get_s1s2(>))),
|
||||||
">=" => Some(impl_op!(get_s1s2(>=))),
|
Token::GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
||||||
"<" => Some(impl_op!(get_s1s2(<))),
|
Token::LessThan => Some(impl_op!(get_s1s2(<))),
|
||||||
"<=" => Some(impl_op!(get_s1s2(<=))),
|
Token::LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
||||||
OP_CONTAINS => Some(|_, args| {
|
|
||||||
let s = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
|
||||||
let c = args[1].as_char().expect(BUILTIN);
|
|
||||||
Ok(s.contains(c).into())
|
|
||||||
}),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// () op string
|
// () op string
|
||||||
if (type1, type2) == (TypeId::of::<()>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<()>(), TypeId::of::<ImmutableString>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| Ok(args[1].clone())),
|
Token::Plus => Some(|_, args| Ok(args[1].clone())),
|
||||||
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::EqualsTo
|
||||||
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
| Token::GreaterThan
|
||||||
|
| Token::GreaterThanEqualsTo
|
||||||
|
| Token::LessThan
|
||||||
|
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
|
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// string op ()
|
// string op ()
|
||||||
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<()>()) {
|
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<()>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| Ok(args[0].clone())),
|
Token::Plus => Some(|_, args| Ok(args[0].clone())),
|
||||||
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::EqualsTo
|
||||||
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
| Token::GreaterThan
|
||||||
|
| Token::GreaterThanEqualsTo
|
||||||
|
| Token::LessThan
|
||||||
|
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
|
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -428,19 +434,9 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
if type1 == TypeId::of::<crate::Blob>() {
|
if type1 == TypeId::of::<crate::Blob>() {
|
||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
if type2 == TypeId::of::<INT>() {
|
|
||||||
return match op {
|
|
||||||
OP_CONTAINS => Some(|_, args| {
|
|
||||||
let blob = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
|
||||||
let x = (args[1].as_int().expect("`INT`") & 0x0000_00ff) as u8;
|
|
||||||
Ok((!blob.is_empty() && blob.contains(&x)).into())
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if type2 == TypeId::of::<char>() {
|
if type2 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+" => Some(|_, args| {
|
Token::Plus => Some(|_, args| {
|
||||||
let mut buf = [0_u8; 4];
|
let mut buf = [0_u8; 4];
|
||||||
let mut blob = args[0].read_lock::<Blob>().expect(BUILTIN).clone();
|
let mut blob = args[0].read_lock::<Blob>().expect(BUILTIN).clone();
|
||||||
let x = args[1].as_char().expect("`char`").encode_utf8(&mut buf);
|
let x = args[1].as_char().expect("`char`").encode_utf8(&mut buf);
|
||||||
@ -452,17 +448,6 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// map op string
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
if (type1, type2) == (TypeId::of::<crate::Map>(), TypeId::of::<ImmutableString>()) {
|
|
||||||
use crate::Map;
|
|
||||||
|
|
||||||
return match op {
|
|
||||||
OP_CONTAINS => Some(impl_op!(Map.contains_key(ImmutableString.as_str()))),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-compatible ranges
|
// Non-compatible ranges
|
||||||
if (type1, type2)
|
if (type1, type2)
|
||||||
== (
|
== (
|
||||||
@ -476,48 +461,28 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
return match op {
|
return match op {
|
||||||
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
"==" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::Equals => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle ranges here because ranges are implemented as custom type
|
// Handle ranges here because ranges are implemented as custom type
|
||||||
if type1 == TypeId::of::<ExclusiveRange>() {
|
if type1 == TypeId::of::<ExclusiveRange>() {
|
||||||
if type2 == TypeId::of::<INT>() {
|
|
||||||
return match op {
|
|
||||||
OP_CONTAINS => Some(|_, args| {
|
|
||||||
let range = &*args[0].read_lock::<ExclusiveRange>().expect(BUILTIN);
|
|
||||||
let x = args[1].as_int().expect("`INT`");
|
|
||||||
Ok(range.contains(&x).into())
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
Token::EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
||||||
"!=" => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
Token::NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<InclusiveRange>() {
|
if type1 == TypeId::of::<InclusiveRange>() {
|
||||||
if type2 == TypeId::of::<INT>() {
|
|
||||||
return match op {
|
|
||||||
OP_CONTAINS => Some(|_, args| {
|
|
||||||
let range = &*args[0].read_lock::<InclusiveRange>().expect(BUILTIN);
|
|
||||||
let x = args[1].as_int().expect("`INT`");
|
|
||||||
Ok(range.contains(&x).into())
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
return match op {
|
return match op {
|
||||||
"==" => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
Token::EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
||||||
"!=" => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
Token::NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -531,8 +496,12 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
} else if type1 != type2 {
|
} else if type1 != type2 {
|
||||||
// If the types are not the same, default to not compare
|
// If the types are not the same, default to not compare
|
||||||
match op {
|
match op {
|
||||||
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::EqualsTo
|
||||||
|
| Token::GreaterThan
|
||||||
|
| Token::GreaterThanEqualsTo
|
||||||
|
| Token::LessThan
|
||||||
|
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -544,8 +513,12 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
// Default comparison operators for different types
|
// Default comparison operators for different types
|
||||||
if type2 != type1 {
|
if type2 != type1 {
|
||||||
return match op {
|
return match op {
|
||||||
"!=" => Some(|_, _| Ok(Dynamic::TRUE)),
|
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
||||||
"==" | ">" | ">=" | "<" | "<=" => Some(|_, _| Ok(Dynamic::FALSE)),
|
Token::EqualsTo
|
||||||
|
| Token::GreaterThan
|
||||||
|
| Token::GreaterThanEqualsTo
|
||||||
|
| Token::LessThan
|
||||||
|
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -558,7 +531,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<Fn
|
|||||||
///
|
///
|
||||||
/// The return function is registered as a _method_, so the first parameter cannot be consumed.
|
/// The return function is registered as a _method_, so the first parameter cannot be consumed.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option<FnBuiltin> {
|
pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<FnBuiltin> {
|
||||||
let type1 = x.type_id();
|
let type1 = x.type_id();
|
||||||
let type2 = y.type_id();
|
let type2 = y.type_id();
|
||||||
|
|
||||||
@ -610,49 +583,51 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
"+=" => return Some(impl_op!(INT => add(as_int, as_int))),
|
Token::PlusAssign => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||||
"-=" => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
Token::MinusAssign => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||||
"*=" => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
Token::MultiplyAssign => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||||
"/=" => return Some(impl_op!(INT => divide(as_int, as_int))),
|
Token::DivideAssign => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||||
"%=" => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
Token::ModuloAssign => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||||
"**=" => return Some(impl_op!(INT => power(as_int, as_int))),
|
Token::PowerOfAssign => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||||
">>=" => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
Token::RightShiftAssign => {
|
||||||
"<<=" => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
return Some(impl_op!(INT => shift_right(as_int, as_int)))
|
||||||
|
}
|
||||||
|
Token::LeftShiftAssign => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
"+=" => return Some(impl_op!(INT += as_int)),
|
Token::PlusAssign => return Some(impl_op!(INT += as_int)),
|
||||||
"-=" => return Some(impl_op!(INT -= as_int)),
|
Token::MinusAssign => return Some(impl_op!(INT -= as_int)),
|
||||||
"*=" => return Some(impl_op!(INT *= as_int)),
|
Token::MultiplyAssign => return Some(impl_op!(INT *= as_int)),
|
||||||
"/=" => return Some(impl_op!(INT /= as_int)),
|
Token::DivideAssign => return Some(impl_op!(INT /= as_int)),
|
||||||
"%=" => return Some(impl_op!(INT %= as_int)),
|
Token::ModuloAssign => return Some(impl_op!(INT %= as_int)),
|
||||||
"**=" => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
Token::PowerOfAssign => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||||
">>=" => return Some(impl_op!(INT >>= as_int)),
|
Token::RightShiftAssign => return Some(impl_op!(INT >>= as_int)),
|
||||||
"<<=" => return Some(impl_op!(INT <<= as_int)),
|
Token::LeftShiftAssign => return Some(impl_op!(INT <<= as_int)),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"&=" => Some(impl_op!(INT &= as_int)),
|
Token::AndAssign => Some(impl_op!(INT &= as_int)),
|
||||||
"|=" => Some(impl_op!(INT |= as_int)),
|
Token::OrAssign => Some(impl_op!(INT |= as_int)),
|
||||||
"^=" => Some(impl_op!(INT ^= as_int)),
|
Token::XOrAssign => Some(impl_op!(INT ^= as_int)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<bool>() {
|
if type1 == TypeId::of::<bool>() {
|
||||||
return match op {
|
return match op {
|
||||||
"&=" => Some(impl_op!(bool = x && as_bool)),
|
Token::AndAssign => Some(impl_op!(bool = x && as_bool)),
|
||||||
"|=" => Some(impl_op!(bool = x || as_bool)),
|
Token::OrAssign => Some(impl_op!(bool = x || as_bool)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<char>() {
|
if type1 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
||||||
Ok((*x = format!("{x}{y}").into()).into())
|
Ok((*x = format!("{x}{y}").into()).into())
|
||||||
@ -663,13 +638,13 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
|
|
||||||
if type1 == TypeId::of::<ImmutableString>() {
|
if type1 == TypeId::of::<ImmutableString>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
||||||
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
||||||
Ok((*x += y).into())
|
Ok((*x += y).into())
|
||||||
}),
|
}),
|
||||||
"-=" => Some(|_, args| {
|
Token::MinusAssign => Some(|_, args| {
|
||||||
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
||||||
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
||||||
@ -684,7 +659,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let blob2 = std::mem::take(args[1]).cast::<Blob>();
|
let blob2 = std::mem::take(args[1]).cast::<Blob>();
|
||||||
let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append(blob1, blob2).into())
|
Ok(crate::packages::blob_basic::blob_functions::append(blob1, blob2).into())
|
||||||
@ -699,12 +674,12 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(impl_op!($x += $yy)),
|
Token::PlusAssign => Some(impl_op!($x += $yy)),
|
||||||
"-=" => Some(impl_op!($x -= $yy)),
|
Token::MinusAssign => Some(impl_op!($x -= $yy)),
|
||||||
"*=" => Some(impl_op!($x *= $yy)),
|
Token::MultiplyAssign => Some(impl_op!($x *= $yy)),
|
||||||
"/=" => Some(impl_op!($x /= $yy)),
|
Token::DivideAssign => Some(impl_op!($x /= $yy)),
|
||||||
"%=" => Some(impl_op!($x %= $yy)),
|
Token::ModuloAssign => Some(impl_op!($x %= $yy)),
|
||||||
"**=" => Some(impl_op!($x => $xx.powf($yy as $x))),
|
Token::PowerOfAssign => Some(impl_op!($x => $xx.powf($yy as $x))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -726,12 +701,12 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(impl_op!(from $x => add($xx, $yy))),
|
Token::PlusAssign => Some(impl_op!(from $x => add($xx, $yy))),
|
||||||
"-=" => Some(impl_op!(from $x => subtract($xx, $yy))),
|
Token::MinusAssign => Some(impl_op!(from $x => subtract($xx, $yy))),
|
||||||
"*=" => Some(impl_op!(from $x => multiply($xx, $yy))),
|
Token::MultiplyAssign => Some(impl_op!(from $x => multiply($xx, $yy))),
|
||||||
"/=" => Some(impl_op!(from $x => divide($xx, $yy))),
|
Token::DivideAssign => Some(impl_op!(from $x => divide($xx, $yy))),
|
||||||
"%=" => Some(impl_op!(from $x => modulo($xx, $yy))),
|
Token::ModuloAssign => Some(impl_op!(from $x => modulo($xx, $yy))),
|
||||||
"**=" => Some(impl_op!(from $x => power($xx, $yy))),
|
Token::PowerOfAssign => Some(impl_op!(from $x => power($xx, $yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -740,12 +715,12 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(impl_op!(from $x += $yy)),
|
Token::PlusAssign => Some(impl_op!(from $x += $yy)),
|
||||||
"-=" => Some(impl_op!(from $x -= $yy)),
|
Token::MinusAssign => Some(impl_op!(from $x -= $yy)),
|
||||||
"*=" => Some(impl_op!(from $x *= $yy)),
|
Token::MultiplyAssign => Some(impl_op!(from $x *= $yy)),
|
||||||
"/=" => Some(impl_op!(from $x /= $yy)),
|
Token::DivideAssign => Some(impl_op!(from $x /= $yy)),
|
||||||
"%=" => Some(impl_op!(from $x %= $yy)),
|
Token::ModuloAssign => Some(impl_op!(from $x %= $yy)),
|
||||||
"**=" => Some(impl_op!(from $x => $xx.powd($yy))),
|
Token::PowerOfAssign => Some(impl_op!(from $x => $xx.powd($yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -761,15 +736,15 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
// string op= char
|
// string op= char
|
||||||
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(impl_op!(ImmutableString += as_char as char)),
|
Token::PlusAssign => Some(impl_op!(ImmutableString += as_char as char)),
|
||||||
"-=" => Some(impl_op!(ImmutableString -= as_char as char)),
|
Token::MinusAssign => Some(impl_op!(ImmutableString -= as_char as char)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// char op= string
|
// char op= string
|
||||||
if (type1, type2) == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let mut ch = args[0].as_char().expect(BUILTIN).to_string();
|
let mut ch = args[0].as_char().expect(BUILTIN).to_string();
|
||||||
ch.push_str(
|
ch.push_str(
|
||||||
args[1]
|
args[1]
|
||||||
@ -793,7 +768,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
|
|
||||||
if type2 == TypeId::of::<crate::Array>() {
|
if type2 == TypeId::of::<crate::Array>() {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let array2 = std::mem::take(args[1]).cast::<Array>();
|
let array2 = std::mem::take(args[1]).cast::<Array>();
|
||||||
let array1 = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
let array1 = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
||||||
Ok(append(array1, array2).into())
|
Ok(append(array1, array2).into())
|
||||||
@ -802,7 +777,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let x = std::mem::take(args[1]);
|
let x = std::mem::take(args[1]);
|
||||||
let array = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
let array = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
||||||
Ok(push(array, x).into())
|
Ok(push(array, x).into())
|
||||||
@ -818,7 +793,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
// blob op= int
|
// blob op= int
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let x = args[1].as_int().expect("`INT`");
|
let x = args[1].as_int().expect("`INT`");
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::push(blob, x).into())
|
Ok(crate::packages::blob_basic::blob_functions::push(blob, x).into())
|
||||||
@ -830,7 +805,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
// blob op= char
|
// blob op= char
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let x = args[1].as_char().expect("`char`");
|
let x = args[1].as_char().expect("`char`");
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append_char(blob, x).into())
|
Ok(crate::packages::blob_basic::blob_functions::append_char(blob, x).into())
|
||||||
@ -842,7 +817,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
|
|||||||
// blob op= string
|
// blob op= string
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
||||||
return match op {
|
return match op {
|
||||||
"+=" => Some(|_, args| {
|
Token::PlusAssign => Some(|_, args| {
|
||||||
let s = std::mem::take(args[1]).cast::<ImmutableString>();
|
let s = std::mem::take(args[1]).cast::<ImmutableString>();
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append_str(blob, &s).into())
|
Ok(crate::packages::blob_basic::blob_functions::append_str(blob, &s).into())
|
||||||
|
@ -9,6 +9,7 @@ use crate::engine::{
|
|||||||
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::eval::{Caches, FnResolutionCacheEntry, GlobalRuntimeState};
|
use crate::eval::{Caches, FnResolutionCacheEntry, GlobalRuntimeState};
|
||||||
|
use crate::tokenizer::Token;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr,
|
||||||
ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf,
|
ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf,
|
||||||
@ -191,7 +192,7 @@ impl Engine {
|
|||||||
hash_base: u64,
|
hash_base: u64,
|
||||||
args: Option<&mut FnCallArgs>,
|
args: Option<&mut FnCallArgs>,
|
||||||
allow_dynamic: bool,
|
allow_dynamic: bool,
|
||||||
is_op_assignment: bool,
|
op_assignment_token: Option<&Token>,
|
||||||
) -> Option<&'s FnResolutionCacheEntry> {
|
) -> Option<&'s FnResolutionCacheEntry> {
|
||||||
if hash_base == 0 {
|
if hash_base == 0 {
|
||||||
return None;
|
return None;
|
||||||
@ -279,22 +280,23 @@ impl Engine {
|
|||||||
|
|
||||||
// Try to find a built-in version
|
// Try to find a built-in version
|
||||||
let builtin = args.and_then(|args| {
|
let builtin = args.and_then(|args| {
|
||||||
if is_op_assignment {
|
if let Some(op_assign) = op_assignment_token {
|
||||||
let (first_arg, rest_args) = args.split_first().unwrap();
|
let (first_arg, rest_args) = args.split_first().unwrap();
|
||||||
|
|
||||||
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map(
|
get_builtin_op_assignment_fn(op_assign, *first_arg, rest_args[0])
|
||||||
|f| FnResolutionCacheEntry {
|
.map(|f| FnResolutionCacheEntry {
|
||||||
func: CallableFunction::from_fn_builtin(f),
|
func: CallableFunction::from_fn_builtin(f),
|
||||||
source: None,
|
source: None,
|
||||||
},
|
})
|
||||||
)
|
} else if let Some(ref operator) = Token::lookup_from_syntax(fn_name) {
|
||||||
} else {
|
get_builtin_binary_op_fn(operator, args[0], args[1]).map(|f| {
|
||||||
get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| {
|
|
||||||
FnResolutionCacheEntry {
|
FnResolutionCacheEntry {
|
||||||
func: CallableFunction::from_fn_builtin(f),
|
func: CallableFunction::from_fn_builtin(f),
|
||||||
source: None,
|
source: None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -360,6 +362,11 @@ impl Engine {
|
|||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
self.inc_operations(&mut global.num_operations, pos)?;
|
||||||
|
|
||||||
let parent_source = global.source.clone();
|
let parent_source = global.source.clone();
|
||||||
|
let op_assign = if is_op_assign {
|
||||||
|
Token::lookup_from_syntax(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Check if function access already in the cache
|
// Check if function access already in the cache
|
||||||
let local_entry = &mut None;
|
let local_entry = &mut None;
|
||||||
@ -373,7 +380,7 @@ impl Engine {
|
|||||||
hash,
|
hash,
|
||||||
Some(args),
|
Some(args),
|
||||||
true,
|
true,
|
||||||
is_op_assign,
|
op_assign.as_ref(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if func.is_some() {
|
if func.is_some() {
|
||||||
@ -653,7 +660,7 @@ impl Engine {
|
|||||||
hashes.script,
|
hashes.script,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
false,
|
None,
|
||||||
)
|
)
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
@ -993,7 +1000,7 @@ impl Engine {
|
|||||||
args_expr: &[Expr],
|
args_expr: &[Expr],
|
||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
capture_scope: bool,
|
capture_scope: bool,
|
||||||
is_operator: bool,
|
operator_token: Option<&Token>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
@ -1006,7 +1013,7 @@ impl Engine {
|
|||||||
let redirected; // Handle call() - Redirect function call
|
let redirected; // Handle call() - Redirect function call
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
_ if is_operator => (),
|
_ if operator_token.is_some() => (),
|
||||||
|
|
||||||
// Handle call()
|
// Handle call()
|
||||||
KEYWORD_FN_PTR_CALL if total_args >= 1 => {
|
KEYWORD_FN_PTR_CALL if total_args >= 1 => {
|
||||||
|
@ -1181,8 +1181,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Overloaded operators can override built-in.
|
// Overloaded operators can override built-in.
|
||||||
_ if x.args.len() == 2 && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native, &arg_types)) => {
|
_ if x.args.len() == 2 && x.operator_token.is_some() && (state.engine.fast_operators() || !has_native_fn_override(state.engine, x.hashes.native, &arg_types)) => {
|
||||||
if let Some(result) = get_builtin_binary_op_fn(&x.name, &arg_values[0], &arg_values[1])
|
if let Some(result) = get_builtin_binary_op_fn(x.operator_token.as_ref().unwrap(), &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = state.lib;
|
let lib = state.lib;
|
||||||
|
@ -146,6 +146,21 @@ pub mod blob_functions {
|
|||||||
pub fn is_empty(blob: &mut Blob) -> bool {
|
pub fn is_empty(blob: &mut Blob) -> bool {
|
||||||
blob.len() == 0
|
blob.len() == 0
|
||||||
}
|
}
|
||||||
|
/// Return `true` if the BLOB contains a specified byte value.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "hello, world!";
|
||||||
|
///
|
||||||
|
/// print(text.contains('h')); // prints true
|
||||||
|
///
|
||||||
|
/// print(text.contains('x')); // prints false
|
||||||
|
/// ```
|
||||||
|
#[rhai_fn(name = "contains")]
|
||||||
|
pub fn contains(blob: &mut Blob, value: INT) -> bool {
|
||||||
|
blob.contains(&((value & 0x0000_00ff) as u8))
|
||||||
|
}
|
||||||
/// Get the byte value at the `index` position in the BLOB.
|
/// Get the byte value at the `index` position in the BLOB.
|
||||||
///
|
///
|
||||||
/// * If `index` < 0, position counts from the end of the BLOB (`-1` is the last element).
|
/// * If `index` < 0, position counts from the end of the BLOB (`-1` is the last element).
|
||||||
|
@ -668,6 +668,12 @@ mod range_functions {
|
|||||||
pub fn is_empty_exclusive(range: &mut ExclusiveRange) -> bool {
|
pub fn is_empty_exclusive(range: &mut ExclusiveRange) -> bool {
|
||||||
range.is_empty()
|
range.is_empty()
|
||||||
}
|
}
|
||||||
|
/// Return `true` if the range contains a specified value.
|
||||||
|
#[rhai_fn(name = "contains")]
|
||||||
|
pub fn contains_exclusive(range: &mut ExclusiveRange, value: INT) -> bool {
|
||||||
|
range.contains(&value)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the start of the inclusive range.
|
/// Return the start of the inclusive range.
|
||||||
#[rhai_fn(get = "start", name = "start", pure)]
|
#[rhai_fn(get = "start", name = "start", pure)]
|
||||||
pub fn start_inclusive(range: &mut InclusiveRange) -> INT {
|
pub fn start_inclusive(range: &mut InclusiveRange) -> INT {
|
||||||
@ -695,4 +701,9 @@ mod range_functions {
|
|||||||
pub fn is_empty_inclusive(range: &mut InclusiveRange) -> bool {
|
pub fn is_empty_inclusive(range: &mut InclusiveRange) -> bool {
|
||||||
range.is_empty()
|
range.is_empty()
|
||||||
}
|
}
|
||||||
|
/// Return `true` if the range contains a specified value.
|
||||||
|
#[rhai_fn(name = "contains")]
|
||||||
|
pub fn contains_inclusive(range: &mut InclusiveRange, value: INT) -> bool {
|
||||||
|
range.contains(&value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,20 @@ mod map_functions {
|
|||||||
pub fn is_empty(map: &mut Map) -> bool {
|
pub fn is_empty(map: &mut Map) -> bool {
|
||||||
map.len() == 0
|
map.len() == 0
|
||||||
}
|
}
|
||||||
|
/// Returns `true` if the object map contains a specified property.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let m = #{a: 1, b: 2, c: 3};
|
||||||
|
///
|
||||||
|
/// print(m.contains("b")); // prints true
|
||||||
|
///
|
||||||
|
/// print(m.contains("x")); // prints false
|
||||||
|
/// ```
|
||||||
|
pub fn contains(map: &mut Map, property: &str) -> bool {
|
||||||
|
map.contains_key(property)
|
||||||
|
}
|
||||||
/// Get the value of the `property` in the object map and return a copy.
|
/// Get the value of the `property` in the object map and return a copy.
|
||||||
///
|
///
|
||||||
/// If `property` does not exist in the object map, `()` is returned.
|
/// If `property` does not exist in the object map, `()` is returned.
|
||||||
|
@ -506,6 +506,37 @@ mod string_functions {
|
|||||||
*character = to_lower_char(*character);
|
*character = to_lower_char(*character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `true` if the string contains a specified string.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "hello, world!";
|
||||||
|
///
|
||||||
|
/// print(text.contains("hello")); // prints true
|
||||||
|
///
|
||||||
|
/// print(text.contains("hey")); // prints false
|
||||||
|
/// ```
|
||||||
|
pub fn contains(string: &str, match_string: &str) -> bool {
|
||||||
|
string.contains(match_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `true` if the string contains a specified character.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "hello, world!";
|
||||||
|
///
|
||||||
|
/// print(text.contains('h')); // prints true
|
||||||
|
///
|
||||||
|
/// print(text.contains('x')); // prints false
|
||||||
|
/// ```
|
||||||
|
#[rhai_fn(name = "contains")]
|
||||||
|
pub fn contains_char(string: &str, character: char) -> bool {
|
||||||
|
string.contains(character).into()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return `true` if the string starts with a specified string.
|
/// Return `true` if the string starts with a specified string.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -472,7 +472,7 @@ fn match_token(input: &mut TokenStream, token: Token) -> (bool, Position) {
|
|||||||
fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
|
fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
|
||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
// Variable name
|
// Variable name
|
||||||
(Token::Identifier(s), pos) => Ok((s, pos)),
|
(Token::Identifier(s), pos) => Ok((*s, pos)),
|
||||||
// Reserved keyword
|
// Reserved keyword
|
||||||
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
||||||
Err(PERR::Reserved(s.to_string()).into_err(pos))
|
Err(PERR::Reserved(s.to_string()).into_err(pos))
|
||||||
@ -492,7 +492,7 @@ fn parse_symbol(input: &mut TokenStream) -> ParseResult<(SmartString, Position)>
|
|||||||
// Symbol
|
// Symbol
|
||||||
(token, pos) if token.is_standard_symbol() => Ok((token.literal_syntax().into(), pos)),
|
(token, pos) if token.is_standard_symbol() => Ok((token.literal_syntax().into(), pos)),
|
||||||
// Reserved symbol
|
// Reserved symbol
|
||||||
(Token::Reserved(s), pos) if !is_valid_identifier(s.chars()) => Ok((s, pos)),
|
(Token::Reserved(s), pos) if !is_valid_identifier(s.chars()) => Ok((*s, pos)),
|
||||||
// Bad symbol
|
// Bad symbol
|
||||||
(Token::LexError(err), pos) => Err(err.into_err(pos)),
|
(Token::LexError(err), pos) => Err(err.into_err(pos)),
|
||||||
// Not a symbol
|
// Not a symbol
|
||||||
@ -616,7 +616,7 @@ impl Engine {
|
|||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
is_native_operator: false,
|
operator_token: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
@ -684,7 +684,7 @@ impl Engine {
|
|||||||
return Ok(FnCallExpr {
|
return Ok(FnCallExpr {
|
||||||
name: state.get_interned_string(id),
|
name: state.get_interned_string(id),
|
||||||
capture_parent_scope,
|
capture_parent_scope,
|
||||||
is_native_operator: false,
|
operator_token: None,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace,
|
namespace,
|
||||||
hashes,
|
hashes,
|
||||||
@ -1000,10 +1000,10 @@ impl Engine {
|
|||||||
|
|
||||||
let (name, pos) = match input.next().expect(NEVER_ENDS) {
|
let (name, pos) = match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::Identifier(s) | Token::StringConstant(s), pos) => {
|
(Token::Identifier(s) | Token::StringConstant(s), pos) => {
|
||||||
if map.iter().any(|(p, ..)| **p == s) {
|
if map.iter().any(|(p, ..)| **p == *s) {
|
||||||
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
|
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
|
||||||
}
|
}
|
||||||
(s, pos)
|
(*s, pos)
|
||||||
}
|
}
|
||||||
(Token::InterpolatedString(..), pos) => {
|
(Token::InterpolatedString(..), pos) => {
|
||||||
return Err(PERR::PropertyExpected.into_err(pos))
|
return Err(PERR::PropertyExpected.into_err(pos))
|
||||||
@ -1342,7 +1342,7 @@ impl Engine {
|
|||||||
Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
|
Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
|
||||||
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
||||||
Token::StringConstant(s) => {
|
Token::StringConstant(s) => {
|
||||||
Expr::StringConstant(state.get_interned_string(s), settings.pos)
|
Expr::StringConstant(state.get_interned_string(*s), settings.pos)
|
||||||
}
|
}
|
||||||
Token::True => Expr::BoolConstant(true, settings.pos),
|
Token::True => Expr::BoolConstant(true, settings.pos),
|
||||||
Token::False => Expr::BoolConstant(false, settings.pos),
|
Token::False => Expr::BoolConstant(false, settings.pos),
|
||||||
@ -1356,7 +1356,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
Token::DecimalConstant(x) => {
|
Token::DecimalConstant(x) => {
|
||||||
let x = (*x).into();
|
let x = (**x).into();
|
||||||
input.next();
|
input.next();
|
||||||
Expr::DynamicConstant(Box::new(x), settings.pos)
|
Expr::DynamicConstant(Box::new(x), settings.pos)
|
||||||
}
|
}
|
||||||
@ -1479,7 +1479,7 @@ impl Engine {
|
|||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::InterpolatedString(s), ..) if s.is_empty() => (),
|
(Token::InterpolatedString(s), ..) if s.is_empty() => (),
|
||||||
(Token::InterpolatedString(s), pos) => {
|
(Token::InterpolatedString(s), pos) => {
|
||||||
segments.push(Expr::StringConstant(s.into(), pos))
|
segments.push(Expr::StringConstant(state.get_interned_string(*s), pos))
|
||||||
}
|
}
|
||||||
token => {
|
token => {
|
||||||
unreachable!("Token::InterpolatedString expected but gets {:?}", token)
|
unreachable!("Token::InterpolatedString expected but gets {:?}", token)
|
||||||
@ -1502,14 +1502,16 @@ impl Engine {
|
|||||||
match input.next().expect(NEVER_ENDS) {
|
match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::StringConstant(s), pos) => {
|
(Token::StringConstant(s), pos) => {
|
||||||
if !s.is_empty() {
|
if !s.is_empty() {
|
||||||
segments.push(Expr::StringConstant(s.into(), pos));
|
segments
|
||||||
|
.push(Expr::StringConstant(state.get_interned_string(*s), pos));
|
||||||
}
|
}
|
||||||
// End the interpolated string if it is terminated by a back-tick.
|
// End the interpolated string if it is terminated by a back-tick.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(Token::InterpolatedString(s), pos) => {
|
(Token::InterpolatedString(s), pos) => {
|
||||||
if !s.is_empty() {
|
if !s.is_empty() {
|
||||||
segments.push(Expr::StringConstant(s.into(), pos));
|
segments
|
||||||
|
.push(Expr::StringConstant(state.get_interned_string(*s), pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Token::LexError(err), pos)
|
(Token::LexError(err), pos)
|
||||||
@ -1574,7 +1576,7 @@ impl Engine {
|
|||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, ns, 0, state.get_interned_string(s)).into(),
|
(None, ns, 0, state.get_interned_string(*s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1587,7 +1589,7 @@ 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;
|
||||||
}
|
}
|
||||||
let name = state.get_interned_string(s);
|
let name = state.get_interned_string(*s);
|
||||||
Expr::Variable((None, ns, 0, name).into(), None, settings.pos)
|
Expr::Variable((None, ns, 0, name).into(), None, settings.pos)
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
@ -1612,7 +1614,7 @@ impl Engine {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let name = state.get_interned_string(s);
|
let name = state.get_interned_string(*s);
|
||||||
Expr::Variable((index, ns, 0, name).into(), short_index, settings.pos)
|
Expr::Variable((index, ns, 0, name).into(), short_index, settings.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1634,7 +1636,7 @@ impl Engine {
|
|||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
Token::LeftParen | Token::Bang | Token::Unit if is_keyword_function(&s) => {
|
Token::LeftParen | Token::Bang | Token::Unit if is_keyword_function(&s) => {
|
||||||
Expr::Variable(
|
Expr::Variable(
|
||||||
(None, ns, 0, state.get_interned_string(s)).into(),
|
(None, ns, 0, state.get_interned_string(*s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)
|
)
|
||||||
@ -1642,7 +1644,7 @@ impl Engine {
|
|||||||
// Access to `this` as a variable is OK within a function scope
|
// Access to `this` as a variable is OK within a function scope
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable(
|
_ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable(
|
||||||
(None, ns, 0, state.get_interned_string(s)).into(),
|
(None, ns, 0, state.get_interned_string(*s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
),
|
),
|
||||||
@ -1888,7 +1890,7 @@ impl Engine {
|
|||||||
// -expr
|
// -expr
|
||||||
Token::Minus | Token::UnaryMinus => {
|
Token::Minus | Token::UnaryMinus => {
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
let pos = eat_token(input, token);
|
let pos = eat_token(input, token.clone());
|
||||||
|
|
||||||
match self.parse_unary(input, state, lib, settings.level_up())? {
|
match self.parse_unary(input, state, lib, settings.level_up())? {
|
||||||
// Negative integer
|
// Negative integer
|
||||||
@ -1918,7 +1920,7 @@ impl Engine {
|
|||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "-", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
is_native_operator: true,
|
operator_token: Some(token),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -1928,7 +1930,7 @@ impl Engine {
|
|||||||
// +expr
|
// +expr
|
||||||
Token::Plus | Token::UnaryPlus => {
|
Token::Plus | Token::UnaryPlus => {
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
let pos = eat_token(input, token);
|
let pos = eat_token(input, token.clone());
|
||||||
|
|
||||||
match self.parse_unary(input, state, lib, settings.level_up())? {
|
match self.parse_unary(input, state, lib, settings.level_up())? {
|
||||||
expr @ Expr::IntegerConstant(..) => Ok(expr),
|
expr @ Expr::IntegerConstant(..) => Ok(expr),
|
||||||
@ -1946,7 +1948,7 @@ impl Engine {
|
|||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "+", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
is_native_operator: true,
|
operator_token: Some(token),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -1955,7 +1957,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// !expr
|
// !expr
|
||||||
Token::Bang => {
|
Token::Bang => {
|
||||||
|
let token = token.clone();
|
||||||
let pos = eat_token(input, Token::Bang);
|
let pos = eat_token(input, Token::Bang);
|
||||||
|
|
||||||
let mut args = StaticVec::new_const();
|
let mut args = StaticVec::new_const();
|
||||||
args.push(self.parse_unary(input, state, lib, settings.level_up())?);
|
args.push(self.parse_unary(input, state, lib, settings.level_up())?);
|
||||||
args.shrink_to_fit();
|
args.shrink_to_fit();
|
||||||
@ -1965,7 +1969,7 @@ impl Engine {
|
|||||||
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
hashes: FnCallHashes::from_native(calc_fn_hash(None, "!", 1)),
|
||||||
args,
|
args,
|
||||||
pos,
|
pos,
|
||||||
is_native_operator: true,
|
operator_token: Some(token),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.into_fn_call_expr(pos))
|
.into_fn_call_expr(pos))
|
||||||
@ -2283,7 +2287,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(&**c)
|
||||||
.copied()
|
.copied()
|
||||||
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
@ -2308,7 +2312,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Token::Custom(c) => self
|
Token::Custom(c) => self
|
||||||
.custom_keywords
|
.custom_keywords
|
||||||
.get(c)
|
.get(&**c)
|
||||||
.copied()
|
.copied()
|
||||||
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
|
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
|
||||||
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
|
||||||
@ -2335,12 +2339,17 @@ impl Engine {
|
|||||||
|
|
||||||
let op = op_token.syntax();
|
let op = op_token.syntax();
|
||||||
let hash = calc_fn_hash(None, &op, 2);
|
let hash = calc_fn_hash(None, &op, 2);
|
||||||
|
let operator_token = if is_valid_function_name(&op) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(op_token.clone())
|
||||||
|
};
|
||||||
|
|
||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
name: state.get_interned_string(op.as_ref()),
|
name: state.get_interned_string(op.as_ref()),
|
||||||
hashes: FnCallHashes::from_native(hash),
|
hashes: FnCallHashes::from_native(hash),
|
||||||
pos,
|
pos,
|
||||||
is_native_operator: !is_valid_function_name(&op),
|
operator_token,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2578,7 +2587,7 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) {
|
CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::StringConstant(s), pos) => {
|
(Token::StringConstant(s), pos) => {
|
||||||
let s = state.get_interned_string(s);
|
let s = state.get_interned_string(*s);
|
||||||
inputs.push(Expr::StringConstant(s.clone(), pos));
|
inputs.push(Expr::StringConstant(s.clone(), pos));
|
||||||
segments.push(s);
|
segments.push(s);
|
||||||
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_STRING));
|
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_STRING));
|
||||||
@ -3228,7 +3237,7 @@ impl Engine {
|
|||||||
|
|
||||||
match input.next().expect(NEVER_ENDS).0 {
|
match input.next().expect(NEVER_ENDS).0 {
|
||||||
Token::Comment(comment) => {
|
Token::Comment(comment) => {
|
||||||
comments.push(comment);
|
comments.push(*comment);
|
||||||
|
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::Fn | Token::Private, ..) => break,
|
(Token::Fn | Token::Private, ..) => break,
|
||||||
@ -3562,7 +3571,7 @@ impl Engine {
|
|||||||
return Err(PERR::FnDuplicatedParam(name.to_string(), s.to_string())
|
return Err(PERR::FnDuplicatedParam(name.to_string(), s.to_string())
|
||||||
.into_err(pos));
|
.into_err(pos));
|
||||||
}
|
}
|
||||||
let s = state.get_interned_string(s);
|
let s = state.get_interned_string(*s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params.push((s, pos));
|
params.push((s, pos));
|
||||||
}
|
}
|
||||||
@ -3700,7 +3709,7 @@ impl Engine {
|
|||||||
PERR::FnDuplicatedParam(String::new(), s.to_string()).into_err(pos)
|
PERR::FnDuplicatedParam(String::new(), s.to_string()).into_err(pos)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let s = state.get_interned_string(s);
|
let s = state.get_interned_string(*s);
|
||||||
state.stack.push(s.clone(), ());
|
state.stack.push(s.clone(), ());
|
||||||
params_list.push(s);
|
params_list.push(s);
|
||||||
}
|
}
|
||||||
|
10
src/tests.rs
10
src/tests.rs
@ -22,15 +22,7 @@ fn check_struct_sizes() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
size_of::<tokenizer::Token>(),
|
size_of::<tokenizer::Token>(),
|
||||||
if IS_32_BIT {
|
if IS_32_BIT { 8 } else { 16 }
|
||||||
if cfg!(feature = "decimal") {
|
|
||||||
24
|
|
||||||
} else {
|
|
||||||
16
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
32
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(size_of::<ast::Expr>(), if PACKED { 12 } else { 16 });
|
assert_eq!(size_of::<ast::Expr>(), if PACKED { 12 } else { 16 });
|
||||||
assert_eq!(size_of::<Option<ast::Expr>>(), if PACKED { 12 } else { 16 });
|
assert_eq!(size_of::<Option<ast::Expr>>(), if PACKED { 12 } else { 16 });
|
||||||
|
105
src/tokenizer.rs
105
src/tokenizer.rs
@ -381,15 +381,15 @@ pub enum Token {
|
|||||||
///
|
///
|
||||||
/// Requires the `decimal` feature.
|
/// Requires the `decimal` feature.
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
DecimalConstant(rust_decimal::Decimal),
|
DecimalConstant(Box<rust_decimal::Decimal>),
|
||||||
/// An identifier.
|
/// An identifier.
|
||||||
Identifier(Identifier),
|
Identifier(Box<Identifier>),
|
||||||
/// A character constant.
|
/// A character constant.
|
||||||
CharConstant(char),
|
CharConstant(char),
|
||||||
/// A string constant.
|
/// A string constant.
|
||||||
StringConstant(SmartString),
|
StringConstant(Box<SmartString>),
|
||||||
/// An interpolated string.
|
/// An interpolated string.
|
||||||
InterpolatedString(SmartString),
|
InterpolatedString(Box<SmartString>),
|
||||||
/// `{`
|
/// `{`
|
||||||
LeftBrace,
|
LeftBrace,
|
||||||
/// `}`
|
/// `}`
|
||||||
@ -570,14 +570,14 @@ pub enum Token {
|
|||||||
/// A lexer error.
|
/// A lexer error.
|
||||||
LexError(Box<LexError>),
|
LexError(Box<LexError>),
|
||||||
/// A comment block.
|
/// A comment block.
|
||||||
Comment(SmartString),
|
Comment(Box<SmartString>),
|
||||||
/// A reserved symbol.
|
/// A reserved symbol.
|
||||||
Reserved(SmartString),
|
Reserved(Box<SmartString>),
|
||||||
/// A custom keyword.
|
/// A custom keyword.
|
||||||
///
|
///
|
||||||
/// Not available under `no_custom_syntax`.
|
/// Not available under `no_custom_syntax`.
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Custom(SmartString),
|
Custom(Box<SmartString>),
|
||||||
/// End of the input stream.
|
/// End of the input stream.
|
||||||
EOF,
|
EOF,
|
||||||
}
|
}
|
||||||
@ -898,21 +898,23 @@ impl Token {
|
|||||||
|
|
||||||
// List of reserved operators
|
// List of reserved operators
|
||||||
"===" | "!==" | "->" | "<-" | "?" | ":=" | ":;" | "~" | "!." | "::<" | "(*" | "*)"
|
"===" | "!==" | "->" | "<-" | "?" | ":=" | ":;" | "~" | "!." | "::<" | "(*" | "*)"
|
||||||
| "#" | "#!" | "@" | "$" | "++" | "--" | "..." | "<|" | "|>" => Reserved(syntax.into()),
|
| "#" | "#!" | "@" | "$" | "++" | "--" | "..." | "<|" | "|>" => {
|
||||||
|
Reserved(Box::new(syntax.into()))
|
||||||
|
}
|
||||||
|
|
||||||
// List of reserved keywords
|
// List of reserved keywords
|
||||||
"public" | "protected" | "super" | "new" | "use" | "module" | "package" | "var"
|
"public" | "protected" | "super" | "new" | "use" | "module" | "package" | "var"
|
||||||
| "static" | "shared" | "with" | "is" | "goto" | "exit" | "match" | "case"
|
| "static" | "shared" | "with" | "is" | "goto" | "exit" | "match" | "case"
|
||||||
| "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync"
|
| "default" | "void" | "null" | "nil" | "spawn" | "thread" | "go" | "sync"
|
||||||
| "async" | "await" | "yield" => Reserved(syntax.into()),
|
| "async" | "await" | "yield" => Reserved(Box::new(syntax.into())),
|
||||||
|
|
||||||
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR
|
||||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS | KEYWORD_IS_DEF_VAR => {
|
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_THIS | KEYWORD_IS_DEF_VAR => {
|
||||||
Reserved(syntax.into())
|
Reserved(Box::new(syntax.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
crate::engine::KEYWORD_IS_DEF_FN => Reserved(syntax.into()),
|
crate::engine::KEYWORD_IS_DEF_FN => Reserved(Box::new(syntax.into())),
|
||||||
|
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
@ -1097,8 +1099,8 @@ impl Token {
|
|||||||
pub(crate) fn into_function_name_for_override(self) -> Result<SmartString, Self> {
|
pub(crate) fn into_function_name_for_override(self) -> Result<SmartString, Self> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
Self::Custom(s) if is_valid_function_name(&s) => Ok(s),
|
Self::Custom(s) if is_valid_function_name(&s) => Ok(*s),
|
||||||
Self::Identifier(s) if is_valid_function_name(&s) => Ok(s),
|
Self::Identifier(s) if is_valid_function_name(&s) => Ok(*s),
|
||||||
_ => Err(self),
|
_ => Err(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1510,7 +1512,7 @@ fn get_next_token_inner(
|
|||||||
let return_comment = return_comment || is_doc_comment(comment.as_ref().expect("`Some`"));
|
let return_comment = return_comment || is_doc_comment(comment.as_ref().expect("`Some`"));
|
||||||
|
|
||||||
if return_comment {
|
if return_comment {
|
||||||
return Some((Token::Comment(comment.expect("`Some`")), start_pos));
|
return Some((Token::Comment(comment.expect("`Some`").into()), start_pos));
|
||||||
}
|
}
|
||||||
if state.comment_level > 0 {
|
if state.comment_level > 0 {
|
||||||
// Reached EOF without ending comment block
|
// Reached EOF without ending comment block
|
||||||
@ -1524,9 +1526,9 @@ fn get_next_token_inner(
|
|||||||
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
||||||
|(result, interpolated, start_pos)| {
|
|(result, interpolated, start_pos)| {
|
||||||
if interpolated {
|
if interpolated {
|
||||||
Some((Token::InterpolatedString(result), start_pos))
|
Some((Token::InterpolatedString(result.into()), start_pos))
|
||||||
} else {
|
} else {
|
||||||
Some((Token::StringConstant(result), start_pos))
|
Some((Token::StringConstant(result.into()), start_pos))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1676,13 +1678,16 @@ fn get_next_token_inner(
|
|||||||
// Then try decimal
|
// Then try decimal
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
let num = num.or_else(|_| {
|
let num = num.or_else(|_| {
|
||||||
rust_decimal::Decimal::from_str(&result).map(Token::DecimalConstant)
|
rust_decimal::Decimal::from_str(&result)
|
||||||
|
.map(Box::new)
|
||||||
|
.map(Token::DecimalConstant)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then try decimal in scientific notation
|
// Then try decimal in scientific notation
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
let num = num.or_else(|_| {
|
let num = num.or_else(|_| {
|
||||||
rust_decimal::Decimal::from_scientific(&result)
|
rust_decimal::Decimal::from_scientific(&result)
|
||||||
|
.map(Box::new)
|
||||||
.map(Token::DecimalConstant)
|
.map(Token::DecimalConstant)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1709,7 +1714,7 @@ fn get_next_token_inner(
|
|||||||
return parse_string_literal(stream, state, pos, c, false, true, false)
|
return parse_string_literal(stream, state, pos, c, false, true, false)
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
||||||
|(result, ..)| Some((Token::StringConstant(result), start_pos)),
|
|(result, ..)| Some((Token::StringConstant(result.into()), start_pos)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// ` - string literal
|
// ` - string literal
|
||||||
@ -1737,9 +1742,9 @@ fn get_next_token_inner(
|
|||||||
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
|(err, err_pos)| Some((Token::LexError(err.into()), err_pos)),
|
||||||
|(result, interpolated, ..)| {
|
|(result, interpolated, ..)| {
|
||||||
if interpolated {
|
if interpolated {
|
||||||
Some((Token::InterpolatedString(result), start_pos))
|
Some((Token::InterpolatedString(result.into()), start_pos))
|
||||||
} else {
|
} else {
|
||||||
Some((Token::StringConstant(result), start_pos))
|
Some((Token::StringConstant(result.into()), start_pos))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1786,7 +1791,7 @@ fn get_next_token_inner(
|
|||||||
// Parentheses
|
// Parentheses
|
||||||
('(', '*') => {
|
('(', '*') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("(*".into()), start_pos));
|
return Some((Token::Reserved(Box::new("(*".into())), start_pos));
|
||||||
}
|
}
|
||||||
('(', ..) => return Some((Token::LeftParen, start_pos)),
|
('(', ..) => return Some((Token::LeftParen, start_pos)),
|
||||||
(')', ..) => return Some((Token::RightParen, start_pos)),
|
(')', ..) => return Some((Token::RightParen, start_pos)),
|
||||||
@ -1802,7 +1807,7 @@ fn get_next_token_inner(
|
|||||||
return Some((Token::MapStart, start_pos));
|
return Some((Token::MapStart, start_pos));
|
||||||
}
|
}
|
||||||
// Shebang
|
// Shebang
|
||||||
('#', '!') => return Some((Token::Reserved("#!".into()), start_pos)),
|
('#', '!') => return Some((Token::Reserved(Box::new("#!".into())), start_pos)),
|
||||||
|
|
||||||
('#', ' ') => {
|
('#', ' ') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1812,10 +1817,10 @@ fn get_next_token_inner(
|
|||||||
} else {
|
} else {
|
||||||
"#"
|
"#"
|
||||||
};
|
};
|
||||||
return Some((Token::Reserved(token.into()), start_pos));
|
return Some((Token::Reserved(Box::new(token.into())), start_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
('#', ..) => return Some((Token::Reserved("#".into()), start_pos)),
|
('#', ..) => return Some((Token::Reserved(Box::new("#".into())), start_pos)),
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
('+', '=') => {
|
('+', '=') => {
|
||||||
@ -1824,7 +1829,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('+', '+') => {
|
('+', '+') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("++".into()), start_pos));
|
return Some((Token::Reserved(Box::new("++".into())), start_pos));
|
||||||
}
|
}
|
||||||
('+', ..) if !state.next_token_cannot_be_unary => {
|
('+', ..) if !state.next_token_cannot_be_unary => {
|
||||||
return Some((Token::UnaryPlus, start_pos))
|
return Some((Token::UnaryPlus, start_pos))
|
||||||
@ -1839,11 +1844,11 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('-', '>') => {
|
('-', '>') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("->".into()), start_pos));
|
return Some((Token::Reserved(Box::new("->".into())), start_pos));
|
||||||
}
|
}
|
||||||
('-', '-') => {
|
('-', '-') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("--".into()), start_pos));
|
return Some((Token::Reserved(Box::new("--".into())), start_pos));
|
||||||
}
|
}
|
||||||
('-', ..) if !state.next_token_cannot_be_unary => {
|
('-', ..) if !state.next_token_cannot_be_unary => {
|
||||||
return Some((Token::UnaryMinus, start_pos))
|
return Some((Token::UnaryMinus, start_pos))
|
||||||
@ -1852,7 +1857,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
('*', ')') => {
|
('*', ')') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("*)".into()), start_pos));
|
return Some((Token::Reserved(Box::new("*)".into())), start_pos));
|
||||||
}
|
}
|
||||||
('*', '=') => {
|
('*', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1925,7 +1930,7 @@ fn get_next_token_inner(
|
|||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.global_comments
|
.global_comments
|
||||||
.push(comment),
|
.push(comment),
|
||||||
_ => return Some((Token::Comment(comment), start_pos)),
|
_ => return Some((Token::Comment(comment.into()), start_pos)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1953,7 +1958,7 @@ fn get_next_token_inner(
|
|||||||
scan_block_comment(stream, state.comment_level, pos, comment.as_mut());
|
scan_block_comment(stream, state.comment_level, pos, comment.as_mut());
|
||||||
|
|
||||||
if let Some(comment) = comment {
|
if let Some(comment) = comment {
|
||||||
return Some((Token::Comment(comment), start_pos));
|
return Some((Token::Comment(comment.into()), start_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,7 +1977,7 @@ fn get_next_token_inner(
|
|||||||
match stream.peek_next() {
|
match stream.peek_next() {
|
||||||
Some('.') => {
|
Some('.') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
Token::Reserved("...".into())
|
Token::Reserved(Box::new("...".into()))
|
||||||
}
|
}
|
||||||
Some('=') => {
|
Some('=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -1990,7 +1995,7 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
if stream.peek_next() == Some('=') {
|
if stream.peek_next() == Some('=') {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("===".into()), start_pos));
|
return Some((Token::Reserved(Box::new("===".into())), start_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some((Token::EqualsTo, start_pos));
|
return Some((Token::EqualsTo, start_pos));
|
||||||
@ -2007,18 +2012,18 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
if stream.peek_next() == Some('<') {
|
if stream.peek_next() == Some('<') {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("::<".into()), start_pos));
|
return Some((Token::Reserved(Box::new("::<".into())), start_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some((Token::DoubleColon, start_pos));
|
return Some((Token::DoubleColon, start_pos));
|
||||||
}
|
}
|
||||||
(':', '=') => {
|
(':', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved(":=".into()), start_pos));
|
return Some((Token::Reserved(Box::new(":=".into())), start_pos));
|
||||||
}
|
}
|
||||||
(':', ';') => {
|
(':', ';') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved(":;".into()), start_pos));
|
return Some((Token::Reserved(Box::new(":;".into())), start_pos));
|
||||||
}
|
}
|
||||||
(':', ..) => return Some((Token::Colon, start_pos)),
|
(':', ..) => return Some((Token::Colon, start_pos)),
|
||||||
|
|
||||||
@ -2028,7 +2033,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('<', '-') => {
|
('<', '-') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("<-".into()), start_pos));
|
return Some((Token::Reserved(Box::new("<-".into())), start_pos));
|
||||||
}
|
}
|
||||||
('<', '<') => {
|
('<', '<') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -2045,7 +2050,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('<', '|') => {
|
('<', '|') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("<|".into()), start_pos));
|
return Some((Token::Reserved(Box::new("<|".into())), start_pos));
|
||||||
}
|
}
|
||||||
('<', ..) => return Some((Token::LessThan, start_pos)),
|
('<', ..) => return Some((Token::LessThan, start_pos)),
|
||||||
|
|
||||||
@ -2073,14 +2078,14 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
if stream.peek_next() == Some('=') {
|
if stream.peek_next() == Some('=') {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("!==".into()), start_pos));
|
return Some((Token::Reserved(Box::new("!==".into())), start_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some((Token::NotEqualsTo, start_pos));
|
return Some((Token::NotEqualsTo, start_pos));
|
||||||
}
|
}
|
||||||
('!', '.') => {
|
('!', '.') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("!.".into()), start_pos));
|
return Some((Token::Reserved(Box::new("!.".into())), start_pos));
|
||||||
}
|
}
|
||||||
('!', ..) => return Some((Token::Bang, start_pos)),
|
('!', ..) => return Some((Token::Bang, start_pos)),
|
||||||
|
|
||||||
@ -2094,7 +2099,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('|', '>') => {
|
('|', '>') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
return Some((Token::Reserved("|>".into()), start_pos));
|
return Some((Token::Reserved(Box::new("|>".into())), start_pos));
|
||||||
}
|
}
|
||||||
('|', ..) => return Some((Token::Pipe, start_pos)),
|
('|', ..) => return Some((Token::Pipe, start_pos)),
|
||||||
|
|
||||||
@ -2114,7 +2119,7 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('^', ..) => return Some((Token::XOr, start_pos)),
|
('^', ..) => return Some((Token::XOr, start_pos)),
|
||||||
|
|
||||||
('~', ..) => return Some((Token::Reserved("~".into()), start_pos)),
|
('~', ..) => return Some((Token::Reserved(Box::new("~".into())), start_pos)),
|
||||||
|
|
||||||
('%', '=') => {
|
('%', '=') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -2122,9 +2127,9 @@ fn get_next_token_inner(
|
|||||||
}
|
}
|
||||||
('%', ..) => return Some((Token::Modulo, start_pos)),
|
('%', ..) => return Some((Token::Modulo, start_pos)),
|
||||||
|
|
||||||
('@', ..) => return Some((Token::Reserved("@".into()), start_pos)),
|
('@', ..) => return Some((Token::Reserved(Box::new("@".into())), start_pos)),
|
||||||
|
|
||||||
('$', ..) => return Some((Token::Reserved("$".into()), start_pos)),
|
('$', ..) => return Some((Token::Reserved(Box::new("$".into())), start_pos)),
|
||||||
|
|
||||||
('?', '.') => {
|
('?', '.') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
@ -2132,7 +2137,7 @@ fn get_next_token_inner(
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Token::Elvis,
|
Token::Elvis,
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
Token::Reserved("?.".into()),
|
Token::Reserved(Box::new("?.".into())),
|
||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -2146,11 +2151,11 @@ fn get_next_token_inner(
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::QuestionBracket,
|
Token::QuestionBracket,
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
Token::Reserved("?[".into()),
|
Token::Reserved(Box::new("?[".into())),
|
||||||
start_pos,
|
start_pos,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
('?', ..) => return Some((Token::Reserved("?".into()), start_pos)),
|
('?', ..) => return Some((Token::Reserved(Box::new("?".into())), start_pos)),
|
||||||
|
|
||||||
(ch, ..) if ch.is_whitespace() => (),
|
(ch, ..) if ch.is_whitespace() => (),
|
||||||
|
|
||||||
@ -2201,7 +2206,7 @@ fn get_identifier(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
(Token::Identifier(identifier), start_pos)
|
(Token::Identifier(identifier.into()), start_pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is a keyword allowed as a function?
|
/// Is a keyword allowed as a function?
|
||||||
@ -2382,7 +2387,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
// Reserved keyword/symbol
|
// Reserved keyword/symbol
|
||||||
Some((Token::Reserved(s), pos)) => (match
|
Some((Token::Reserved(s), pos)) => (match
|
||||||
(&*s,
|
(s.as_str(),
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
(!self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s)),
|
(!self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(&*s)),
|
||||||
#[cfg(feature = "no_custom_syntax")]
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
@ -2438,7 +2443,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
|
Some((token, pos)) if !self.engine.custom_keywords.is_empty() && self.engine.custom_keywords.contains_key(token.literal_syntax()) => {
|
||||||
if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
|
if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) {
|
||||||
// Disabled standard keyword/symbol
|
// Disabled standard keyword/symbol
|
||||||
(Token::Custom(token.literal_syntax().into()), pos)
|
(Token::Custom(Box::new(token.literal_syntax().into())), pos)
|
||||||
} else {
|
} else {
|
||||||
// Active standard keyword - should never be a custom keyword!
|
// Active standard keyword - should never be a custom keyword!
|
||||||
unreachable!("{:?} is an active keyword", token)
|
unreachable!("{:?} is an active keyword", token)
|
||||||
@ -2446,7 +2451,7 @@ impl<'a> Iterator for TokenIterator<'a> {
|
|||||||
}
|
}
|
||||||
// Disabled symbol
|
// Disabled symbol
|
||||||
Some((token, pos)) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) => {
|
Some((token, pos)) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token.literal_syntax()) => {
|
||||||
(Token::Reserved(token.literal_syntax().into()), pos)
|
(Token::Reserved(Box::new(token.literal_syntax().into())), pos)
|
||||||
}
|
}
|
||||||
// Normal symbol
|
// Normal symbol
|
||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user