diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index 868b9931..7aaad56b 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -273,7 +273,7 @@ impl Engine { .into_err(Position::NONE)); } // Identifier in first position - _ if segments.is_empty() && is_valid_identifier(s.chars()) => { + _ if segments.is_empty() && is_valid_identifier(s) => { // Make it a custom keyword/symbol if it is disabled or reserved if (!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s)) || token.map_or(false, |v| v.is_reserved()) diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 863299c8..f42209b6 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -111,9 +111,11 @@ impl CustomExpr { pub struct FnCallHashes { /// Pre-calculated hash for a script-defined function (zero if native functions only). #[cfg(not(feature = "no_function"))] - pub script: u64, + script: u64, /// Pre-calculated hash for a native Rust function with no parameter types. - pub native: u64, + /// + /// This hash can never be zero. + native: u64, } impl fmt::Debug for FnCallHashes { @@ -148,7 +150,7 @@ impl From for FnCallHashes { impl FnCallHashes { /// Create a [`FnCallHashes`] with only the native Rust hash. - #[inline] + #[inline(always)] #[must_use] pub const fn from_native(hash: u64) -> Self { Self { @@ -158,7 +160,7 @@ impl FnCallHashes { } } /// Create a [`FnCallHashes`] with both native Rust and script function hashes. - #[inline] + #[inline(always)] #[must_use] pub const fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self { Self { @@ -167,16 +169,29 @@ impl FnCallHashes { native: if native == 0 { ALT_ZERO_HASH } else { native }, } } - /// Is this [`FnCallHashes`] native Rust only? + /// Is this [`FnCallHashes`] native-only? #[inline(always)] #[must_use] pub const fn is_native_only(&self) -> bool { #[cfg(not(feature = "no_function"))] return self.script == 0; - #[cfg(feature = "no_function")] return true; } + /// Get the native hash. + #[inline(always)] + #[must_use] + pub const fn native(&self) -> u64 { + self.native + } + /// Get the script hash. + #[cfg(not(feature = "no_function"))] + #[inline(always)] + #[must_use] + pub const fn script(&self) -> u64 { + assert!(self.script != 0); + self.script + } } /// _(internals)_ A function call. @@ -196,9 +211,6 @@ pub struct FnCallExpr { pub capture_parent_scope: bool, /// Is this function call a native operator? pub operator_token: Option, - /// Can this function call be a scripted function? - #[cfg(not(feature = "no_function"))] - pub can_be_script: bool, /// [Position] of the function name. pub pos: Position, } @@ -221,10 +233,6 @@ impl fmt::Debug for FnCallExpr { if self.capture_parent_scope { ff.field("capture_parent_scope", &self.capture_parent_scope); } - #[cfg(not(feature = "no_function"))] - if self.can_be_script { - ff.field("can_be_script", &self.can_be_script); - } ff.field("pos", &self.pos); ff.finish() } @@ -691,8 +699,6 @@ impl Expr { args: once(Self::StringConstant(f.fn_name().into(), pos)).collect(), capture_parent_scope: false, operator_token: None, - #[cfg(not(feature = "no_function"))] - can_be_script: true, pos, } .into(), diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 5afd07d9..17c2d82d 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -223,16 +223,9 @@ impl Engine { hashes, args, operator_token, - #[cfg(not(feature = "no_function"))] - can_be_script, .. } = expr; - #[cfg(not(feature = "no_function"))] - let native = !can_be_script; - #[cfg(feature = "no_function")] - let native = true; - // Short-circuit native binary operator call if under Fast Operators mode if operator_token.is_some() && self.fast_operators() && args.len() == 2 { let mut lhs = self @@ -257,8 +250,7 @@ impl Engine { return self .exec_fn_call( - None, global, caches, lib, name, native, *hashes, operands, false, false, pos, - level, + None, global, caches, lib, name, *hashes, operands, false, false, pos, level, ) .map(|(v, ..)| v); } @@ -266,7 +258,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if !expr.namespace.is_empty() { // Qualified function call - let hash = hashes.native; + let hash = hashes.native(); let namespace = &expr.namespace; return self.make_qualified_function_call( @@ -287,7 +279,6 @@ impl Engine { lib, this_ptr, name, - native, first_arg, args, *hashes, diff --git a/src/func/call.rs b/src/func/call.rs index ef5d77e7..d840d7df 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -11,9 +11,9 @@ use crate::engine::{ use crate::eval::{Caches, FnResolutionCacheEntry, GlobalRuntimeState}; use crate::tokenizer::Token; use crate::{ - calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, Engine, FnArgsVec, FnPtr, - ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult, RhaiResultOf, - Scope, ERR, + calc_fn_hash, calc_fn_params_hash, combine_hashes, is_valid_function_name, Dynamic, Engine, + FnArgsVec, FnPtr, ImmutableString, Module, OptimizationLevel, Position, RhaiError, RhaiResult, + RhaiResultOf, Scope, ERR, }; #[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; @@ -570,7 +570,6 @@ impl Engine { caches: &mut Caches, lib: &[&Module], fn_name: &str, - _native_only: bool, hashes: FnCallHashes, args: &mut FnCallArgs, is_ref_mut: bool, @@ -590,55 +589,58 @@ impl Engine { #[cfg(not(feature = "no_closure"))] ensure_no_data_race(fn_name, args, is_ref_mut)?; - // These may be redirected from method style calls. - match fn_name { - // Handle type_of() - KEYWORD_TYPE_OF if args.len() == 1 => { - let typ = self.map_type_name(args[0].type_name()).to_string().into(); - return Ok((typ, false)); - } - - // Handle is_def_fn() - #[cfg(not(feature = "no_function"))] - crate::engine::KEYWORD_IS_DEF_FN - if args.len() == 2 && args[0].is::() && args[1].is::() => - { - let fn_name = args[0].read_lock::().expect("`FnPtr`"); - let num_params = args[1].as_int().expect("`INT`"); - - return Ok(( - if num_params < 0 || num_params > crate::MAX_USIZE_INT { - false - } else { - let hash_script = calc_fn_hash(None, fn_name.as_str(), num_params as usize); - self.has_script_fn(Some(global), caches, lib, hash_script) - } - .into(), - false, - )); - } - - // Handle is_shared() - #[cfg(not(feature = "no_closure"))] - crate::engine::KEYWORD_IS_SHARED if args.len() == 1 => { - return no_method_err(fn_name, pos) - } - - KEYWORD_FN_PTR | KEYWORD_EVAL | KEYWORD_IS_DEF_VAR if args.len() == 1 => { - return no_method_err(fn_name, pos) - } - - KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY if !args.is_empty() => { - return no_method_err(fn_name, pos) - } - - _ => (), - } - let level = level + 1; + // These may be redirected from method style calls. + if hashes.is_native_only() { + match fn_name { + // Handle type_of() + KEYWORD_TYPE_OF if args.len() == 1 => { + let typ = self.map_type_name(args[0].type_name()).to_string().into(); + return Ok((typ, false)); + } + + // Handle is_def_fn() + #[cfg(not(feature = "no_function"))] + crate::engine::KEYWORD_IS_DEF_FN + if args.len() == 2 && args[0].is::() && args[1].is::() => + { + let fn_name = args[0].read_lock::().expect("`FnPtr`"); + let num_params = args[1].as_int().expect("`INT`"); + + return Ok(( + if num_params < 0 || num_params > crate::MAX_USIZE_INT { + false + } else { + let hash_script = + calc_fn_hash(None, fn_name.as_str(), num_params as usize); + self.has_script_fn(Some(global), caches, lib, hash_script) + } + .into(), + false, + )); + } + + // Handle is_shared() + #[cfg(not(feature = "no_closure"))] + crate::engine::KEYWORD_IS_SHARED if args.len() == 1 => { + return no_method_err(fn_name, pos) + } + + KEYWORD_FN_PTR | KEYWORD_EVAL | KEYWORD_IS_DEF_VAR if args.len() == 1 => { + return no_method_err(fn_name, pos) + } + + KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY if !args.is_empty() => { + return no_method_err(fn_name, pos) + } + + _ => (), + } + } + #[cfg(not(feature = "no_function"))] - if !_native_only { + if !hashes.is_native_only() { // Script-defined function call? let local_entry = &mut None; @@ -649,7 +651,7 @@ impl Engine { local_entry, lib, fn_name, - hashes.script, + hashes.script(), None, false, None, @@ -719,7 +721,7 @@ impl Engine { } // Native function call - let hash = hashes.native; + let hash = hashes.native(); self.call_native_fn( global, caches, lib, fn_name, hash, args, is_ref_mut, false, pos, level, ) @@ -808,9 +810,13 @@ impl Engine { let fn_ptr = target.read_lock::().expect("`FnPtr`"); // Redirect function name let fn_name = fn_ptr.fn_name(); - let args_len = call_args.len() + fn_ptr.curry().len(); // Recalculate hashes - let new_hash = calc_fn_hash(None, fn_name, args_len).into(); + let args_len = call_args.len() + fn_ptr.curry().len(); + let new_hash = if !fn_ptr.is_anonymous() && !is_valid_function_name(fn_name) { + FnCallHashes::from_native(calc_fn_hash(None, fn_name, args_len)) + } else { + calc_fn_hash(None, fn_name, args_len).into() + }; // Arguments are passed as-is, adding the curried arguments let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); curry.extend(fn_ptr.curry().iter().cloned()); @@ -825,7 +831,6 @@ impl Engine { caches, lib, fn_name, - false, new_hash, &mut args, false, @@ -845,20 +850,25 @@ impl Engine { // FnPtr call on object let fn_ptr = mem::take(&mut call_args[0]).cast::(); + let is_anon = fn_ptr.is_anonymous(); call_args = &mut call_args[1..]; // Redirect function name - let fn_name = fn_ptr.fn_name(); - let args_len = call_args.len() + fn_ptr.curry().len(); + let (fn_name, fn_curry) = fn_ptr.take_data(); // Recalculate hash - let new_hash = FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, fn_name, args_len), - calc_fn_hash(None, fn_name, args_len + 1), - ); + let args_len = call_args.len() + fn_curry.len(); + let new_hash = if !is_anon && !is_valid_function_name(&fn_name) { + FnCallHashes::from_native(calc_fn_hash(None, &fn_name, args_len + 1)) + } else { + FnCallHashes::from_all( + #[cfg(not(feature = "no_function"))] + calc_fn_hash(None, &fn_name, args_len), + calc_fn_hash(None, &fn_name, args_len + 1), + ) + }; // Replace the first argument with the object pointer, adding the curried arguments - let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); - curry.extend(fn_ptr.curry().iter().cloned()); + let mut curry = FnArgsVec::with_capacity(fn_curry.len()); + curry.extend(fn_curry.into_iter()); let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len() + 1); args.push(target.as_mut()); args.extend(curry.iter_mut()); @@ -870,8 +880,7 @@ impl Engine { global, caches, lib, - fn_name, - false, + &fn_name, new_hash, &mut args, is_ref_mut, @@ -939,11 +948,19 @@ impl Engine { call_args = &mut _arg_values; } // Recalculate the hash based on the new function name and new arguments - hash = FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, fn_name, call_args.len()), - calc_fn_hash(None, fn_name, call_args.len() + 1), - ); + hash = if !fn_ptr.is_anonymous() && !is_valid_function_name(&fn_name) { + FnCallHashes::from_native(calc_fn_hash( + None, + fn_name, + call_args.len() + 1, + )) + } else { + FnCallHashes::from_all( + #[cfg(not(feature = "no_function"))] + calc_fn_hash(None, fn_name, call_args.len()), + calc_fn_hash(None, fn_name, call_args.len() + 1), + ) + }; } } }; @@ -959,7 +976,6 @@ impl Engine { caches, lib, fn_name, - false, hash, &mut args, is_ref_mut, @@ -987,7 +1003,6 @@ impl Engine { lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, fn_name: &str, - native_only: bool, first_arg: Option<&Expr>, args_expr: &[Expr], hashes: FnCallHashes, @@ -996,7 +1011,6 @@ impl Engine { pos: Position, level: usize, ) -> RhaiResult { - let native = native_only; let mut first_arg = first_arg; let mut a_expr = args_expr; let mut total_args = if first_arg.is_some() { 1 } else { 0 } + a_expr.len(); @@ -1020,10 +1034,12 @@ impl Engine { } let fn_ptr = arg_value.cast::(); - curry.extend(fn_ptr.curry().iter().cloned()); + let is_anon = fn_ptr.is_anonymous(); + let (fn_name, fn_curry) = fn_ptr.take_data(); + curry.extend(fn_curry.into_iter()); // Redirect function name - redirected = fn_ptr.take_data().0; + redirected = fn_name; name = &redirected; // Shift the arguments @@ -1035,7 +1051,8 @@ impl Engine { // Recalculate hash let args_len = total_args + curry.len(); - hashes = if hashes.is_native_only() { + + hashes = if !is_anon && !is_valid_function_name(name) { FnCallHashes::from_native(calc_fn_hash(None, name, args_len)) } else { calc_fn_hash(None, name, args_len).into() @@ -1193,8 +1210,8 @@ impl Engine { return self .exec_fn_call( - scope, global, caches, lib, name, native, hashes, &mut args, is_ref_mut, false, - pos, level, + scope, global, caches, lib, name, hashes, &mut args, is_ref_mut, false, pos, + level, ) .map(|(v, ..)| v); } @@ -1256,8 +1273,7 @@ impl Engine { } self.exec_fn_call( - None, global, caches, lib, name, native, hashes, &mut args, is_ref_mut, false, pos, - level, + None, global, caches, lib, name, hashes, &mut args, is_ref_mut, false, pos, level, ) .map(|(v, ..)| v) } diff --git a/src/func/native.rs b/src/func/native.rs index 6afda4da..a8eec976 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -416,7 +416,6 @@ impl<'a> NativeCallContext<'a> { caches, self.lib, fn_name, - false, hash, args, is_ref_mut, diff --git a/src/optimizer.rs b/src/optimizer.rs index 08abb8f2..01717a0a 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -1142,7 +1142,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { return; } // Overloaded operators can override built-in. - _ 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 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.operator_token.as_ref().unwrap(), &arg_values[0], &arg_values[1]) .and_then(|f| { #[cfg(not(feature = "no_function"))] diff --git a/src/parser.rs b/src/parser.rs index c2e02aa7..0eb767dd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -469,7 +469,7 @@ fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position // Variable name (Token::Identifier(s), pos) => Ok((*s, pos)), // Reserved keyword - (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { + (Token::Reserved(s), pos) if is_valid_identifier(s.as_str()) => { Err(PERR::Reserved(s.to_string()).into_err(pos)) } // Bad identifier @@ -486,7 +486,7 @@ fn parse_symbol(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> // Symbol (token, pos) if token.is_standard_symbol() => Ok((token.literal_syntax().into(), pos)), // Reserved symbol - (Token::Reserved(s), pos) if !is_valid_identifier(s.chars()) => Ok((*s, pos)), + (Token::Reserved(s), pos) if !is_valid_identifier(s.as_str()) => Ok((*s, pos)), // Bad symbol (Token::LexError(err), pos) => Err(err.into_err(pos)), // Not a symbol @@ -599,9 +599,7 @@ impl Engine { #[cfg(feature = "no_module")] let hash = calc_fn_hash(None, &id, 0); - let is_valid_function_name = is_valid_function_name(&id); - - let hashes = if is_valid_function_name { + let hashes = if is_valid_function_name(&id) { hash.into() } else { FnCallHashes::from_native(hash) @@ -613,8 +611,6 @@ impl Engine { name: state.get_interned_string(id), capture_parent_scope, operator_token: None, - #[cfg(not(feature = "no_function"))] - can_be_script: is_valid_function_name, #[cfg(not(feature = "no_module"))] namespace, hashes, @@ -671,9 +667,7 @@ impl Engine { #[cfg(feature = "no_module")] let hash = calc_fn_hash(None, &id, args.len()); - let is_valid_function_name = is_valid_function_name(&id); - - let hashes = if is_valid_function_name { + let hashes = if is_valid_function_name(&id) { hash.into() } else { FnCallHashes::from_native(hash) @@ -685,8 +679,6 @@ impl Engine { name: state.get_interned_string(id), capture_parent_scope, operator_token: None, - #[cfg(not(feature = "no_function"))] - can_be_script: is_valid_function_name, #[cfg(not(feature = "no_module"))] namespace, hashes, @@ -1012,7 +1004,7 @@ impl Engine { (Token::InterpolatedString(..), pos) => { return Err(PERR::PropertyExpected.into_err(pos)) } - (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { + (Token::Reserved(s), pos) if is_valid_identifier(s.as_str()) => { return Err(PERR::Reserved(s.to_string()).into_err(pos)); } (Token::LexError(err), pos) => return Err(err.into_err(pos)), @@ -1944,8 +1936,6 @@ impl Engine { pos, operator_token: Some(token), capture_parent_scope: false, - #[cfg(not(feature = "no_function"))] - can_be_script: false, } .into_fn_call_expr(pos)) } @@ -1976,8 +1966,6 @@ impl Engine { pos, operator_token: Some(token), capture_parent_scope: false, - #[cfg(not(feature = "no_function"))] - can_be_script: false, } .into_fn_call_expr(pos)) } @@ -2001,8 +1989,6 @@ impl Engine { pos, operator_token: Some(token), capture_parent_scope: false, - #[cfg(not(feature = "no_function"))] - can_be_script: false, } .into_fn_call_expr(pos)) } @@ -2217,11 +2203,15 @@ impl Engine { // lhs.func(...) (lhs, Expr::FnCall(mut func, func_pos)) => { // Recalculate hash - func.hashes = FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &func.name, func.args.len()), - calc_fn_hash(None, &func.name, func.args.len() + 1), - ); + func.hashes = if is_valid_function_name(&func.name) { + FnCallHashes::from_all( + #[cfg(not(feature = "no_function"))] + calc_fn_hash(None, &func.name, func.args.len()), + calc_fn_hash(None, &func.name, func.args.len() + 1), + ) + } else { + FnCallHashes::from_native(calc_fn_hash(None, &func.name, func.args.len() + 1)) + }; let rhs = Expr::MethodCall(func, func_pos); Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos)) @@ -2263,11 +2253,19 @@ impl Engine { // lhs.func().dot_rhs or lhs.func()[idx_rhs] Expr::FnCall(mut func, func_pos) => { // Recalculate hash - func.hashes = FnCallHashes::from_all( - #[cfg(not(feature = "no_function"))] - calc_fn_hash(None, &func.name, func.args.len()), - calc_fn_hash(None, &func.name, func.args.len() + 1), - ); + func.hashes = if is_valid_function_name(&func.name) { + FnCallHashes::from_all( + #[cfg(not(feature = "no_function"))] + calc_fn_hash(None, &func.name, func.args.len()), + calc_fn_hash(None, &func.name, func.args.len() + 1), + ) + } else { + FnCallHashes::from_native(calc_fn_hash( + None, + &func.name, + func.args.len() + 1, + )) + }; let new_lhs = BinaryExpr { lhs: Expr::MethodCall(func, func_pos), @@ -2322,7 +2320,7 @@ impl Engine { .get(&**c) .copied() .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) => { return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos)) } _ => current_op.precedence(), @@ -2347,7 +2345,7 @@ impl Engine { .get(&**c) .copied() .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) => { return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos)) } _ => next_op.precedence(), @@ -2371,8 +2369,8 @@ impl Engine { let op = op_token.syntax(); let hash = calc_fn_hash(None, &op, 2); - let is_function = is_valid_function_name(&op); - let operator_token = if is_function { + let is_valid_script_function = is_valid_function_name(&op); + let operator_token = if is_valid_script_function { None } else { Some(op_token.clone()) @@ -2387,8 +2385,6 @@ impl Engine { pos, operator_token, capture_parent_scope: false, - #[cfg(not(feature = "no_function"))] - can_be_script: is_function, }; let mut args = StaticVec::new_const(); @@ -2474,7 +2470,7 @@ impl Engine { let pos = args[0].start_position(); FnCallExpr { - hashes: if is_function { + hashes: if is_valid_script_function { hash.into() } else { FnCallHashes::from_native(hash) @@ -3732,8 +3728,6 @@ impl Engine { pos, operator_token: None, capture_parent_scope: false, - #[cfg(not(feature = "no_function"))] - can_be_script: false, } .into_fn_call_expr(pos); diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 6aa0ec43..96a56170 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -2199,7 +2199,7 @@ fn get_identifier( } } - let is_valid_identifier = is_valid_identifier(identifier.chars()); + let is_valid_identifier = is_valid_identifier(&identifier); if let Some(token) = Token::lookup_from_syntax(&identifier) { return (token, start_pos); @@ -2233,10 +2233,10 @@ pub fn is_keyword_function(name: &str) -> bool { /// _(internals)_ Is a text string a valid identifier? /// Exported under the `internals` feature only. #[must_use] -pub fn is_valid_identifier(name: impl Iterator) -> bool { +pub fn is_valid_identifier(name: &str) -> bool { let mut first_alphabetic = false; - for ch in name { + for ch in name.chars() { match ch { '_' => (), _ if is_id_first_alphabetic(ch) => first_alphabetic = true, @@ -2254,7 +2254,7 @@ pub fn is_valid_identifier(name: impl Iterator) -> bool { #[inline(always)] #[must_use] pub fn is_valid_function_name(name: &str) -> bool { - is_valid_identifier(name.chars()) + is_valid_identifier(name) && !is_keyword_function(name) } /// Is a character valid to start an identifier? @@ -2433,7 +2433,7 @@ impl<'a> Iterator for TokenIterator<'a> { (.., true) => unreachable!("no custom operators"), // Reserved keyword that is not custom and disabled. (token, false) if !self.engine.disabled_symbols.is_empty() && self.engine.disabled_symbols.contains(token) => { - let msg = format!("reserved {} '{token}' is disabled", if is_valid_identifier(token.chars()) { "keyword"} else {"symbol"}); + let msg = format!("reserved {} '{token}' is disabled", if is_valid_identifier(token) { "keyword"} else {"symbol"}); Token::LexError(LERR::ImproperSymbol(s.to_string(), msg).into()) }, // Reserved keyword/operator that is not custom. diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 8c5d4b1f..1bdc8652 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -1,10 +1,9 @@ //! The `FnPtr` type. -use crate::tokenizer::is_valid_identifier; use crate::types::dynamic::Variant; use crate::{ - Dynamic, Engine, FuncArgs, ImmutableString, Module, NativeCallContext, Position, RhaiError, - RhaiResult, RhaiResultOf, StaticVec, AST, ERR, + is_valid_function_name, Dynamic, Engine, FuncArgs, ImmutableString, Module, NativeCallContext, + Position, RhaiError, RhaiResult, RhaiResultOf, StaticVec, AST, ERR, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -254,7 +253,7 @@ impl TryFrom for FnPtr { #[inline(always)] fn try_from(value: ImmutableString) -> RhaiResultOf { - if is_valid_identifier(value.chars()) { + if is_valid_function_name(&value) { Ok(Self { name: value, curry: StaticVec::new_const(), diff --git a/src/types/parse_error.rs b/src/types/parse_error.rs index d11a49c6..86fedfdf 100644 --- a/src/types/parse_error.rs +++ b/src/types/parse_error.rs @@ -238,7 +238,7 @@ impl fmt::Display for ParseErrorType { Self::AssignmentToInvalidLHS(s) => f.write_str(s), Self::LiteralTooLarge(typ, max) => write!(f, "{typ} exceeds the maximum limit ({max})"), - Self::Reserved(s) if is_valid_identifier(s.chars()) => write!(f, "'{s}' is a reserved keyword"), + Self::Reserved(s) if is_valid_identifier(s.as_str()) => write!(f, "'{s}' is a reserved keyword"), Self::Reserved(s) => write!(f, "'{s}' is a reserved symbol"), Self::UnexpectedEOF => f.write_str("Script is incomplete"), Self::WrongSwitchIntegerCase => f.write_str("Integer switch case cannot follow a range case"),