From 5c813ca7c0f82ebfe17b89f6f37c556d0c26736b Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 28 Dec 2020 09:49:54 +0800 Subject: [PATCH 1/2] Code cleanup. --- RELEASES.md | 7 +- doc/src/engine/metadata/gen_fn_sig.md | 5 +- src/ast.rs | 12 ++- src/module/mod.rs | 5 +- src/module/resolvers/file.rs | 14 +-- src/parser.rs | 145 ++++++++++++-------------- tests/optimizer.rs | 2 +- 7 files changed, 94 insertions(+), 96 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ae226bae..4198f744 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -4,13 +4,16 @@ Rhai Release Notes Version 0.19.9 ============== -This version removes the confusing differences between _packages_ and _modules_ +This version fixes a bug introduced in `0.19.8` which breaks property access +within closures. + +It also removes the confusing differences between _packages_ and _modules_ by unifying the terminology and API under the global umbrella of _modules_. Bug fixes --------- -* Property access in +* Bug when accessing properties in closures is fixed. Breaking changes ---------------- diff --git a/doc/src/engine/metadata/gen_fn_sig.md b/doc/src/engine/metadata/gen_fn_sig.md index 30067c60..8eab0d0c 100644 --- a/doc/src/engine/metadata/gen_fn_sig.md +++ b/doc/src/engine/metadata/gen_fn_sig.md @@ -53,9 +53,10 @@ In this case, the first parameter should be `&mut T` of the custom type and the Script-defined [function] signatures contain parameter names. Since all parameters, as well as the return value, are [`Dynamic`] the types are simply not shown. -A script-defined function always takes dynamic arguments, and the return type is also dynamic: +A script-defined function always takes dynamic arguments, and the return type is also dynamic, +so no type information is needed: -> `foo(x, y, z) -> Dynamic` +> `foo(x, y, z)` probably defined as: diff --git a/src/ast.rs b/src/ast.rs index b6c211c6..920dccb4 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -91,7 +91,7 @@ impl fmt::Display for ScriptFnDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "{}{}({}) -> Dynamic", + "{}{}({})", if self.access.is_private() { "private " } else { @@ -133,7 +133,7 @@ impl fmt::Display for ScriptFnMetadata<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "{}{}({}) -> Dynamic", + "{}{}({})", if self.access.is_private() { "private " } else { @@ -646,7 +646,7 @@ impl AsRef for AST { /// ## WARNING /// /// This type is volatile and may change. -#[derive(Debug, Clone, Eq, PartialEq, Hash)] +#[derive(Clone, Eq, PartialEq, Hash)] pub struct Ident { /// Identifier name. pub name: ImmutableString, @@ -654,6 +654,12 @@ pub struct Ident { pub pos: Position, } +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Ident({:?} @ {:?})", self.name, self.pos) + } +} + /// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement. /// Exported under the `internals` feature only. /// diff --git a/src/module/mod.rs b/src/module/mod.rs index 92c7b8fb..d1c023e5 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -101,8 +101,6 @@ impl FuncInfo { if return_type != "()" { sig.push_str(") -> "); sig.push_str(&return_type); - } else if self.func.is_script() { - sig.push_str(") -> Dynamic"); } else { sig.push_str(")"); } @@ -115,7 +113,7 @@ impl FuncInfo { } if self.func.is_script() { - sig.push_str(") -> Dynamic"); + sig.push_str(")"); } else { sig.push_str(") -> ?"); } @@ -471,6 +469,7 @@ impl Module { /// /// By taking a mutable reference, it is assumed that some sub-modules will be modified. /// Thus the module is automatically set to be non-indexed. + #[cfg(not(feature = "no_module"))] #[inline(always)] pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap> { // We must assume that the user has changed the sub-modules diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index b3be9bce..c35c347d 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -39,7 +39,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared}; /// ``` #[derive(Debug)] pub struct FileModuleResolver { - path: PathBuf, + base_path: PathBuf, extension: String, #[cfg(not(feature = "sync"))] @@ -99,7 +99,7 @@ impl FileModuleResolver { extension: impl Into, ) -> Self { Self { - path: path.into(), + base_path: path.into(), extension: extension.into(), cache: Default::default(), } @@ -127,13 +127,13 @@ impl FileModuleResolver { /// Get the base path for script files. #[inline(always)] - pub fn path(&self) -> &Path { - self.path.as_ref() + pub fn base_path(&self) -> &Path { + self.base_path.as_ref() } /// Set the base path for script files. #[inline(always)] - pub fn set_path(&mut self, path: impl Into) -> &mut Self { - self.path = path.into(); + pub fn set_base_path(&mut self, path: impl Into) -> &mut Self { + self.base_path = path.into(); self } @@ -186,7 +186,7 @@ impl ModuleResolver for FileModuleResolver { pos: Position, ) -> Result, Box> { // Construct the script file path - let mut file_path = self.path.clone(); + let mut file_path = self.base_path.clone(); file_path.push(path); file_path.set_extension(&self.extension); // Force extension diff --git a/src/parser.rs b/src/parser.rs index 5d22c9dd..0011572c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -280,12 +280,12 @@ fn parse_paren_expr( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // ( ... - settings.pos = eat_token(input, Token::LeftParen); - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // ( ... + settings.pos = eat_token(input, Token::LeftParen); + if match_token(input, Token::RightParen).0 { return Ok(Expr::Unit(settings.pos)); } @@ -316,11 +316,11 @@ fn parse_fn_call( mut namespace: Option, settings: ParseSettings, ) -> Result { - let (token, token_pos) = input.peek().unwrap(); - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + let (token, token_pos) = input.peek().unwrap(); + let mut args = StaticVec::new(); match token { @@ -642,12 +642,12 @@ fn parse_array_literal( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // [ ... - settings.pos = eat_token(input, Token::LeftBracket); - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // [ ... + settings.pos = eat_token(input, Token::LeftBracket); + let mut arr = StaticVec::new(); loop { @@ -712,12 +712,12 @@ fn parse_map_literal( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // #{ ... - settings.pos = eat_token(input, Token::MapStart); - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // #{ ... + settings.pos = eat_token(input, Token::MapStart); + let mut map: StaticVec<(Ident, Expr)> = Default::default(); loop { @@ -823,13 +823,12 @@ fn parse_switch( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // switch ... - let token_pos = eat_token(input, Token::Switch); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // switch ... + settings.pos = eat_token(input, Token::Switch); + let item = parse_expr(input, state, lib, settings.level_up())?; match input.next().unwrap() { @@ -950,12 +949,12 @@ fn parse_primary( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - let (token, token_pos) = input.peek().unwrap(); - settings.pos = *token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + let (token, token_pos) = input.peek().unwrap(); + settings.pos = *token_pos; + let mut root_expr = match token { Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)), @@ -1241,7 +1240,7 @@ fn parse_primary( state.allow_capture = false; } - let rhs = parse_unary(input, state, lib, settings.level_up())?; + let rhs = parse_primary(input, state, lib, settings.level_up())?; make_dot_expr(state, expr, rhs, tail_pos)? } // Unknown postfix operator @@ -1262,17 +1261,16 @@ fn parse_primary( }, _ => None, } - .map(|x| { - if let (_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) = x.as_mut() { + .map(|x| match x.as_mut() { + (_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) => { // Qualifiers + variable name *hash = calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0).unwrap(); #[cfg(not(feature = "no_module"))] namespace.set_index(state.find_module(&namespace[0].name)); - } else { - unreachable!(); } + _ => unreachable!(), }); // Make sure identifiers are valid @@ -1458,12 +1456,12 @@ fn parse_op_assignment_stmt( lhs: Expr, mut settings: ParseSettings, ) -> Result { - let (token, token_pos) = input.peek().unwrap(); - settings.pos = *token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + let (token, token_pos) = input.peek().unwrap(); + settings.pos = *token_pos; + let op = match token { Token::Equals => "".into(), @@ -1714,11 +1712,11 @@ fn parse_binary_op( lhs: Expr, mut settings: ParseSettings, ) -> Result { - settings.pos = lhs.position(); - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + settings.pos = lhs.position(); + let mut root = lhs; loop { @@ -1868,12 +1866,6 @@ fn parse_binary_op( make_in_expr(current_lhs, rhs, pos)? } - // #[cfg(not(feature = "no_object"))] - // Token::Period => { - // let rhs = args.pop().unwrap(); - // let current_lhs = args.pop().unwrap(); - // make_dot_expr(state, current_lhs, rhs, pos)? - // } Token::Custom(s) if state .engine @@ -2017,11 +2009,11 @@ fn parse_expr( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - settings.pos = input.peek().unwrap().1; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + settings.pos = input.peek().unwrap().1; + // Check if it is a custom syntax. if !state.engine.custom_syntax.is_empty() { let (token, pos) = input.peek().unwrap(); @@ -2095,13 +2087,12 @@ fn parse_if( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // if ... - let token_pos = eat_token(input, Token::If); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // if ... + settings.pos = eat_token(input, Token::If); + // if guard { if_body } ensure_not_statement_expr(input, "a boolean")?; let guard = parse_expr(input, state, lib, settings.level_up())?; @@ -2121,7 +2112,11 @@ fn parse_if( None }; - Ok(Stmt::If(guard, Box::new((if_body, else_body)), token_pos)) + Ok(Stmt::If( + guard, + Box::new((if_body, else_body)), + settings.pos, + )) } /// Parse a while loop. @@ -2149,7 +2144,7 @@ fn parse_while_loop( settings.is_breakable = true; let body = Box::new(parse_block(input, state, lib, settings.level_up())?); - Ok(Stmt::While(guard, body, token_pos)) + Ok(Stmt::While(guard, body, settings.pos)) } /// Parse a do loop. @@ -2159,13 +2154,12 @@ fn parse_do( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // do ... - let token_pos = eat_token(input, Token::Do); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // do ... + settings.pos = eat_token(input, Token::Do); + // do { body } [while|until] guard settings.is_breakable = true; let body = Box::new(parse_block(input, state, lib, settings.level_up())?); @@ -2186,7 +2180,7 @@ fn parse_do( let guard = parse_expr(input, state, lib, settings.level_up())?; ensure_not_assignment(input)?; - Ok(Stmt::Do(body, guard, is_while, token_pos)) + Ok(Stmt::Do(body, guard, is_while, settings.pos)) } /// Parse a for loop. @@ -2196,13 +2190,12 @@ fn parse_for( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // for ... - let token_pos = eat_token(input, Token::For); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // for ... + settings.pos = eat_token(input, Token::For); + // for name ... let name = match input.next().unwrap() { // Variable name @@ -2242,7 +2235,7 @@ fn parse_for( state.stack.truncate(prev_stack_len); - Ok(Stmt::For(expr, Box::new((name, body)), token_pos)) + Ok(Stmt::For(expr, Box::new((name, body)), settings.pos)) } /// Parse a variable definition statement. @@ -2254,13 +2247,12 @@ fn parse_let( export: bool, mut settings: ParseSettings, ) -> Result { - // let/const... (specified in `var_type`) - let token_pos = input.next().unwrap().1; - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // let/const... (specified in `var_type`) + settings.pos = input.next().unwrap().1; + // let name ... let (name, pos) = match input.next().unwrap() { (Token::Identifier(s), pos) => (s, pos), @@ -2272,7 +2264,7 @@ fn parse_let( }; // let name = ... - let init_expr = if match_token(input, Token::Equals).0 { + let expr = if match_token(input, Token::Equals).0 { // let name = expr Some(parse_expr(input, state, lib, settings.level_up())?) } else { @@ -2285,14 +2277,14 @@ fn parse_let( let name = state.get_interned_string(name); state.stack.push((name.clone(), AccessMode::ReadWrite)); let var_def = Ident { name, pos }; - Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos)) + Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos)) } // const name = { expr:constant } AccessMode::ReadOnly => { let name = state.get_interned_string(name); state.stack.push((name.clone(), AccessMode::ReadOnly)); let var_def = Ident { name, pos }; - Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos)) + Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos)) } } } @@ -2305,23 +2297,22 @@ fn parse_import( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // import ... - let token_pos = eat_token(input, Token::Import); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // import ... + settings.pos = eat_token(input, Token::Import); + // import expr ... let expr = parse_expr(input, state, lib, settings.level_up())?; // import expr as ... if !match_token(input, Token::As).0 { - return Ok(Stmt::Import(expr, None, token_pos)); + return Ok(Stmt::Import(expr, None, settings.pos)); } // import expr as name ... - let (name, _) = match input.next().unwrap() { + let (name, name_pos) = match input.next().unwrap() { (Token::Identifier(s), pos) => (s, pos), (Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => { return Err(PERR::Reserved(s).into_err(pos)); @@ -2337,9 +2328,9 @@ fn parse_import( expr, Some(Box::new(Ident { name, - pos: settings.pos, + pos: name_pos, })), - token_pos, + settings.pos, )) } @@ -2351,12 +2342,11 @@ fn parse_export( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - let token_pos = eat_token(input, Token::Export); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + settings.pos = eat_token(input, Token::Export); + match input.peek().unwrap() { (Token::Let, pos) => { let pos = *pos; @@ -2424,7 +2414,7 @@ fn parse_export( } } - Ok(Stmt::Export(exports, token_pos)) + Ok(Stmt::Export(exports, settings.pos)) } /// Parse a statement block. @@ -2513,11 +2503,11 @@ fn parse_expr_stmt( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - settings.pos = input.peek().unwrap().1; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + settings.pos = input.peek().unwrap().1; + let expr = parse_expr(input, state, lib, settings.level_up())?; let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?; Ok(stmt) @@ -2715,13 +2705,12 @@ fn parse_try_catch( lib: &mut FunctionsLib, mut settings: ParseSettings, ) -> Result { - // try ... - let token_pos = eat_token(input, Token::Try); - settings.pos = token_pos; - #[cfg(not(feature = "unchecked"))] settings.ensure_level_within_max_limit(state.max_expr_depth)?; + // try ... + settings.pos = eat_token(input, Token::Try); + // try { body } let body = parse_block(input, state, lib, settings.level_up())?; @@ -2765,7 +2754,7 @@ fn parse_try_catch( Ok(Stmt::TryCatch( Box::new((body, var_def, catch_body)), - token_pos, + settings.pos, catch_pos, )) } diff --git a/tests/optimizer.rs b/tests/optimizer.rs index bfb9c4e0..94d77d3c 100644 --- a/tests/optimizer.rs +++ b/tests/optimizer.rs @@ -55,7 +55,7 @@ fn test_optimizer_parse() -> Result<(), Box> { let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?; - assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident { name: "DECISION", pos: 1:9 }, Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#)); + assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident("DECISION" @ 1:9), Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#)); let ast = engine.compile("if 1 == 2 { 42 }")?; From e481a8019dde3e74f297be48c49d735d4022d3b7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 28 Dec 2020 14:21:13 +0800 Subject: [PATCH 2/2] Simplify code and better error messages. --- RELEASES.md | 3 +- src/ast.rs | 18 +----- src/dynamic.rs | 3 +- src/engine.rs | 86 +++++++++++++++++---------- src/fn_call.rs | 8 ++- src/fn_native.rs | 24 +++++--- src/optimize.rs | 2 - src/parser.rs | 65 +++++++++------------ src/result.rs | 27 ++++++--- src/serde_impl/ser.rs | 133 +++++++++++++++++++++++++++++------------- src/token.rs | 12 ++-- 11 files changed, 224 insertions(+), 157 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 4198f744..f91a0b16 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,7 +13,8 @@ by unifying the terminology and API under the global umbrella of _modules_. Bug fixes --------- -* Bug when accessing properties in closures is fixed. +* Fix bug when accessing properties in closures. +* Fix bug when accessing a deep index with a function call. Breaking changes ---------------- diff --git a/src/ast.rs b/src/ast.rs index 920dccb4..0707c87b 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -830,7 +830,7 @@ impl Stmt { Self::Import(_, _, _) | Self::Export(_, _) => false, #[cfg(not(feature = "no_closure"))] - Self::Share(_) => unreachable!(), + Self::Share(_) => unreachable!("Stmt::Share should not be parsed"), } } /// Is this statement _pure_? @@ -979,8 +979,6 @@ pub enum Expr { Property(Box<(ImmutableString, ImmutableString, Ident)>), /// { [statement][Stmt] } Stmt(Box>, Position), - /// Wrapped [expression][Expr] - should not be optimized away. - Expr(Box), /// func `(` expr `,` ... `)` FnCall(Box, Position), /// lhs `.` rhs @@ -1010,8 +1008,6 @@ impl Expr { /// Returns [`None`] if the expression is not constant. pub fn get_constant_value(&self) -> Option { Some(match self { - Self::Expr(x) => return x.get_constant_value(), - Self::DynamicConstant(x, _) => x.as_ref().clone(), Self::IntegerConstant(x, _) => (*x).into(), #[cfg(not(feature = "no_float"))] @@ -1061,8 +1057,6 @@ impl Expr { /// Get the [position][Position] of the expression. pub fn position(&self) -> Position { match self { - Self::Expr(x) => x.position(), - #[cfg(not(feature = "no_float"))] Self::FloatConstant(_, pos) => *pos, @@ -1091,10 +1085,6 @@ impl Expr { /// Override the [position][Position] of the expression. pub fn set_position(&mut self, new_pos: Position) -> &mut Self { match self { - Self::Expr(x) => { - x.set_position(new_pos); - } - #[cfg(not(feature = "no_float"))] Self::FloatConstant(_, pos) => *pos = new_pos, @@ -1123,8 +1113,6 @@ impl Expr { /// A pure expression has no side effects. pub fn is_pure(&self) -> bool { match self { - Self::Expr(x) => x.is_pure(), - Self::Array(x, _) => x.iter().all(Self::is_pure), Self::Map(x, _) => x.iter().map(|(_, v)| v).all(Self::is_pure), @@ -1151,8 +1139,6 @@ impl Expr { /// Is the expression a constant? pub fn is_constant(&self) -> bool { match self { - Self::Expr(x) => x.is_constant(), - #[cfg(not(feature = "no_float"))] Self::FloatConstant(_, _) => true, @@ -1189,8 +1175,6 @@ impl Expr { } match self { - Self::Expr(x) => x.is_valid_postfix(token), - #[cfg(not(feature = "no_float"))] Self::FloatConstant(_, _) => false, diff --git a/src/dynamic.rs b/src/dynamic.rs index ba4abb5d..75b3c7a4 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -812,6 +812,7 @@ impl Dynamic { #[cfg(not(feature = "no_closure"))] #[cfg(feature = "sync")] Union::Shared(cell, _) => return cell.read().unwrap().clone().try_cast(), + _ => (), } @@ -903,7 +904,7 @@ impl Dynamic { match self.0 { Union::Variant(value, _) => (*value).as_box_any().downcast().map(|x| *x).ok(), #[cfg(not(feature = "no_closure"))] - Union::Shared(_, _) => unreachable!(), + Union::Shared(_, _) => unreachable!("Union::Shared case should be already handled"), _ => None, } } diff --git a/src/engine.rs b/src/engine.rs index 012578c9..5d05c85a 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -225,7 +225,7 @@ impl IndexChainValue { #[cfg(not(feature = "no_index"))] pub fn as_value(self) -> Dynamic { match self { - Self::None | Self::FnCallArgs(_) => unreachable!("expecting IndexChainValue::Value"), + Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"), Self::Value(value) => value, } } @@ -237,7 +237,7 @@ impl IndexChainValue { #[cfg(not(feature = "no_object"))] pub fn as_fn_call_args(self) -> StaticVec { match self { - Self::None | Self::Value(_) => unreachable!("expecting IndexChainValue::FnCallArgs"), + Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"), Self::FnCallArgs(value) => value, } } @@ -382,7 +382,7 @@ impl<'a> Target<'a> { #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_object"))] Self::LockGuard((r, _)) => **r = new_val, - Self::Value(_) => unreachable!(), + Self::Value(_) => panic!("cannot update a value"), #[cfg(not(feature = "no_index"))] Self::StringChar(string, index, _) if string.is::() => { let mut s = string.write_lock::().unwrap(); @@ -896,7 +896,7 @@ impl Engine { // Normal variable access _ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr), }, - _ => unreachable!(), + _ => unreachable!("Expr::Variable expected, but gets {:?}", expr), } } @@ -912,7 +912,7 @@ impl Engine { ) -> Result<(Target<'s>, Position), Box> { let (index, _, Ident { name, pos }) = match expr { Expr::Variable(v) => v.as_ref(), - _ => unreachable!(), + _ => unreachable!("Expr::Variable expected, but gets {:?}", expr), }; // Check if the variable is `this` @@ -988,7 +988,7 @@ impl Engine { new_val: Option<(Dynamic, Position)>, ) -> Result<(Dynamic, bool), Box> { if chain_type == ChainType::None { - unreachable!(); + unreachable!("should not be ChainType::None"); } let is_ref = target.is_ref(); @@ -1103,7 +1103,9 @@ impl Engine { ) } // xxx.module::fn_name(...) - syntax error - Expr::FnCall(_, _) => unreachable!(), + Expr::FnCall(_, _) => { + unreachable!("function call in dot chain should not be namespace-qualified") + } // {xxx:map}.id = ??? Expr::Property(x) if target_val.is::() && new_val.is_some() => { let Ident { name, pos } = &x.2; @@ -1178,9 +1180,11 @@ impl Engine { val.into() } // {xxx:map}.module::fn_name(...) - syntax error - Expr::FnCall(_, _) => unreachable!(), + Expr::FnCall(_, _) => unreachable!( + "function call in dot chain should not be namespace-qualified" + ), // Others - syntax error - _ => unreachable!(), + expr => unreachable!("invalid dot expression: {:?}", expr), }; self.eval_dot_index_chain_helper( @@ -1266,9 +1270,11 @@ impl Engine { .map_err(|err| err.fill_position(*pos)) } // xxx.module::fn_name(...) - syntax error - Expr::FnCall(_, _) => unreachable!(), + Expr::FnCall(_, _) => unreachable!( + "function call in dot chain should not be namespace-qualified" + ), // Others - syntax error - _ => unreachable!(), + expr => unreachable!("invalid dot expression: {:?}", expr), } } // Syntax error @@ -1276,7 +1282,7 @@ impl Engine { } } - _ => unreachable!(), + chain_type => unreachable!("invalid ChainType: {:?}", chain_type), } } @@ -1296,7 +1302,7 @@ impl Engine { let (crate::ast::BinaryExpr { lhs, rhs }, chain_type, op_pos) = match expr { Expr::Index(x, pos) => (x.as_ref(), ChainType::Index, *pos), Expr::Dot(x, pos) => (x.as_ref(), ChainType::Dot, *pos), - _ => unreachable!(), + _ => unreachable!("index or dot chain expected, but gets {:?}", expr), }; let idx_values = &mut Default::default(); @@ -1333,7 +1339,7 @@ impl Engine { .map_err(|err| err.fill_position(op_pos)) } // {expr}.??? = ??? or {expr}[???] = ??? - _ if new_val.is_some() => unreachable!(), + _ if new_val.is_some() => unreachable!("cannot assign to an expression"), // {expr}.??? or {expr}[???] expr => { let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; @@ -1359,7 +1365,7 @@ impl Engine { lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, expr: &Expr, - chain_type: ChainType, + parent_chain_type: ChainType, idx_values: &mut StaticVec, size: usize, level: usize, @@ -1367,7 +1373,7 @@ impl Engine { self.inc_operations(state, expr.position())?; match expr { - Expr::FnCall(x, _) if x.namespace.is_none() => { + Expr::FnCall(x, _) if parent_chain_type == ChainType::Dot && x.namespace.is_none() => { let arg_values = x .args .iter() @@ -1378,15 +1384,27 @@ impl Engine { idx_values.push(arg_values.into()); } - Expr::FnCall(_, _) => unreachable!(), - Expr::Property(_) => idx_values.push(IndexChainValue::None), + Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => { + unreachable!("function call in dot chain should not be namespace-qualified") + } + + Expr::Property(_) if parent_chain_type == ChainType::Dot => { + idx_values.push(IndexChainValue::None) + } + Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"), + Expr::Index(x, _) | Expr::Dot(x, _) => { let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref(); // Evaluate in left-to-right order let lhs_val = match lhs { - Expr::Property(_) => IndexChainValue::None, - Expr::FnCall(x, _) if chain_type == ChainType::Dot && x.namespace.is_none() => { + Expr::Property(_) if parent_chain_type == ChainType::Dot => { + IndexChainValue::None + } + Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"), + Expr::FnCall(x, _) + if parent_chain_type == ChainType::Dot && x.namespace.is_none() => + { x.args .iter() .map(|arg_expr| { @@ -1395,7 +1413,9 @@ impl Engine { .collect::, _>>()? .into() } - Expr::FnCall(_, _) => unreachable!(), + Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => { + unreachable!("function call in dot chain should not be namespace-qualified") + } _ => self .eval_expr(scope, mods, state, lib, this_ptr, lhs, level)? .into(), @@ -1405,7 +1425,7 @@ impl Engine { let chain_type = match expr { Expr::Index(_, _) => ChainType::Index, Expr::Dot(_, _) => ChainType::Dot, - _ => unreachable!(), + _ => unreachable!("index or dot chain expected, but gets {:?}", expr), }; self.eval_indexed_chain( scope, mods, state, lib, this_ptr, rhs, chain_type, idx_values, size, level, @@ -1413,6 +1433,7 @@ impl Engine { idx_values.push(lhs_val); } + _ => idx_values.push( self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .into(), @@ -1622,7 +1643,7 @@ impl Engine { // var[...] #[cfg(not(feature = "no_index"))] Expr::Index(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs { - Expr::Property(_) => unreachable!(), + Expr::Property(_) => unreachable!("unexpected Expr::Property in indexing"), // var[...]... Expr::FnCall(_, _) | Expr::Index(_, _) | Expr::Dot(_, _) => self .eval_expr(scope, mods, state, lib, this_ptr, expr, level) @@ -1655,7 +1676,9 @@ impl Engine { // var.prop #[cfg(not(feature = "no_object"))] Expr::Dot(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs { - Expr::Variable(_) => unreachable!(), + Expr::Variable(_) => unreachable!( + "unexpected Expr::Variable in dot access (should be Expr::Property)" + ), // var.prop Expr::Property(ref p) => { let (mut target, _) = self.eval_expr_as_target( @@ -1718,8 +1741,6 @@ impl Engine { self.inc_operations(state, expr.position())?; let result = match expr { - Expr::Expr(x) => self.eval_expr(scope, mods, state, lib, this_ptr, x, level), - Expr::DynamicConstant(x, _) => Ok(x.as_ref().clone()), Expr::IntegerConstant(x, _) => Ok((*x).into()), #[cfg(not(feature = "no_float"))] @@ -1738,7 +1759,6 @@ impl Engine { let (val, _) = self.search_namespace(scope, mods, state, lib, this_ptr, expr)?; Ok(val.take_or_clone()) } - Expr::Property(_) => unreachable!(), // Statement block Expr::Stmt(x, _) => { @@ -1867,7 +1887,7 @@ impl Engine { (custom.func)(&mut context, &expressions) } - _ => unreachable!(), + _ => unreachable!("expression cannot be evaluated: {:?}", expr), }; self.check_data_size(result, expr.position()) @@ -2072,7 +2092,9 @@ impl Engine { // Must be either `var[index] op= val` or `var.prop op= val` match lhs_expr { // name op= rhs (handled above) - Expr::Variable(_) => unreachable!(), + Expr::Variable(_) => { + unreachable!("Expr::Variable case should already been handled") + } // idx_lhs[idx_expr] op= rhs #[cfg(not(feature = "no_index"))] Expr::Index(_, _) => { @@ -2090,7 +2112,7 @@ impl Engine { Ok(Dynamic::UNIT) } // Non-lvalue expression (should be caught during parsing) - _ => unreachable!(), + _ => unreachable!("cannot assign to expression: {:?}", lhs_expr), } } @@ -2334,7 +2356,7 @@ impl Engine { let entry_type = match stmt { Stmt::Let(_, _, _, _) => AccessMode::ReadWrite, Stmt::Const(_, _, _, _) => AccessMode::ReadOnly, - _ => unreachable!(), + _ => unreachable!("should be Stmt::Let or Stmt::Const, but gets {:?}", stmt), }; let val = if let Some(expr) = expr { @@ -2353,7 +2375,7 @@ impl Engine { }, ) } else if *export { - unreachable!(); + unreachable!("exported variable not on global level"); } else { (unsafe_cast_var_name_to_lifetime(&var_def.name).into(), None) }; diff --git a/src/fn_call.rs b/src/fn_call.rs index 8b42985f..ae678448 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -118,7 +118,7 @@ impl Drop for ArgBackup<'_> { // Panic if the shorter lifetime leaks. assert!( self.orig_mut.is_none(), - "MutBackup::restore has not been called prior to existing this scope" + "ArgBackup::restore_first_arg has not been called prior to existing this scope" ); } } @@ -672,7 +672,9 @@ impl Engine { }) .or_else(|err| match *err { EvalAltResult::Return(out, _) => Ok(out), - EvalAltResult::LoopBreak(_, _) => unreachable!(), + EvalAltResult::LoopBreak(_, _) => { + unreachable!("no outer loop scope to break out of") + } _ => Err(err), }) } @@ -1227,7 +1229,7 @@ impl Engine { f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut()) } - Some(_) => unreachable!(), + Some(f) => unreachable!("unknown function type: {:?}", f), None if def_val.is_some() => Ok(def_val.unwrap().clone()), None => EvalAltResult::ErrorFunctionNotFound( format!( diff --git a/src/fn_native.rs b/src/fn_native.rs index 68b5b0ce..ddfebb20 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -535,10 +535,10 @@ impl CallableFunction { pub fn get_native_fn(&self) -> &FnAny { match self { Self::Pure(f) | Self::Method(f) => f.as_ref(), - Self::Iterator(_) | Self::Plugin(_) => unreachable!(), + Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"), #[cfg(not(feature = "no_function"))] - Self::Script(_) => unreachable!(), + Self::Script(_) => panic!("function should be native"), } } /// Get a shared reference to a script-defined function definition. @@ -549,7 +549,9 @@ impl CallableFunction { #[cfg(not(feature = "no_function"))] pub fn get_fn_def(&self) -> &ScriptFnDef { match self { - Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => unreachable!(), + Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => { + panic!("function should be scripted") + } Self::Script(f) => f.as_ref(), } } @@ -561,10 +563,12 @@ impl CallableFunction { pub fn get_iter_fn(&self) -> IteratorFn { match self { Self::Iterator(f) => *f, - Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => unreachable!(), + Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => { + panic!("function should an iterator") + } #[cfg(not(feature = "no_function"))] - Self::Script(_) => unreachable!(), + Self::Script(_) => panic!("function should be an iterator"), } } /// Get a shared reference to a plugin function. @@ -575,10 +579,12 @@ impl CallableFunction { pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin { match self { Self::Plugin(f) => f.as_ref(), - Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(), + Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => { + panic!("function should a plugin") + } #[cfg(not(feature = "no_function"))] - Self::Script(_) => unreachable!(), + Self::Script(_) => panic!("function should a plugin"), } } /// Create a new [`CallableFunction::Pure`]. @@ -609,7 +615,7 @@ impl From for CallableFunction { #[inline(always)] fn from(_func: ScriptFnDef) -> Self { #[cfg(feature = "no_function")] - unreachable!(); + unreachable!("no_function active"); #[cfg(not(feature = "no_function"))] Self::Script(_func.into()) @@ -620,7 +626,7 @@ impl From> for CallableFunction { #[inline(always)] fn from(_func: Shared) -> Self { #[cfg(feature = "no_function")] - unreachable!(); + unreachable!("no_function active"); #[cfg(not(feature = "no_function"))] Self::Script(_func) diff --git a/src/optimize.rs b/src/optimize.rs index 07d16642..5ba290e0 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -483,8 +483,6 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { ]; match expr { - // expr - do not promote because there is a reason it is wrapped in an `Expr::Expr` - Expr::Expr(x) => optimize_expr(x, state), // {} Expr::Stmt(x, pos) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(*pos) } // { stmt; ... } - do not count promotion as dirty because it gets turned back into an array diff --git a/src/parser.rs b/src/parser.rs index 0011572c..d9f37d74 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -603,26 +603,10 @@ fn parse_index_chain( )) } // Otherwise terminate the indexing chain - _ => { - match idx_expr { - // Terminate with an `Expr::Expr` wrapper to prevent the last index expression - // inside brackets to be mis-parsed as another level of indexing, or a - // dot expression/function call to be mis-parsed as following the indexing chain. - Expr::Index(_, _) | Expr::Dot(_, _) | Expr::FnCall(_, _) => { - Ok(Expr::Index( - Box::new(BinaryExpr { - lhs, - rhs: Expr::Expr(Box::new(idx_expr)), - }), - settings.pos, - )) - } - _ => Ok(Expr::Index( - Box::new(BinaryExpr { lhs, rhs: idx_expr }), - settings.pos, - )), - } - } + _ => Ok(Expr::Index( + Box::new(BinaryExpr { lhs, rhs: idx_expr }), + settings.pos, + )), } } (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)), @@ -970,7 +954,7 @@ fn parse_primary( } Token::True => Expr::BoolConstant(true, settings.pos), Token::False => Expr::BoolConstant(false, settings.pos), - _ => unreachable!(), + t => unreachable!("unexpected token: {:?}", t), }, #[cfg(not(feature = "no_float"))] Token::FloatConstant(x) => { @@ -983,7 +967,7 @@ fn parse_primary( Token::LeftBrace if settings.allow_stmt_expr => { match parse_block(input, state, lib, settings.level_up())? { Stmt::Block(statements, pos) => Expr::Stmt(Box::new(statements.into()), pos), - _ => unreachable!(), + stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt), } } // ( - grouped expression @@ -1050,7 +1034,7 @@ fn parse_primary( Token::Identifier(_) => { let s = match input.next().unwrap().0 { Token::Identifier(s) => s, - _ => unreachable!(), + t => unreachable!("expecting Token::Identifier, but gets {:?}", t), }; match input.peek().unwrap().0 { @@ -1097,7 +1081,7 @@ fn parse_primary( Token::Reserved(_) => { let s = match input.next().unwrap().0 { Token::Reserved(s) => s, - _ => unreachable!(), + t => unreachable!("expecting Token::Reserved, but gets {:?}", t), }; match input.peek().unwrap().0 { @@ -1140,7 +1124,7 @@ fn parse_primary( Token::LexError(_) => { let err = match input.next().unwrap().0 { Token::LexError(err) => err, - _ => unreachable!(), + t => unreachable!("expecting Token::LexError, but gets {:?}", t), }; return Err(err.into_err(settings.pos)); @@ -1200,7 +1184,6 @@ fn parse_primary( let ns = namespace.map(|(_, ns)| ns); parse_fn_call(input, state, lib, name, false, ns, settings.level_up())? } - (Expr::Property(_), _) => unreachable!(), // module access (Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() { (Token::Identifier(id2), pos2) => { @@ -1270,7 +1253,7 @@ fn parse_primary( #[cfg(not(feature = "no_module"))] namespace.set_index(state.find_module(&namespace[0].name)); } - _ => unreachable!(), + _ => unreachable!("expecting namespace-qualified variable access"), }); // Make sure identifiers are valid @@ -1973,7 +1956,7 @@ fn parse_custom_syntax( segments.push(keyword.clone()); tokens.push(keyword); } - _ => unreachable!(), + stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt), }, s => match input.next().unwrap() { (Token::LexError(err), pos) => return Err(err.into_err(pos)), @@ -2136,7 +2119,7 @@ fn parse_while_loop( (parse_expr(input, state, lib, settings.level_up())?, pos) } (Token::Loop, pos) => (Expr::BoolConstant(true, pos), pos), - _ => unreachable!(), + (t, _) => unreachable!("expecting Token::While or Token::Loop, but gets {:?}", t), }; settings.pos = token_pos; @@ -2533,23 +2516,24 @@ fn parse_stmt( } if !is_doc_comment(comment) { - unreachable!(); + unreachable!("expecting doc-comment, but gets {:?}", comment); } if !settings.is_global { return Err(PERR::WrongDocComment.into_err(comments_pos)); } - if let Token::Comment(comment) = input.next().unwrap().0 { - comments.push(comment); + match input.next().unwrap().0 { + Token::Comment(comment) => { + comments.push(comment); - match input.peek().unwrap() { - (Token::Fn, _) | (Token::Private, _) => break, - (Token::Comment(_), _) => (), - _ => return Err(PERR::WrongDocComment.into_err(comments_pos)), + match input.peek().unwrap() { + (Token::Fn, _) | (Token::Private, _) => break, + (Token::Comment(_), _) => (), + _ => return Err(PERR::WrongDocComment.into_err(comments_pos)), + } } - } else { - unreachable!(); + t => unreachable!("expecting Token::Comment, but gets {:?}", t), } } @@ -2649,7 +2633,10 @@ fn parse_stmt( match token { Token::Return => ReturnType::Return, Token::Throw => ReturnType::Exception, - _ => unreachable!(), + t => unreachable!( + "expecting Token::Return or Token::Throw, but gets {:?}", + t + ), }, pos, ) diff --git a/src/result.rs b/src/result.rs index 02a0f5c8..afc45dec 100644 --- a/src/result.rs +++ b/src/result.rs @@ -190,13 +190,16 @@ impl fmt::Display for EvalAltResult { Self::ErrorAssignmentToConstant(s, _) => { write!(f, "Cannot assign to constant '{}'", s)? } - Self::ErrorMismatchOutputType(r, s, _) => { + Self::ErrorMismatchOutputType(s, r, _) => { write!(f, "Output type is incorrect: {} (expecting {})", r, s)? } - Self::ErrorMismatchDataType(r, s, _) if r.is_empty() => { + Self::ErrorMismatchDataType(s, r, _) if r.is_empty() => { write!(f, "Data type is incorrect, expecting {}", s)? } - Self::ErrorMismatchDataType(r, s, _) => { + Self::ErrorMismatchDataType(s, r, _) if s.is_empty() => { + write!(f, "Data type is incorrect: {}", r)? + } + Self::ErrorMismatchDataType(s, r, _) => { write!(f, "Data type is incorrect: {} (expecting {})", r, s)? } Self::ErrorArithmetic(s, _) => f.write_str(s)?, @@ -263,10 +266,14 @@ impl> From for Box { impl EvalAltResult { /// Can this error be caught? + /// + /// # Panics + /// + /// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return]. pub fn is_catchable(&self) -> bool { match self { Self::ErrorSystem(_, _) => false, - Self::ErrorParsing(_, _) => unreachable!(), + Self::ErrorParsing(_, _) => false, Self::ErrorFunctionNotFound(_, _) | Self::ErrorInFunctionCall(_, _, _) @@ -293,14 +300,19 @@ impl EvalAltResult { | Self::ErrorDataTooLarge(_, _) | Self::ErrorTerminated(_, _) => false, - Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(), + Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"), + Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"), } } /// Is this error a system exception? + /// + /// # Panics + /// + /// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return]. pub fn is_system_exception(&self) -> bool { match self { Self::ErrorSystem(_, _) => true, - Self::ErrorParsing(_, _) => unreachable!(), + Self::ErrorParsing(_, _) => true, Self::ErrorTooManyOperations(_) | Self::ErrorTooManyModules(_) @@ -309,7 +321,8 @@ impl EvalAltResult { Self::ErrorTerminated(_, _) => true, - Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(), + Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"), + Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"), _ => false, } diff --git a/src/serde_impl/ser.rs b/src/serde_impl/ser.rs index b4c6dedd..dc62d3c7 100644 --- a/src/serde_impl/ser.rs +++ b/src/serde_impl/ser.rs @@ -283,9 +283,9 @@ impl Serializer for &mut DynamicSerializer { make_variant(_variant, content) } #[cfg(feature = "no_object")] - return EvalAltResult::ErrorMismatchOutputType( - "Dynamic".into(), - "map".into(), + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), Position::NONE, ) .into(); @@ -295,9 +295,9 @@ impl Serializer for &mut DynamicSerializer { #[cfg(not(feature = "no_index"))] return Ok(DynamicSerializer::new(Array::new().into())); #[cfg(feature = "no_index")] - return EvalAltResult::ErrorMismatchOutputType( - "Dynamic".into(), - "array".into(), + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "arrays are not supported with 'no_index'".into(), Position::NONE, ) .into(); @@ -322,33 +322,28 @@ impl Serializer for &mut DynamicSerializer { _variant: &'static str, _len: usize, ) -> Result> { - #[cfg(not(any(feature = "no_object", feature = "no_index")))] + #[cfg(not(feature = "no_object"))] + #[cfg(not(feature = "no_index"))] return Ok(TupleVariantSerializer { variant: _variant, array: Array::with_capacity(_len), }); #[cfg(any(feature = "no_object", feature = "no_index"))] - { - #[cfg(feature = "no_object")] - let err_type = "map"; - #[cfg(not(feature = "no_object"))] - let err_type = "array"; - EvalAltResult::ErrorMismatchOutputType( - "Dynamic".into(), - err_type.into(), - Position::NONE, - ) - .into() - } + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "tuples are not supported with 'no_index' or 'no_object'".into(), + Position::NONE, + ) + .into(); } fn serialize_map(self, _len: Option) -> Result> { #[cfg(not(feature = "no_object"))] return Ok(DynamicSerializer::new(Map::new().into())); #[cfg(feature = "no_object")] - return EvalAltResult::ErrorMismatchOutputType( - "Dynamic".into(), - "map".into(), + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), Position::NONE, ) .into(); @@ -375,9 +370,9 @@ impl Serializer for &mut DynamicSerializer { map: Map::with_capacity(_len), }); #[cfg(feature = "no_object")] - return EvalAltResult::ErrorMismatchOutputType( - "Dynamic".into(), - "map".into(), + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), Position::NONE, ) .into(); @@ -400,7 +395,12 @@ impl SerializeSeq for DynamicSerializer { Ok(()) } #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "arrays are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } // Close the sequence. @@ -408,7 +408,12 @@ impl SerializeSeq for DynamicSerializer { #[cfg(not(feature = "no_index"))] return Ok(self._value); #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "arrays are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } } @@ -428,14 +433,24 @@ impl SerializeTuple for DynamicSerializer { Ok(()) } #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "tuples are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } fn end(self) -> Result> { #[cfg(not(feature = "no_index"))] return Ok(self._value); #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "tuples are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } } @@ -455,14 +470,24 @@ impl SerializeTupleStruct for DynamicSerializer { Ok(()) } #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "tuples are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } fn end(self) -> Result> { #[cfg(not(feature = "no_index"))] return Ok(self._value); #[cfg(feature = "no_index")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "tuples are not supported with 'no_index'".into(), + Position::NONE, + ) + .into(); } } @@ -477,7 +502,12 @@ impl SerializeMap for DynamicSerializer { Ok(()) } #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } fn serialize_value( @@ -489,7 +519,7 @@ impl SerializeMap for DynamicSerializer { let key = crate::stdlib::mem::take(&mut self._key) .take_immutable_string() .map_err(|typ| { - EvalAltResult::ErrorMismatchOutputType( + EvalAltResult::ErrorMismatchDataType( "string".into(), typ.into(), Position::NONE, @@ -501,7 +531,12 @@ impl SerializeMap for DynamicSerializer { Ok(()) } #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } fn serialize_entry( @@ -513,7 +548,7 @@ impl SerializeMap for DynamicSerializer { { let _key: Dynamic = _key.serialize(&mut *self)?; let _key = _key.take_immutable_string().map_err(|typ| { - EvalAltResult::ErrorMismatchOutputType("string".into(), typ.into(), Position::NONE) + EvalAltResult::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE) })?; let _value = _value.serialize(&mut *self)?; let map = self._value.downcast_mut::().unwrap(); @@ -521,14 +556,24 @@ impl SerializeMap for DynamicSerializer { Ok(()) } #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } fn end(self) -> Result> { #[cfg(not(feature = "no_object"))] return Ok(self._value); #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } } @@ -549,14 +594,24 @@ impl SerializeStruct for DynamicSerializer { Ok(()) } #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } fn end(self) -> Result> { #[cfg(not(feature = "no_object"))] return Ok(self._value); #[cfg(feature = "no_object")] - unreachable!() + return EvalAltResult::ErrorMismatchDataType( + "".into(), + "object maps are not supported with 'no_object'".into(), + Position::NONE, + ) + .into(); } } diff --git a/src/token.rs b/src/token.rs index 1d3fbead..c10c1ba4 100644 --- a/src/token.rs +++ b/src/token.rs @@ -437,7 +437,7 @@ impl Token { #[cfg(not(feature = "no_module"))] As => "as", EOF => "{EOF}", - _ => unreachable!("operator should be match in outer scope"), + _ => unreachable!("operator should be matched in outer scope"), } .into(), } @@ -837,7 +837,7 @@ pub fn parse_string_literal( 'x' => 2, 'u' => 4, 'U' => 8, - _ => unreachable!(), + _ => unreachable!("expecting 'x', 'u' or 'U', but gets {}", ch), }; for _ in 0..len { @@ -1126,14 +1126,14 @@ fn get_next_token_inner( 'x' | 'X' => is_hex_char, 'o' | 'O' => is_octal_char, 'b' | 'B' => is_binary_char, - _ => unreachable!(), + _ => unreachable!("expecting 'x', 'o' or 'B', but gets {}", ch), }; radix_base = Some(match ch { 'x' | 'X' => 16, 'o' | 'O' => 8, 'b' | 'B' => 2, - _ => unreachable!(), + _ => unreachable!("expecting 'x', 'o' or 'B', but gets {}", ch), }); while let Some(next_char_in_escape_seq) = stream.peek_next() { @@ -1494,8 +1494,6 @@ fn get_next_token_inner( ('$', _) => return Some((Token::Reserved("$".into()), start_pos)), - ('\0', _) => unreachable!(), - (ch, _) if ch.is_whitespace() => (), #[cfg(feature = "unicode-xid-ident")] (ch, _) if unicode_xid::UnicodeXID::is_xid_start(ch) => { @@ -1749,7 +1747,7 @@ impl<'a> Iterator for TokenIterator<'a, '_> { Some((Token::Custom(token.syntax().into()), pos)) } else { // Active standard keyword - should never be a custom keyword! - unreachable!("{:?}", token) + unreachable!("{:?} is an active keyword", token) } } // Disabled symbol