From 4e27039521259b05a2671fe3cea9e8b077362db1 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 23 Nov 2022 11:36:30 +0800 Subject: [PATCH] Use bitflags. --- codegen/src/function.rs | 6 +- examples/event_handler_js/main.rs | 2 +- src/api/definitions/mod.rs | 10 +- src/api/json.rs | 4 +- src/api/register.rs | 9 +- src/engine.rs | 3 +- src/eval/stmt.rs | 4 +- src/eval/target.rs | 12 +- src/func/builtin.rs | 28 ++-- src/lib.rs | 10 +- src/module/mod.rs | 114 +++++++------ src/optimizer.rs | 3 +- src/packages/arithmetic.rs | 3 +- src/packages/array_basic.rs | 3 +- src/packages/bit_field.rs | 3 +- src/packages/blob_basic.rs | 3 +- src/packages/debugging.rs | 3 +- src/packages/fn_basic.rs | 3 +- src/packages/iter_basic.rs | 3 +- src/packages/lang_core.rs | 6 +- src/packages/logic.rs | 3 +- src/packages/map_basic.rs | 3 +- src/packages/math_basic.rs | 3 +- src/packages/pkg_core.rs | 3 +- src/packages/pkg_std.rs | 3 +- src/packages/string_basic.rs | 3 +- src/packages/string_more.rs | 3 +- src/packages/time_basic.rs | 3 +- src/parser.rs | 255 +++++++++++++++--------------- src/serde/metadata.rs | 10 +- src/tokenizer.rs | 23 +-- tests/closures.rs | 6 +- tests/custom_syntax.rs | 3 +- 33 files changed, 294 insertions(+), 259 deletions(-) diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 833e3d98..aaa07df5 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -313,7 +313,7 @@ impl Parse for ExportedFn { } } - let skip_slots = if pass_context { 1 } else { 0 }; + let skip_slots = usize::from(pass_context); // Determine whether function generates a special calling convention for a mutable receiver. let mut_receiver = match fn_all.sig.inputs.iter().nth(skip_slots) { @@ -485,12 +485,12 @@ impl ExportedFn { } pub fn arg_list(&self) -> impl Iterator { - let skip = if self.pass_context { 1 } else { 0 }; + let skip = usize::from(self.pass_context); self.signature.inputs.iter().skip(skip) } pub fn arg_count(&self) -> usize { - let skip = if self.pass_context { 1 } else { 0 }; + let skip = usize::from(self.pass_context); self.signature.inputs.len() - skip } diff --git a/examples/event_handler_js/main.rs b/examples/event_handler_js/main.rs index f2aac172..e6998d7a 100644 --- a/examples/event_handler_js/main.rs +++ b/examples/event_handler_js/main.rs @@ -8,7 +8,7 @@ pub fn main() { #[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_object"))] pub fn main() { - use rhai::{CallFnOptions, Dynamic, Engine, ImmutableString, Map, Scope, AST}; + use rhai::{CallFnOptions, Dynamic, Engine, Map, Scope, AST}; use std::io::{stdin, stdout, Write}; const SCRIPT_FILE: &str = "event_handler_js/script.rhai"; diff --git a/src/api/definitions/mod.rs b/src/api/definitions/mod.rs index 3ee43af0..54d9b2d7 100644 --- a/src/api/definitions/mod.rs +++ b/src/api/definitions/mod.rs @@ -2,7 +2,7 @@ #![cfg(feature = "internals")] #![cfg(feature = "metadata")] -use crate::module::FuncInfo; +use crate::module::{FuncInfo, ModuleFlags}; use crate::tokenizer::{is_valid_function_name, Token}; use crate::{Engine, FnAccess, FnPtr, Module, Scope, INT}; @@ -308,10 +308,16 @@ impl Definitions<'_> { String::new() }; + let exclude_flags = if !self.config.include_standard_packages { + ModuleFlags::STANDARD_LIB + } else { + ModuleFlags::empty() + }; + self.engine .global_modules .iter() - .filter(|m| self.config.include_standard_packages || !m.standard) + .filter(|m| !m.flags.contains(exclude_flags)) .enumerate() .for_each(|(i, m)| { if i > 0 { diff --git a/src/api/json.rs b/src/api/json.rs index 4365a4a8..f692e160 100644 --- a/src/api/json.rs +++ b/src/api/json.rs @@ -1,7 +1,7 @@ //! Module that defines JSON manipulation functions for [`Engine`]. #![cfg(not(feature = "no_object"))] -use crate::parser::ParseState; +use crate::parser::{ParseSettingFlags, ParseState}; use crate::tokenizer::Token; use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope}; #[cfg(feature = "no_std")] @@ -122,7 +122,7 @@ impl Engine { let ast = self.parse_global_expr( &mut stream.peekable(), &mut state, - |s| s.allow_unquoted_map_properties = false, + |s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES, #[cfg(not(feature = "no_optimize"))] OptimizationLevel::None, #[cfg(feature = "no_optimize")] diff --git a/src/api/register.rs b/src/api/register.rs index 41a9416d..84d8f4fa 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -1,6 +1,7 @@ //! Module that defines the public function/module registration API of [`Engine`]. use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync}; +use crate::module::ModuleFlags; use crate::types::dynamic::Variant; use crate::{ Engine, FnAccess, FnNamespace, Identifier, Module, NativeCallContext, RhaiResultOf, Shared, @@ -741,11 +742,17 @@ impl Engine { signatures.extend(m.gen_fn_signatures().map(|f| format!("{name}::{f}"))); } + let exclude_flags = if !include_packages { + ModuleFlags::INTERNAL | ModuleFlags::STANDARD_LIB + } else { + ModuleFlags::INTERNAL + }; + signatures.extend( self.global_modules .iter() .skip(1) - .filter(|m| !m.internal && (include_packages || !m.standard)) + .filter(|m| !m.flags.contains(exclude_flags)) .flat_map(|m| m.gen_fn_signatures()), ); diff --git a/src/engine.rs b/src/engine.rs index 8d5df823..f888807b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -5,6 +5,7 @@ use crate::func::native::{ locked_write, OnDebugCallback, OnDefVarCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback, }; +use crate::module::ModuleFlags; use crate::packages::{Package, StandardPackage}; use crate::tokenizer::Token; use crate::types::StringsInterner; @@ -303,7 +304,7 @@ impl Engine { // Add the global namespace module let mut global_namespace = Module::with_capacity(0); - global_namespace.internal = true; + global_namespace.flags |= ModuleFlags::INTERNAL; engine.global_modules.push(global_namespace.into()); engine diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 2aab1455..1b4e7050 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -764,6 +764,8 @@ impl Engine { // Import statement #[cfg(not(feature = "no_module"))] Stmt::Import(x, _pos) => { + use crate::ModuleResolver; + let (expr, export) = &**x; // Guard against too many modules @@ -777,8 +779,6 @@ impl Engine { self.make_type_mismatch_err::(typ, expr.position()) })?; - use crate::ModuleResolver; - let path_pos = expr.start_position(); let resolver = global.embedded_module_resolver.clone(); diff --git a/src/eval/target.rs b/src/eval/target.rs index 45723ab6..199cf8a7 100644 --- a/src/eval/target.rs +++ b/src/eval/target.rs @@ -53,14 +53,12 @@ pub fn calc_index( negative_count_from_end: bool, err_func: impl FnOnce() -> Result, ) -> Result { - if start < 0 { - if negative_count_from_end { - let abs_start = start.unsigned_abs() as usize; + if start < 0 && negative_count_from_end { + let abs_start = start.unsigned_abs() as usize; - // Count from end if negative - if abs_start <= length { - return Ok(length - abs_start); - } + // Count from end if negative + if abs_start <= length { + return Ok(length - abs_start); } } if start <= crate::MAX_USIZE_INT && (start as usize) < length { diff --git a/src/func/builtin.rs b/src/func/builtin.rs index 8f1699e9..a4b00050 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -529,24 +529,20 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option< } // Handle ranges here because ranges are implemented as custom type - if type1 == TypeId::of::() { - if type1 == type2 { - return match op { - EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)), - NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)), - _ => None, - }; - } + if type1 == TypeId::of::() && type1 == type2 { + return match op { + EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)), + NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)), + _ => None, + }; } - if type1 == TypeId::of::() { - if type1 == type2 { - return match op { - EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)), - NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)), - _ => None, - }; - } + if type1 == TypeId::of::() && type1 == type2 { + return match op { + EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)), + NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)), + _ => None, + }; } // One of the operands is a custom type, so it is never built-in diff --git a/src/lib.rs b/src/lib.rs index 96bee4eb..2ddb652a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,11 +58,11 @@ #![cfg_attr(feature = "no_std", no_std)] #![deny(missing_docs)] -// #![warn(clippy::all)] -// #![warn(clippy::pedantic)] -// #![warn(clippy::nursery)] -// #![warn(clippy::cargo)] -// #![warn(clippy::undocumented_unsafe_blocks)] +#![warn(clippy::all)] +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![warn(clippy::cargo)] +#![warn(clippy::undocumented_unsafe_blocks)] #![allow(clippy::unit_arg)] #![allow(clippy::missing_errors_doc)] #![allow(clippy::used_underscore_binding)] diff --git a/src/module/mod.rs b/src/module/mod.rs index 91be1a53..e02a77db 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -5,13 +5,14 @@ use crate::api::type_names::format_type; use crate::ast::FnAccess; use crate::func::{ shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn, RegisterNativeFunction, - SendSync, + SendSync, StraightHashMap, }; use crate::types::{dynamic::Variant, BloomFilterU64, CustomTypesCollection}; use crate::{ calc_fn_hash, calc_fn_hash_full, Dynamic, Identifier, ImmutableString, NativeCallContext, RhaiResultOf, Shared, SharedModule, SmartString, StaticVec, }; +use bitflags::bitflags; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -24,8 +25,6 @@ use std::{ #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] use crate::func::register::Mut; -use crate::func::StraightHashMap; - /// A type representing the namespace of a function. #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[cfg_attr(feature = "metadata", derive(serde::Serialize))] @@ -94,44 +93,44 @@ impl FuncInfo { #[cfg(feature = "metadata")] #[must_use] pub fn gen_signature(&self) -> String { - let mut sig = format!("{}(", self.name); + let mut signature = format!("{}(", self.name); let return_type = format_type(&self.return_type, true); if self.params_info.is_empty() { for x in 0..self.num_params { - sig.push('_'); + signature.push('_'); if x < self.num_params - 1 { - sig.push_str(", "); + signature.push_str(", "); } } } else { let params: StaticVec<_> = self .params_info .iter() - .map(|s| { - let mut seg = s.splitn(2, ':'); - let name = match seg.next().unwrap().trim() { + .map(|param| { + let mut segment = param.splitn(2, ':'); + let name = match segment.next().unwrap().trim() { "" => "_", s => s, }; - let result: std::borrow::Cow = match seg.next() { + let result: std::borrow::Cow = match segment.next() { Some(typ) => format!("{name}: {}", format_type(typ, false)).into(), None => name.into(), }; result }) .collect(); - sig.push_str(¶ms.join(", ")); + signature.push_str(¶ms.join(", ")); } - sig.push(')'); + signature.push(')'); if !self.func.is_script() && !return_type.is_empty() { - sig.push_str(" -> "); - sig.push_str(&return_type); + signature.push_str(" -> "); + signature.push_str(&return_type); } - sig + signature } } @@ -156,6 +155,20 @@ pub fn calc_native_fn_hash<'a>( ) } +bitflags! { + /// Bit-flags containing all status for [`Module`]. + pub struct ModuleFlags: u8 { + /// Is the [`Module`] internal? + const INTERNAL = 0b0000_0001; + /// Is the [`Module`] part of a standard library? + const STANDARD_LIB = 0b0000_0010; + /// Is the [`Module`] indexed? + const INDEXED = 0b0000_0100; + /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? + const INDEXED_GLOBAL_FUNCTIONS = 0b0000_1000; + } +} + /// A module which may contain variables, sub-modules, external Rust functions, /// and/or script-defined functions. #[derive(Clone)] @@ -165,10 +178,6 @@ pub struct Module { /// Module documentation. #[cfg(feature = "metadata")] doc: crate::SmartString, - /// Is this module internal? - pub(crate) internal: bool, - /// Is this module part of a standard library? - pub(crate) standard: bool, /// Custom types. custom_types: Option, /// Sub-modules. @@ -188,10 +197,8 @@ pub struct Module { type_iterators: Option>>, /// Flattened collection of iterator functions, including those in sub-modules. all_type_iterators: Option>>, - /// Is the [`Module`] indexed? - indexed: bool, - /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? - contains_indexed_global_functions: bool, + /// Flags. + pub(crate) flags: ModuleFlags, } impl Default for Module { @@ -295,8 +302,6 @@ impl Module { id: None, #[cfg(feature = "metadata")] doc: crate::SmartString::new_const(), - internal: false, - standard: false, custom_types: None, modules: None, variables: None, @@ -306,8 +311,7 @@ impl Module { dynamic_functions_filter: BloomFilterU64::new(), type_iterators: None, all_type_iterators: None, - indexed: true, - contains_indexed_global_functions: false, + flags: ModuleFlags::empty(), } } @@ -437,11 +441,8 @@ impl Module { /// Clear the [`Module`]. #[inline(always)] pub fn clear(&mut self) { - self.id = None; #[cfg(feature = "metadata")] self.doc.clear(); - self.internal = false; - self.standard = false; self.custom_types = None; self.modules = None; self.variables = None; @@ -451,8 +452,7 @@ impl Module { self.dynamic_functions_filter.clear(); self.type_iterators = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; } /// Map a custom type to a friendly display name. @@ -543,7 +543,7 @@ impl Module { #[inline] #[must_use] pub fn is_empty(&self) -> bool { - !self.contains_indexed_global_functions + !self.flags.contains(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS) && self.functions.is_empty() && self.variables.as_ref().map_or(true, |m| m.is_empty()) && self.modules.as_ref().map_or(true, |m| m.is_empty()) @@ -579,7 +579,7 @@ impl Module { #[inline(always)] #[must_use] pub const fn is_indexed(&self) -> bool { - self.indexed + self.flags.contains(ModuleFlags::INDEXED) } /// _(metadata)_ Generate signatures for all the non-private functions in the [`Module`]. @@ -666,7 +666,7 @@ impl Module { let ident = name.into(); let value = Dynamic::from(value); - if self.indexed { + if self.is_indexed() { let hash_var = crate::calc_var_hash(Some(""), &ident); self.all_variables .get_or_insert_with(|| Default::default()) @@ -717,8 +717,7 @@ impl Module { func: fn_def.into(), }, ); - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; hash_script } @@ -759,8 +758,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; self.modules.get_or_insert_with(|| Default::default()) } @@ -826,8 +824,7 @@ impl Module { self.modules .get_or_insert_with(|| Default::default()) .insert(name.into(), sub_module.into()); - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; self } @@ -942,8 +939,7 @@ impl Module { pub fn update_fn_namespace(&mut self, hash_fn: u64, namespace: FnNamespace) -> &mut Self { if let Some(f) = self.functions.get_mut(&hash_fn) { f.namespace = namespace; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; } self } @@ -1051,8 +1047,7 @@ impl Module { }, ); - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; hash_fn } @@ -1607,8 +1602,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; #[cfg(feature = "metadata")] if !other.doc.is_empty() { @@ -1650,8 +1644,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; #[cfg(feature = "metadata")] if !other.doc.is_empty() { @@ -1702,8 +1695,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; #[cfg(feature = "metadata")] if !other.doc.is_empty() { @@ -1775,8 +1767,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; #[cfg(feature = "metadata")] if !other.doc.is_empty() { @@ -1811,8 +1802,7 @@ impl Module { self.all_functions = None; self.all_variables = None; self.all_type_iterators = None; - self.indexed = false; - self.contains_indexed_global_functions = false; + self.flags &= !ModuleFlags::INDEXED & !ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; self } @@ -2108,7 +2098,7 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_indexed_global_functions(&self) -> bool { - self.contains_indexed_global_functions + self.flags.contains(ModuleFlags::INDEXED_GLOBAL_FUNCTIONS) } /// Scan through all the sub-modules in the [`Module`] and build a hash index of all @@ -2181,7 +2171,7 @@ impl Module { contains_indexed_global_functions } - if !self.indexed { + if !self.is_indexed() { let mut path = Vec::with_capacity(4); let mut variables = StraightHashMap::default(); let mut functions = StraightHashMap::default(); @@ -2189,7 +2179,7 @@ impl Module { path.push(""); - self.contains_indexed_global_functions = index_module( + let r = index_module( self, &mut path, &mut variables, @@ -2197,6 +2187,10 @@ impl Module { &mut type_iterators, ); + if r { + self.flags |= ModuleFlags::INDEXED_GLOBAL_FUNCTIONS; + } + self.all_variables = if variables.is_empty() { None } else { @@ -2213,7 +2207,7 @@ impl Module { Some(type_iterators) }; - self.indexed = true; + self.flags |= ModuleFlags::INDEXED; } self @@ -2257,7 +2251,7 @@ impl Module { func: impl Fn(Dynamic) -> Box>> + SendSync + 'static, ) -> &mut Self { let func = Shared::new(func); - if self.indexed { + if self.is_indexed() { self.all_type_iterators .get_or_insert_with(|| Default::default()) .insert(type_id, func.clone()); diff --git a/src/optimizer.rs b/src/optimizer.rs index 39ae36c0..63b519f8 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -8,6 +8,7 @@ use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, use crate::eval::{Caches, GlobalRuntimeState}; use crate::func::builtin::get_builtin_binary_op_fn; use crate::func::hashing::get_hasher; +use crate::module::ModuleFlags; use crate::tokenizer::Token; use crate::types::dynamic::AccessMode; use crate::{ @@ -168,7 +169,7 @@ fn has_native_fn_override( if engine .global_modules .iter() - .filter(|m| !m.standard) + .filter(|m| !m.flags.contains(ModuleFlags::STANDARD_LIB)) .any(|m| m.contains_fn(hash)) { return true; diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index 3dafc1ae..49fd6c1b 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -1,5 +1,6 @@ #![allow(non_snake_case)] +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, Position, RhaiError, RhaiResultOf, ERR, INT}; #[cfg(feature = "no_std")] @@ -192,7 +193,7 @@ macro_rules! reg_functions { def_package! { /// Basic arithmetic package. pub ArithmeticPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "int", int_functions); reg_functions!(lib += signed_basic; INT); diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 01b51e27..527b1001 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -2,6 +2,7 @@ use crate::engine::OP_EQUALS; use crate::eval::{calc_index, calc_offset_len}; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext, @@ -14,7 +15,7 @@ use std::{any::TypeId, cmp::Ordering, mem}; def_package! { /// Package of basic array utilities. pub BasicArrayPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "array", array_functions); diff --git a/src/packages/bit_field.rs b/src/packages/bit_field.rs index 5deb09ce..5ecde54d 100644 --- a/src/packages/bit_field.rs +++ b/src/packages/bit_field.rs @@ -1,4 +1,5 @@ use crate::eval::calc_index; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ def_package, ExclusiveRange, InclusiveRange, Position, RhaiResultOf, ERR, INT, INT_BITS, @@ -10,7 +11,7 @@ use std::prelude::v1::*; def_package! { /// Package of basic bit-field utilities. pub BitFieldPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "bit_field", bit_field_functions); } diff --git a/src/packages/blob_basic.rs b/src/packages/blob_basic.rs index 2e51b108..18e970b9 100644 --- a/src/packages/blob_basic.rs +++ b/src/packages/blob_basic.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "no_index"))] use crate::eval::{calc_index, calc_offset_len}; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position, @@ -16,7 +17,7 @@ use crate::{FLOAT, FLOAT_BYTES}; def_package! { /// Package of basic BLOB utilities. pub BasicBlobPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "blob", blob_functions); combine_with_exported_module!(lib, "parse_int", parse_int_functions); diff --git a/src/packages/debugging.rs b/src/packages/debugging.rs index 4e3cbc35..aaf01d01 100644 --- a/src/packages/debugging.rs +++ b/src/packages/debugging.rs @@ -1,6 +1,7 @@ #![cfg(feature = "debugging")] use crate::def_package; +use crate::module::ModuleFlags; use crate::plugin::*; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -17,7 +18,7 @@ use crate::Map; def_package! { /// Package of basic debugging utilities. pub DebuggingPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "debugging", debugging_functions); } diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index 130646c3..5e2bfcb4 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -1,3 +1,4 @@ +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, FnPtr, ImmutableString, NativeCallContext}; #[cfg(feature = "no_std")] @@ -6,7 +7,7 @@ use std::prelude::v1::*; def_package! { /// Package of basic function pointer utilities. pub BasicFnPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "FnPtr", fn_ptr_functions); } diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index f7985004..a611d0d1 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -1,4 +1,5 @@ use crate::eval::calc_index; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS, MAX_USIZE_INT, @@ -329,7 +330,7 @@ macro_rules! reg_range { def_package! { /// Package of basic range iterators pub BasicIteratorPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; reg_range!(lib | "range" => INT); diff --git a/src/packages/lang_core.rs b/src/packages/lang_core.rs index 1096416a..6f53a98d 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -1,4 +1,5 @@ use crate::def_package; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::types::dynamic::Tag; use crate::{Dynamic, RhaiResultOf, ERR, INT}; @@ -8,7 +9,7 @@ use std::prelude::v1::*; def_package! { /// Package of core language features. pub LanguageCorePackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "core", core_functions); @@ -277,7 +278,8 @@ fn collect_fn_metadata( &mut ns, "{namespace}{}{name}", crate::tokenizer::Token::DoubleColon.literal_syntax() - ); + ) + .unwrap(); scan_module(dict, list, &ns, &**m, filter); } } diff --git a/src/packages/logic.rs b/src/packages/logic.rs index af494f00..adc55b18 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -1,4 +1,5 @@ use crate::def_package; +use crate::module::ModuleFlags; use crate::plugin::*; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -38,7 +39,7 @@ macro_rules! reg_functions { def_package! { /// Package of basic logic operators. pub LogicPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index e5174c1b..8851efb5 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "no_object"))] use crate::engine::OP_EQUALS; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, Dynamic, ImmutableString, Map, NativeCallContext, RhaiResultOf, INT}; #[cfg(feature = "no_std")] @@ -12,7 +13,7 @@ use crate::Array; def_package! { /// Package of basic object map utilities. pub BasicMapPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "map", map_functions); } diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index f7c3c40f..1aed8578 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -1,5 +1,6 @@ #![allow(non_snake_case)] +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, Position, RhaiResultOf, ERR, INT}; #[cfg(feature = "no_std")] @@ -54,7 +55,7 @@ macro_rules! reg_functions { def_package! { /// Basic mathematical package. pub BasicMathPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; // Integer functions combine_with_exported_module!(lib, "int", int_functions); diff --git a/src/packages/pkg_core.rs b/src/packages/pkg_core.rs index 547274cd..0bd2cb19 100644 --- a/src/packages/pkg_core.rs +++ b/src/packages/pkg_core.rs @@ -3,6 +3,7 @@ use std::prelude::v1::*; use super::*; use crate::def_package; +use crate::module::ModuleFlags; def_package! { /// Core package containing basic facilities. @@ -23,6 +24,6 @@ def_package! { BasicFnPackage, #[cfg(feature = "debugging")] DebuggingPackage { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; } } diff --git a/src/packages/pkg_std.rs b/src/packages/pkg_std.rs index b054b3ae..b52b0589 100644 --- a/src/packages/pkg_std.rs +++ b/src/packages/pkg_std.rs @@ -3,6 +3,7 @@ use std::prelude::v1::*; use super::*; use crate::def_package; +use crate::module::ModuleFlags; def_package! { /// Standard package containing all built-in features. @@ -29,6 +30,6 @@ def_package! { #[cfg(not(feature = "no_time"))] BasicTimePackage, MoreStringPackage { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; } } diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index f7450e2a..266a485c 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -1,3 +1,4 @@ +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, FnPtr, SmartString, INT}; use std::any::TypeId; @@ -17,7 +18,7 @@ pub const FUNC_TO_DEBUG: &str = "to_debug"; def_package! { /// Package of basic string utilities (e.g. printing) pub BasicStringPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "print_debug", print_debug_functions); combine_with_exported_module!(lib, "number_formatting", number_formatting); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 79f744ac..843b0b4b 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,3 +1,4 @@ +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{ def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT, @@ -12,7 +13,7 @@ use super::string_basic::{print_with_func, FUNC_TO_STRING}; def_package! { /// Package of additional string utilities over [`BasicStringPackage`][super::BasicStringPackage] pub MoreStringPackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; combine_with_exported_module!(lib, "string", string_functions); } diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index 59e198b8..2ea495c2 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "no_time"))] use super::arithmetic::make_err as make_arithmetic_err; +use crate::module::ModuleFlags; use crate::plugin::*; use crate::{def_package, Dynamic, RhaiResult, RhaiResultOf, INT}; @@ -16,7 +17,7 @@ use instant::{Duration, Instant}; def_package! { /// Package of basic timing utilities. pub BasicTimePackage(lib) { - lib.standard = true; + lib.flags |= ModuleFlags::STANDARD_LIB; // Register date/time functions combine_with_exported_module!(lib, "time", time_functions); diff --git a/src/parser.rs b/src/parser.rs index ae5e6837..a789b492 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -21,6 +21,7 @@ use crate::{ ImmutableString, InclusiveRange, LexError, OptimizationLevel, ParseError, Position, Scope, Shared, SmartString, StaticVec, AST, INT, PERR, }; +use bitflags::bitflags; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -280,24 +281,32 @@ impl<'e> ParseState<'e> { } } +bitflags! { + /// Bit-flags containing all status for [`ParseSettings`]. + pub struct ParseSettingFlags: u8 { + /// Is the construct being parsed located at global level? + const GLOBAL_LEVEL = 0b0000_0001; + /// Is the construct being parsed located inside a function definition? + #[cfg(not(feature = "no_function"))] + const FN_SCOPE = 0b0000_0010; + /// Is the construct being parsed located inside a closure definition? + #[cfg(not(feature = "no_function"))] + #[cfg(not(feature = "no_closure"))] + const CLOSURE_SCOPE = 0b0000_0100; + /// Is the construct being parsed located inside a breakable loop? + const BREAKABLE = 0b0000_1000; + /// Disallow statements in blocks? + const DISALLOW_STATEMENTS_IN_BLOCKS = 0b0001_0000; + /// Disallow unquoted map properties? + const DISALLOW_UNQUOTED_MAP_PROPERTIES = 0b0010_0000; + } +} + /// A type that encapsulates all the settings for a particular parsing function. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub(crate) struct ParseSettings { - /// Is the construct being parsed located at global level? - pub at_global_level: bool, - /// Is the construct being parsed located inside a function definition? - #[cfg(not(feature = "no_function"))] - pub in_fn_scope: bool, - /// Is the construct being parsed located inside a closure definition? - #[cfg(not(feature = "no_function"))] - #[cfg(not(feature = "no_closure"))] - pub in_closure: bool, - /// Is the construct being parsed located inside a breakable loop? - pub is_breakable: bool, - /// Allow statements in blocks? - pub allow_statements: bool, - /// Allow unquoted map properties? - pub allow_unquoted_map_properties: bool, +pub struct ParseSettings { + /// Flags. + pub flags: ParseSettingFlags, /// Language options in effect (overrides Engine options). pub options: LangOptions, /// Current expression nesting level. @@ -307,6 +316,18 @@ pub(crate) struct ParseSettings { } impl ParseSettings { + /// Is a particular flag on? + #[inline(always)] + #[must_use] + pub const fn has_flag(&self, flag: ParseSettingFlags) -> bool { + self.flags.contains(flag) + } + /// Is a particular language option on? + #[inline(always)] + #[must_use] + pub const fn has_option(&self, option: LangOptions) -> bool { + self.options.contains(option) + } /// Create a new `ParseSettings` with one higher expression level. #[inline] #[must_use] @@ -585,7 +606,7 @@ impl Engine { #[cfg(any(feature = "no_function", feature = "no_module"))] let is_global = false; - if settings.options.contains(LangOptions::STRICT_VAR) + if settings.has_option(LangOptions::STRICT_VAR) && index.is_none() && !is_global && !state.global_imports.iter().any(|m| m.as_str() == root) @@ -653,7 +674,7 @@ impl Engine { #[cfg(any(feature = "no_function", feature = "no_module"))] let is_global = false; - if settings.options.contains(LangOptions::STRICT_VAR) + if settings.has_option(LangOptions::STRICT_VAR) && index.is_none() && !is_global && !state.global_imports.iter().any(|m| m.as_str() == root) @@ -995,7 +1016,9 @@ impl Engine { } let (name, pos) = match input.next().expect(NEVER_ENDS) { - (Token::Identifier(..), pos) if !settings.allow_unquoted_map_properties => { + (Token::Identifier(..), pos) + if settings.has_flag(ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES) => + { return Err(PERR::PropertyExpected.into_err(pos)) } (Token::Identifier(s) | Token::StringConstant(s), pos) => { @@ -1196,18 +1219,19 @@ impl Engine { } }; - let (action_expr, need_comma) = if settings.allow_statements { - let stmt = self.parse_stmt(input, state, lib, settings.level_up())?; - let need_comma = !stmt.is_self_terminated(); + let (action_expr, need_comma) = + if !settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) { + let stmt = self.parse_stmt(input, state, lib, settings.level_up())?; + let need_comma = !stmt.is_self_terminated(); - let stmt_block: StmtBlock = stmt.into(); - (Expr::Stmt(stmt_block.into()), need_comma) - } else { - ( - self.parse_expr(input, state, lib, settings.level_up())?, - true, - ) - }; + let stmt_block: StmtBlock = stmt.into(); + (Expr::Stmt(stmt_block.into()), need_comma) + } else { + ( + self.parse_expr(input, state, lib, settings.level_up())?, + true, + ) + }; let has_condition = !matches!(condition, Expr::BoolConstant(true, ..)); expressions.push((condition, action_expr).into()); @@ -1358,7 +1382,7 @@ impl Engine { } // { - block statement as expression - Token::LeftBrace if settings.options.contains(LangOptions::STMT_EXPR) => { + Token::LeftBrace if settings.has_option(LangOptions::STMT_EXPR) => { match self.parse_block(input, state, lib, settings.level_up())? { block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())), stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt), @@ -1369,38 +1393,34 @@ impl Engine { Token::LeftParen => self.parse_paren_expr(input, state, lib, settings.level_up())?, // If statement is allowed to act as expressions - Token::If if settings.options.contains(LangOptions::IF_EXPR) => Expr::Stmt(Box::new( + Token::If if settings.has_option(LangOptions::IF_EXPR) => Expr::Stmt(Box::new( self.parse_if(input, state, lib, settings.level_up())? .into(), )), // Loops are allowed to act as expressions - Token::While | Token::Loop if settings.options.contains(LangOptions::LOOP_EXPR) => { + Token::While | Token::Loop if settings.has_option(LangOptions::LOOP_EXPR) => { Expr::Stmt(Box::new( self.parse_while_loop(input, state, lib, settings.level_up())? .into(), )) } - Token::Do if settings.options.contains(LangOptions::LOOP_EXPR) => Expr::Stmt(Box::new( + Token::Do if settings.has_option(LangOptions::LOOP_EXPR) => Expr::Stmt(Box::new( self.parse_do(input, state, lib, settings.level_up())? .into(), )), - Token::For if settings.options.contains(LangOptions::LOOP_EXPR) => { - Expr::Stmt(Box::new( - self.parse_for(input, state, lib, settings.level_up())? - .into(), - )) - } + Token::For if settings.has_option(LangOptions::LOOP_EXPR) => Expr::Stmt(Box::new( + self.parse_for(input, state, lib, settings.level_up())? + .into(), + )), // Switch statement is allowed to act as expressions - Token::Switch if settings.options.contains(LangOptions::SWITCH_EXPR) => { - Expr::Stmt(Box::new( - self.parse_switch(input, state, lib, settings.level_up())? - .into(), - )) - } + Token::Switch if settings.has_option(LangOptions::SWITCH_EXPR) => Expr::Stmt(Box::new( + self.parse_switch(input, state, lib, settings.level_up())? + .into(), + )), // | ... #[cfg(not(feature = "no_function"))] - Token::Pipe | Token::Or if settings.options.contains(LangOptions::ANON_FN) => { + Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => { // Build new parse state let interned_strings = std::mem::take(&mut state.interned_strings); @@ -1429,24 +1449,24 @@ impl Engine { new_state.max_expr_depth = self.max_function_expr_depth(); } - let mut options = self.options; - options.set( - LangOptions::STRICT_VAR, - if cfg!(feature = "no_closure") { - settings.options.contains(LangOptions::STRICT_VAR) - } else { - // A capturing closure can access variables not defined locally - false - }, - ); + #[cfg(not(feature = "no_closure"))] + let options = self.options & !LangOptions::STRICT_VAR; // A capturing closure can access variables not defined locally + #[cfg(feature = "no_closure")] + let options = self.options | (settings.options & LangOptions::STRICT_VAR); + + let mut flags = (settings.flags + & !ParseSettingFlags::GLOBAL_LEVEL + & ParseSettingFlags::BREAKABLE) + | ParseSettingFlags::FN_SCOPE; + + #[cfg(not(feature = "no_closure"))] + { + flags |= ParseSettingFlags::CLOSURE_SCOPE; + } let new_settings = ParseSettings { - at_global_level: false, - in_fn_scope: true, - #[cfg(not(feature = "no_closure"))] - in_closure: true, - is_breakable: false, level: 0, + flags, options, ..settings }; @@ -1465,8 +1485,8 @@ impl Engine { if !is_func && index.is_none() - && !settings.in_closure - && settings.options.contains(LangOptions::STRICT_VAR) + && !settings.has_flag(ParseSettingFlags::CLOSURE_SCOPE) + && settings.has_option(LangOptions::STRICT_VAR) && !state.scope.contains(name) { // If the parent scope is not inside another capturing closure @@ -1612,7 +1632,7 @@ impl Engine { if !is_property && !is_func && index.is_none() - && settings.options.contains(LangOptions::STRICT_VAR) + && settings.has_option(LangOptions::STRICT_VAR) && !state.scope.contains(&s) { return Err( @@ -1656,11 +1676,13 @@ impl Engine { } // Access to `this` as a variable is OK within a function scope #[cfg(not(feature = "no_function"))] - _ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable( - (None, ns, 0, state.get_interned_string(*s)).into(), - None, - settings.pos, - ), + _ if &*s == KEYWORD_THIS && settings.has_flag(ParseSettingFlags::FN_SCOPE) => { + Expr::Variable( + (None, ns, 0, state.get_interned_string(*s)).into(), + None, + settings.pos, + ) + } // Cannot access to `this` as a variable not in a function scope _ if &*s == KEYWORD_THIS => { let msg = format!("'{s}' can only be used in functions"); @@ -1852,7 +1874,7 @@ impl Engine { #[cfg(any(feature = "no_function", feature = "no_module"))] let is_global = false; - if settings.options.contains(LangOptions::STRICT_VAR) + if settings.has_option(LangOptions::STRICT_VAR) && index.is_none() && !is_global && !state.global_imports.iter().any(|m| m.as_str() == root) @@ -2399,12 +2421,12 @@ impl Engine { Token::Or => { let rhs = op_base.args.pop().unwrap().ensure_bool_expr()?; let lhs = op_base.args.pop().unwrap().ensure_bool_expr()?; - Expr::Or(BinaryExpr { lhs: lhs, rhs: rhs }.into(), pos) + Expr::Or(BinaryExpr { lhs, rhs }.into(), pos) } Token::And => { let rhs = op_base.args.pop().unwrap().ensure_bool_expr()?; let lhs = op_base.args.pop().unwrap().ensure_bool_expr()?; - Expr::And(BinaryExpr { lhs: lhs, rhs: rhs }.into(), pos) + Expr::And(BinaryExpr { lhs, rhs }.into(), pos) } Token::DoubleQuestion => { let rhs = op_base.args.pop().unwrap(); @@ -2590,9 +2612,7 @@ impl Engine { }, s => match input.next().expect(NEVER_ENDS) { (Token::LexError(err), pos) => return Err(err.into_err(pos)), - (Token::Identifier(t), ..) - | (Token::Reserved(t), ..) - | (Token::Custom(t), ..) + (Token::Identifier(t) | Token::Reserved(t) | Token::Custom(t), ..) if *t == s => { segments.push(required_token.clone()); @@ -2726,7 +2746,7 @@ impl Engine { token => unreachable!("Token::While or Token::Loop expected but gets {:?}", token), }; settings.pos = token_pos; - settings.is_breakable = true; + settings.flags |= ParseSettingFlags::BREAKABLE; let body = self.parse_block(input, state, lib, settings.level_up())?; @@ -2749,7 +2769,7 @@ impl Engine { settings.pos = eat_token(input, Token::Do); // do { body } [while|until] guard - settings.is_breakable = true; + settings.flags |= ParseSettingFlags::BREAKABLE; let body = self.parse_block(input, state, lib, settings.level_up())?; let negated = match input.next().expect(NEVER_ENDS) { @@ -2763,7 +2783,7 @@ impl Engine { } }; - settings.is_breakable = false; + settings.flags &= !ParseSettingFlags::BREAKABLE; ensure_not_statement_expr(input, "a boolean")?; let guard = self @@ -2859,7 +2879,7 @@ impl Engine { pos: name_pos, }; - settings.is_breakable = true; + settings.flags |= ParseSettingFlags::BREAKABLE; let body = self.parse_block(input, state, lib, settings.level_up())?; state.stack.rewind(prev_stack_len); @@ -3089,7 +3109,7 @@ impl Engine { let mut statements = StaticVec::new_const(); - if !settings.allow_statements { + if settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) { let stmt = self.parse_expr_stmt(input, state, lib, settings.level_up())?; statements.push(stmt); @@ -3126,7 +3146,7 @@ impl Engine { } // Parse statements inside the block - settings.at_global_level = false; + settings.flags &= !ParseSettingFlags::GLOBAL_LEVEL; let stmt = self.parse_stmt(input, state, lib, settings.level_up())?; @@ -3222,7 +3242,7 @@ impl Engine { unreachable!("doc-comment expected but gets {:?}", comment); } - if !settings.at_global_level { + if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) { return Err(PERR::WrongDocComment.into_err(comments_pos)); } @@ -3264,7 +3284,7 @@ impl Engine { // fn ... #[cfg(not(feature = "no_function"))] - Token::Fn if !settings.at_global_level => { + Token::Fn if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => { Err(PERR::WrongFnDefinition.into_err(token_pos)) } @@ -3307,20 +3327,14 @@ impl Engine { new_state.max_expr_depth = self.max_function_expr_depth(); } - let mut options = self.options; - options.set( - LangOptions::STRICT_VAR, - settings.options.contains(LangOptions::STRICT_VAR), - ); + let options = self.options | (settings.options & LangOptions::STRICT_VAR); + + let flags = ParseSettingFlags::FN_SCOPE + | (settings.flags + & ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES); let new_settings = ParseSettings { - at_global_level: false, - in_fn_scope: true, - #[cfg(not(feature = "no_closure"))] - in_closure: false, - is_breakable: false, - allow_statements: true, - allow_unquoted_map_properties: settings.allow_unquoted_map_properties, + flags, level: 0, options, pos, @@ -3377,11 +3391,15 @@ impl Engine { self.parse_for(input, state, lib, settings.level_up()) } - Token::Continue if self.allow_looping() && settings.is_breakable => { + Token::Continue + if self.allow_looping() && settings.has_flag(ParseSettingFlags::BREAKABLE) => + { let pos = eat_token(input, Token::Continue); Ok(Stmt::BreakLoop(None, ASTFlags::NONE, pos)) } - Token::Break if self.allow_looping() && settings.is_breakable => { + Token::Break + if self.allow_looping() && settings.has_flag(ParseSettingFlags::BREAKABLE) => + { let pos = eat_token(input, Token::Break); let expr = match input.peek().expect(NEVER_ENDS) { @@ -3424,7 +3442,9 @@ impl Engine { // `return`/`throw` at (Token::EOF, ..) => Ok(Stmt::Return(None, return_type, token_pos)), // `return`/`throw` at end of block - (Token::RightBrace, ..) if !settings.at_global_level => { + (Token::RightBrace, ..) + if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => + { Ok(Stmt::Return(None, return_type, token_pos)) } // `return;` or `throw;` @@ -3446,7 +3466,7 @@ impl Engine { Token::Import => self.parse_import(input, state, lib, settings.level_up()), #[cfg(not(feature = "no_module"))] - Token::Export if !settings.at_global_level => { + Token::Export if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => { Err(PERR::WrongExport.into_err(token_pos)) } @@ -3607,7 +3627,7 @@ impl Engine { // Parse function body let body = match input.peek().expect(NEVER_ENDS) { (Token::LeftBrace, ..) => { - settings.is_breakable = false; + settings.flags &= !ParseSettingFlags::BREAKABLE; self.parse_block(input, state, lib, settings.level_up())? } (.., pos) => return Err(PERR::FnMissingBody(name.into()).into_err(*pos)), @@ -3759,7 +3779,7 @@ impl Engine { } // Parse function body - settings.is_breakable = false; + settings.flags &= !ParseSettingFlags::BREAKABLE; let body = self.parse_stmt(input, state, lib, settings.level_up())?; // External variables may need to be processed in a consistent order, @@ -3822,22 +3842,16 @@ impl Engine { ) -> ParseResult { let mut functions = StraightHashMap::default(); - let mut options = self.options; - options.remove(LangOptions::STMT_EXPR | LangOptions::LOOP_EXPR); + let mut options = self.options & !LangOptions::STMT_EXPR & !LangOptions::LOOP_EXPR; #[cfg(not(feature = "no_function"))] - options.remove(LangOptions::ANON_FN); + { + options &= !LangOptions::ANON_FN; + } let mut settings = ParseSettings { - at_global_level: true, - #[cfg(not(feature = "no_function"))] - in_fn_scope: false, - #[cfg(not(feature = "no_function"))] - #[cfg(not(feature = "no_closure"))] - in_closure: false, - is_breakable: false, - allow_statements: false, - allow_unquoted_map_properties: true, level: 0, + flags: ParseSettingFlags::GLOBAL_LEVEL + | ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS, options, pos: Position::START, }; @@ -3883,18 +3897,11 @@ impl Engine { ) -> ParseResult<(StmtBlockContainer, StaticVec>)> { let mut statements = StmtBlockContainer::new_const(); let mut functions = StraightHashMap::default(); + let mut settings = ParseSettings { - at_global_level: true, - #[cfg(not(feature = "no_function"))] - in_fn_scope: false, - #[cfg(not(feature = "no_function"))] - #[cfg(not(feature = "no_closure"))] - in_closure: false, - is_breakable: false, - allow_statements: true, - allow_unquoted_map_properties: true, - options: self.options, level: 0, + flags: ParseSettingFlags::GLOBAL_LEVEL, + options: self.options, pos: Position::START, }; process_settings(&mut settings); diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 51011585..3c01613a 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -2,7 +2,7 @@ #![cfg(feature = "metadata")] use crate::api::type_names::format_type; -use crate::module::{calc_native_fn_hash, FuncInfo}; +use crate::module::{calc_native_fn_hash, FuncInfo, ModuleFlags}; use crate::{calc_fn_hash, Engine, FnAccess, SmartString, StaticVec, AST}; use serde::Serialize; #[cfg(feature = "no_std")] @@ -174,10 +174,16 @@ pub fn gen_metadata_to_json( global.modules.insert(name, m.as_ref().into()); } + let exclude_flags = if !include_standard_packages { + ModuleFlags::STANDARD_LIB + } else { + ModuleFlags::empty() + }; + engine .global_modules .iter() - .filter(|m| include_standard_packages || !m.standard) + .filter(|m| !m.flags.contains(exclude_flags)) .flat_map(|m| m.iter_fn()) .for_each(|f| { #[allow(unused_mut)] diff --git a/src/tokenizer.rs b/src/tokenizer.rs index f9467447..6c7e460a 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -966,18 +966,16 @@ impl Token { use Token::*; match self { - LexError(..) | SemiColon | // ; - is unary Colon | // #{ foo: - is unary Comma | // ( ... , -expr ) - is unary - //Period | - //Elvis | - //DoubleQuestion | - //QuestionBracket | - ExclusiveRange | // .. - is unary + //Period | + //Elvis | + DoubleQuestion | // ?? - is unary + ExclusiveRange | // .. - is unary InclusiveRange | // ..= - is unary LeftBrace | // { -expr } - is unary - // RightBrace | { expr } - expr not unary & is closing + // RightBrace | // { expr } - expr not unary & is closing LeftParen | // ( -expr ) - is unary // RightParen | // ( expr ) - expr not unary & is closing LeftBracket | // [ -expr ] - is unary @@ -1011,7 +1009,7 @@ impl Token { Pipe | Ampersand | If | - //Do | + //Do | While | Until | In | @@ -1022,9 +1020,14 @@ impl Token { XOr | XOrAssign | Return | - Throw => true, + Throw => true, - _ => false, + #[cfg(not(feature = "no_index"))] + QuestionBracket => true, // ?[ - is unary + + LexError(..) => true, + + _ => false, } } diff --git a/tests/closures.rs b/tests/closures.rs index 69df04e1..d2576e80 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -14,7 +14,7 @@ fn test_fn_ptr_curry_call() -> Result<(), Box> { engine.register_raw_fn( "call_with_arg", - &[TypeId::of::(), TypeId::of::()], + [TypeId::of::(), TypeId::of::()], |context, args| { let fn_ptr = std::mem::take(args[0]).cast::(); fn_ptr.call_raw(&context, None, [std::mem::take(args[1])]) @@ -165,7 +165,7 @@ fn test_closures() -> Result<(), Box> { engine.register_raw_fn( "custom_call", - &[TypeId::of::(), TypeId::of::()], + [TypeId::of::(), TypeId::of::()], |context, args| { let func = take(args[1]).cast::(); @@ -348,7 +348,7 @@ fn test_closures_shared_obj() -> Result<(), Box> { let p1 = Rc::new(RefCell::new(41)); let p2 = Rc::new(RefCell::new(1)); - f(p1.clone(), p2.clone())?; + f(p1.clone(), p2)?; assert_eq!(*p1.borrow(), 42); diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index dacca728..c3a5d0fc 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -274,8 +274,7 @@ fn test_custom_syntax_raw() -> Result<(), Box> { Ok(None) } s => Err(LexError::ImproperSymbol(s.to_string(), String::new()) - .into_err(Position::NONE) - .into()), + .into_err(Position::NONE)), }, _ => unreachable!(), },