Change precedence to own type.

This commit is contained in:
Stephen Chung 2021-03-14 10:47:29 +08:00
parent 008ef0a41b
commit d9df6aabc8
4 changed files with 35 additions and 37 deletions

View File

@ -17,7 +17,7 @@ use crate::stdlib::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt, format, fmt, format,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
num::{NonZeroU64, NonZeroU8, NonZeroUsize}, num::{NonZeroU8, NonZeroUsize},
ops::DerefMut, ops::DerefMut,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
@ -41,6 +41,8 @@ use crate::Map;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
pub type Precedence = NonZeroU8;
/// _(INTERNALS)_ A stack of imported [modules][Module]. /// _(INTERNALS)_ A stack of imported [modules][Module].
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
/// ///
@ -590,7 +592,7 @@ pub struct Limits {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
pub max_function_expr_depth: Option<NonZeroUsize>, pub max_function_expr_depth: Option<NonZeroUsize>,
/// Maximum number of operations allowed to run. /// Maximum number of operations allowed to run.
pub max_operations: Option<NonZeroU64>, pub max_operations: Option<crate::stdlib::num::NonZeroU64>,
/// Maximum number of [modules][Module] allowed to load. /// Maximum number of [modules][Module] allowed to load.
/// ///
/// Set to zero to effectively disable loading any [module][Module]. /// Set to zero to effectively disable loading any [module][Module].
@ -724,7 +726,7 @@ pub struct Engine {
/// A hashset containing symbols to disable. /// A hashset containing symbols to disable.
pub(crate) disabled_symbols: HashSet<String>, pub(crate) disabled_symbols: HashSet<String>,
/// A hashmap containing custom keywords and precedence to recognize. /// A hashmap containing custom keywords and precedence to recognize.
pub(crate) custom_keywords: HashMap<String, Option<NonZeroU8>>, pub(crate) custom_keywords: HashMap<String, Option<Precedence>>,
/// Custom syntax. /// Custom syntax.
pub(crate) custom_syntax: HashMap<ImmutableString, CustomSyntax>, pub(crate) custom_syntax: HashMap<ImmutableString, CustomSyntax>,
/// Callback closure for resolving variable access. /// Callback closure for resolving variable access.

View File

@ -1,6 +1,7 @@
//! Configuration settings for [`Engine`]. //! 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::token::Token;
use crate::Engine; use crate::Engine;
@ -272,7 +273,7 @@ impl Engine {
keyword: &str, keyword: &str,
precedence: u8, precedence: u8,
) -> Result<&mut Self, String> { ) -> Result<&mut Self, String> {
let precedence = NonZeroU8::new(precedence); let precedence = Precedence::new(precedence);
if precedence.is_none() { if precedence.is_none() {
return Err("precedence cannot be zero".into()); return Err("precedence cannot be zero".into());

View File

@ -5,7 +5,7 @@ use crate::ast::{
Stmt, StmtBlock, Stmt, StmtBlock,
}; };
use crate::dynamic::{AccessMode, Union}; 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::module::NamespaceRef;
use crate::optimize::optimize_into_ast; use crate::optimize::optimize_into_ast;
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
@ -1611,7 +1611,7 @@ fn parse_binary_op(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
parent_precedence: u8, parent_precedence: Option<Precedence>,
lhs: Expr, lhs: Expr,
mut settings: ParseSettings, mut settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
@ -1625,18 +1625,12 @@ fn parse_binary_op(
loop { loop {
let (current_op, current_pos) = input.peek().unwrap(); let (current_op, current_pos) = input.peek().unwrap();
let precedence = match current_op { let precedence = match current_op {
Token::Custom(c) => { Token::Custom(c) => state
if state
.engine .engine
.custom_keywords .custom_keywords
.get(c) .get(c)
.map_or(false, Option::is_some) .cloned()
{ .ok_or_else(|| PERR::Reserved(c.clone()).into_err(*current_pos))?,
state.engine.custom_keywords.get(c).unwrap().unwrap().get()
} else {
return Err(PERR::Reserved(c.clone()).into_err(*current_pos));
}
}
Token::Reserved(c) if !is_valid_identifier(c.chars()) => { Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
return Err(PERR::UnknownOperator(c.into()).into_err(*current_pos)) 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_op, next_pos) = input.peek().unwrap();
let next_precedence = match next_op { let next_precedence = match next_op {
Token::Custom(c) => { Token::Custom(c) => state
if state
.engine .engine
.custom_keywords .custom_keywords
.get(c) .get(c)
.map_or(false, Option::is_some) .cloned()
{ .ok_or_else(|| PERR::Reserved(c.clone()).into_err(*next_pos))?,
state.engine.custom_keywords.get(c).unwrap().unwrap().get()
} else {
return Err(PERR::Reserved(c.clone()).into_err(*next_pos));
}
}
Token::Reserved(c) if !is_valid_identifier(c.chars()) => { Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
return Err(PERR::UnknownOperator(c.into()).into_err(*next_pos)) return Err(PERR::UnknownOperator(c.into()).into_err(*next_pos))
} }
@ -1937,7 +1925,14 @@ fn parse_expr(
// Parse expression normally. // Parse expression normally.
let lhs = parse_unary(input, state, lib, settings.level_up())?; 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 `{}`). /// Make sure that the expression is not a statement expression (i.e. wrapped in `{}`).

View File

@ -1,8 +1,8 @@
//! Main module defining the lexer and parser. //! Main module defining the lexer and parser.
use crate::engine::{ use crate::engine::{
KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, Precedence, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_FN_PTR_CALL,
KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_THIS, KEYWORD_TYPE_OF,
}; };
use crate::stdlib::{ use crate::stdlib::{
borrow::Cow, borrow::Cow,
@ -666,10 +666,10 @@ impl Token {
} }
/// Get the precedence number of the token. /// Get the precedence number of the token.
pub fn precedence(&self) -> u8 { pub fn precedence(&self) -> Option<Precedence> {
use Token::*; use Token::*;
match self { Precedence::new(match self {
// Assignments are not considered expressions - set to zero // Assignments are not considered expressions - set to zero
Equals | PlusAssign | MinusAssign | MultiplyAssign | DivideAssign | PowerOfAssign Equals | PlusAssign | MinusAssign | MultiplyAssign | DivideAssign | PowerOfAssign
| LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign | LeftShiftAssign | RightShiftAssign | AndAssign | OrAssign | XOrAssign
@ -696,7 +696,7 @@ impl Token {
Period => 240, Period => 240,
_ => 0, _ => 0,
} })
} }
/// Does an expression bind to the right (instead of left)? /// Does an expression bind to the right (instead of left)?