diff --git a/src/engine.rs b/src/engine.rs index 07b18e51..334a7c00 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -17,7 +17,7 @@ use crate::stdlib::{ collections::{HashMap, HashSet}, fmt, format, hash::{Hash, Hasher}, - num::{NonZeroU64, NonZeroU8, NonZeroUsize}, + num::{NonZeroU8, NonZeroUsize}, ops::DerefMut, string::{String, ToString}, vec::Vec, @@ -41,6 +41,8 @@ use crate::Map; #[cfg(not(feature = "no_object"))] pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical +pub type Precedence = NonZeroU8; + /// _(INTERNALS)_ A stack of imported [modules][Module]. /// Exported under the `internals` feature only. /// @@ -590,7 +592,7 @@ pub struct Limits { #[cfg(not(feature = "no_function"))] pub max_function_expr_depth: Option, /// Maximum number of operations allowed to run. - pub max_operations: Option, + pub max_operations: Option, /// Maximum number of [modules][Module] allowed to load. /// /// Set to zero to effectively disable loading any [module][Module]. @@ -724,7 +726,7 @@ pub struct Engine { /// A hashset containing symbols to disable. pub(crate) disabled_symbols: HashSet, /// A hashmap containing custom keywords and precedence to recognize. - pub(crate) custom_keywords: HashMap>, + pub(crate) custom_keywords: HashMap>, /// Custom syntax. pub(crate) custom_syntax: HashMap, /// Callback closure for resolving variable access. diff --git a/src/engine_settings.rs b/src/engine_settings.rs index 166f41f0..7ba0f2cc 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -1,6 +1,7 @@ //! Configuration settings for [`Engine`]. -use crate::stdlib::{format, num::NonZeroU8, string::String}; +use crate::engine::Precedence; +use crate::stdlib::{format, string::String}; use crate::token::Token; use crate::Engine; @@ -272,7 +273,7 @@ impl Engine { keyword: &str, precedence: u8, ) -> Result<&mut Self, String> { - let precedence = NonZeroU8::new(precedence); + let precedence = Precedence::new(precedence); if precedence.is_none() { return Err("precedence cannot be zero".into()); diff --git a/src/parser.rs b/src/parser.rs index 171976e3..12a714a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,7 +5,7 @@ use crate::ast::{ Stmt, StmtBlock, }; use crate::dynamic::{AccessMode, Union}; -use crate::engine::{KEYWORD_THIS, OP_CONTAINS}; +use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS}; use crate::module::NamespaceRef; use crate::optimize::optimize_into_ast; use crate::optimize::OptimizationLevel; @@ -1611,7 +1611,7 @@ fn parse_binary_op( input: &mut TokenStream, state: &mut ParseState, lib: &mut FunctionsLib, - parent_precedence: u8, + parent_precedence: Option, lhs: Expr, mut settings: ParseSettings, ) -> Result { @@ -1625,18 +1625,12 @@ fn parse_binary_op( loop { let (current_op, current_pos) = input.peek().unwrap(); let precedence = match current_op { - Token::Custom(c) => { - if state - .engine - .custom_keywords - .get(c) - .map_or(false, Option::is_some) - { - state.engine.custom_keywords.get(c).unwrap().unwrap().get() - } else { - return Err(PERR::Reserved(c.clone()).into_err(*current_pos)); - } - } + Token::Custom(c) => state + .engine + .custom_keywords + .get(c) + .cloned() + .ok_or_else(|| PERR::Reserved(c.clone()).into_err(*current_pos))?, Token::Reserved(c) if !is_valid_identifier(c.chars()) => { return Err(PERR::UnknownOperator(c.into()).into_err(*current_pos)) } @@ -1656,18 +1650,12 @@ fn parse_binary_op( let (next_op, next_pos) = input.peek().unwrap(); let next_precedence = match next_op { - Token::Custom(c) => { - if state - .engine - .custom_keywords - .get(c) - .map_or(false, Option::is_some) - { - state.engine.custom_keywords.get(c).unwrap().unwrap().get() - } else { - return Err(PERR::Reserved(c.clone()).into_err(*next_pos)); - } - } + Token::Custom(c) => state + .engine + .custom_keywords + .get(c) + .cloned() + .ok_or_else(|| PERR::Reserved(c.clone()).into_err(*next_pos))?, Token::Reserved(c) if !is_valid_identifier(c.chars()) => { return Err(PERR::UnknownOperator(c.into()).into_err(*next_pos)) } @@ -1937,7 +1925,14 @@ fn parse_expr( // Parse expression normally. let lhs = parse_unary(input, state, lib, settings.level_up())?; - parse_binary_op(input, state, lib, 1, lhs, settings.level_up()) + parse_binary_op( + input, + state, + lib, + Precedence::new(1), + lhs, + settings.level_up(), + ) } /// Make sure that the expression is not a statement expression (i.e. wrapped in `{}`). diff --git a/src/token.rs b/src/token.rs index 0d68c460..909442c3 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,8 +1,8 @@ //! Main module defining the lexer and parser. use crate::engine::{ - KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, - KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF, + Precedence, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, + KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF, }; use crate::stdlib::{ borrow::Cow, @@ -666,10 +666,10 @@ impl Token { } /// Get the precedence number of the token. - pub fn precedence(&self) -> u8 { + pub fn precedence(&self) -> Option { use Token::*; - match self { + Precedence::new(match self { // Assignments are not considered expressions - set to zero Equals | PlusAssign | MinusAssign | MultiplyAssign | DivideAssign | PowerOfAssign | LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign @@ -696,7 +696,7 @@ impl Token { Period => 240, _ => 0, - } + }) } /// Does an expression bind to the right (instead of left)?