diff --git a/Cargo.toml b/Cargo.toml index fe543553..61609161 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,12 @@ include = [ num-traits = "*" [features] +default = [] debug_msgs = [] -no_stdlib = [] unchecked = [] +no_stdlib = [] +no_index = [] + +[profile.release] +lto = "fat" +codegen-units = 1 diff --git a/README.md b/README.md index 70555b38..6cf47caf 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Optional features | `debug_msgs` | Print debug messages to stdout (using `println!`) related to function registrations and function calls. | | `no_stdlib` | Exclude the standard library of utility functions in the build, and only include the minimum necessary functionalities. | | `unchecked` | Exclude arithmetic checking in the standard library. Beware that a bad script may panic the entire system! | +| `no_index` | Disable arrays and indexing features | Related ------- @@ -606,7 +607,7 @@ let booly = !true; Numeric functions ----------------- -The following standard functions (defined in the standard library but excluded if `no_stdlib`) operate on `i8`, `i16`, `i32`, `i64`, `f32` and `f64` only: +The following standard functions (defined in the standard library but excluded if [`no_stdlib`](#optional-features)) operate on `i8`, `i16`, `i32`, `i64`, `f32` and `f64` only: | Function | Description | | ---------- | ----------------------------------- | @@ -617,7 +618,7 @@ The following standard functions (defined in the standard library but excluded i Floating-point functions ------------------------ -The following standard functions (defined in the standard library but excluded if `no_stdlib`) operate on `f64` only: +The following standard functions (defined in the standard library but excluded if [`no_stdlib`](#optional-features)) operate on `f64` only: | Category | Functions | | ---------------- | ------------------------------------------------------------ | @@ -645,7 +646,7 @@ let age = 42; let record = full_name + ": age " + age; record == "Bob C. Davis: age 42"; -// Strings can be indexed to get a character +// Strings can be indexed to get a character (disabled with the 'no_index' feature) let c = record[4]; c == 'C'; @@ -669,7 +670,7 @@ record[4] = '\x58'; // 0x58 = 'X' record == "Bob X. Davis: age 42 ❤\n"; ``` -The following standard functions (defined in the standard library but excluded if `no_stdlib`) operate on strings: +The following standard functions (defined in the standard library but excluded if [`no_stdlib`](#optional-features)) operate on strings: | Function | Description | | ---------- | ------------------------------------------------------------------------ | @@ -716,7 +717,7 @@ Arrays You can create arrays of values, and then access them with numeric indices. -The following functions (defined in the standard library but excluded if `no_stdlib`) operate on arrays: +The following functions (defined in the standard library but excluded if [`no_stdlib`](#optional-features)) operate on arrays: | Function | Description | | ---------- | ------------------------------------------------------------------------------------- | @@ -788,6 +789,8 @@ engine.register_fn("push", The type of a Rhai array is `rhai::Array`. `type_of()` returns `"array"`. +Arrays are disabled via the [`no_index`](#optional-features) feature. + Comparison operators -------------------- diff --git a/src/api.rs b/src/api.rs index 9989af7b..ac9914d1 100644 --- a/src/api.rs +++ b/src/api.rs @@ -104,8 +104,7 @@ impl<'e> Engine<'e> { parse(&mut tokens.peekable(), self.optimize) } - /// Compile a file into an AST. - pub fn compile_file(&self, filename: &str) -> Result { + fn read_file(filename: &str) -> Result { let mut f = File::open(filename) .map_err(|err| EvalAltResult::ErrorReadingScriptFile(filename.into(), err))?; @@ -113,19 +112,18 @@ impl<'e> Engine<'e> { f.read_to_string(&mut contents) .map_err(|err| EvalAltResult::ErrorReadingScriptFile(filename.into(), err)) - .and_then(|_| self.compile(&contents).map_err(EvalAltResult::ErrorParsing)) + .map(|_| contents) + } + + /// Compile a file into an AST. + pub fn compile_file(&self, filename: &str) -> Result { + Self::read_file(filename) + .and_then(|contents| self.compile(&contents).map_err(|err| err.into())) } /// Evaluate a file. pub fn eval_file(&mut self, filename: &str) -> Result { - let mut f = File::open(filename) - .map_err(|err| EvalAltResult::ErrorReadingScriptFile(filename.into(), err))?; - - let mut contents = String::new(); - - f.read_to_string(&mut contents) - .map_err(|err| EvalAltResult::ErrorReadingScriptFile(filename.into(), err)) - .and_then(|_| self.eval::(&contents)) + Self::read_file(filename).and_then(|contents| self.eval::(&contents)) } /// Evaluate a string. @@ -164,27 +162,36 @@ impl<'e> Engine<'e> { retain_functions: bool, ast: &AST, ) -> Result { - let AST(statements, functions) = ast; + fn eval_ast_internal( + engine: &mut Engine, + scope: &mut Scope, + retain_functions: bool, + ast: &AST, + ) -> Result { + let AST(statements, functions) = ast; - functions.iter().for_each(|f| { - self.script_functions.insert( - FnSpec { - name: f.name.clone().into(), - args: None, - }, - Arc::new(FnIntExt::Int(f.clone())), - ); - }); + functions.iter().for_each(|f| { + engine.script_functions.insert( + FnSpec { + name: f.name.clone().into(), + args: None, + }, + Arc::new(FnIntExt::Int(f.clone())), + ); + }); - let result = statements - .iter() - .try_fold(().into_dynamic(), |_, stmt| self.eval_stmt(scope, stmt)); + let result = statements + .iter() + .try_fold(().into_dynamic(), |_, stmt| engine.eval_stmt(scope, stmt)); - if !retain_functions { - self.clear_functions(); + if !retain_functions { + engine.clear_functions(); + } + + result } - match result { + match eval_ast_internal(self, scope, retain_functions, ast) { Err(EvalAltResult::Return(out, pos)) => out.downcast::().map(|v| *v).map_err(|a| { EvalAltResult::ErrorMismatchOutputType( self.map_type_name((*a).type_name()).to_string(), @@ -285,45 +292,45 @@ impl<'e> Engine<'e> { ast: &AST, args: A, ) -> Result { + fn call_fn_internal( + engine: &mut Engine, + name: &str, + ast: &AST, + args: FnCallArgs, + ) -> Result { + ast.1.iter().for_each(|f| { + engine.script_functions.insert( + FnSpec { + name: f.name.clone().into(), + args: None, + }, + Arc::new(FnIntExt::Int(f.clone())), + ); + }); + + let result = engine.call_fn_raw(name, args, None, Position::none()); + + engine.clear_functions(); + + result + } + let mut arg_values = args.into_vec(); - self.call_fn_internal( + call_fn_internal( + self, name, ast, arg_values.iter_mut().map(|v| v.as_mut()).collect(), ) - } - - pub(crate) fn call_fn_internal( - &mut self, - name: &str, - ast: &AST, - args: FnCallArgs, - ) -> Result { - let pos = Default::default(); - - ast.1.iter().for_each(|f| { - self.script_functions.insert( - FnSpec { - name: f.name.clone().into(), - args: None, - }, - Arc::new(FnIntExt::Int(f.clone())), - ); - }); - - let result = self.call_fn_raw(name, args, None, pos).and_then(|b| { + .and_then(|b| { b.downcast().map(|b| *b).map_err(|a| { EvalAltResult::ErrorMismatchOutputType( self.map_type_name((*a).type_name()).into(), - pos, + Position::none(), ) }) - }); - - self.clear_functions(); - - result + }) } /// Override default action of `print` (print to stdout using `println!`) diff --git a/src/builtin.rs b/src/builtin.rs index 6cce507e..02e64581 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -2,8 +2,12 @@ //! _standard library_ of utility functions. use crate::any::Any; -use crate::engine::{Array, Engine}; +use crate::engine::Engine; use crate::fn_register::RegisterFn; + +#[cfg(not(feature = "no_index"))] +use crate::engine::Array; + use std::{ fmt::{Debug, Display}, i32, i64, @@ -15,14 +19,13 @@ use std::{ use std::ops::{Shl, Shr}; #[cfg(not(feature = "unchecked"))] -use crate::{parser::Position, result::EvalAltResult, RegisterResultFn}; - -#[cfg(not(feature = "unchecked"))] -use std::convert::TryFrom; - -#[cfg(not(feature = "unchecked"))] -use num_traits::{ - CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, CheckedSub, +use { + crate::{parser::Position, result::EvalAltResult, RegisterResultFn}, + num_traits::{ + CheckedAdd, CheckedDiv, CheckedMul, CheckedNeg, CheckedRem, CheckedShl, CheckedShr, + CheckedSub, + }, + std::convert::TryFrom, }; macro_rules! reg_op { @@ -102,6 +105,7 @@ macro_rules! reg_func2y { } #[cfg(not(feature = "no_stdlib"))] +#[cfg(not(feature = "no_index"))] macro_rules! reg_func3 { ($self:expr, $x:expr, $op:expr, $v:ty, $w:ty, $r:ty, $( $y:ty ),*) => ( $( @@ -438,19 +442,23 @@ impl Engine<'_> { reg_func1!(self, "print", print, String, i8, u8, i16, u16); reg_func1!(self, "print", print, String, i32, i64, u32, u64); reg_func1!(self, "print", print, String, f32, f64, bool, char, String); - reg_func1!(self, "print", print_debug, String, Array); self.register_fn("print", || "".to_string()); self.register_fn("print", |_: ()| "".to_string()); reg_func1!(self, "debug", print_debug, String, i8, u8, i16, u16); reg_func1!(self, "debug", print_debug, String, i32, i64, u32, u64); reg_func1!(self, "debug", print_debug, String, f32, f64, bool, char); - reg_func1!(self, "debug", print_debug, String, String, Array, ()); - // Register array iterator - self.register_iterator::(|a| { - Box::new(a.downcast_ref::().unwrap().clone().into_iter()) - }); + #[cfg(not(feature = "no_index"))] + { + reg_func1!(self, "print", print_debug, String, Array); + reg_func1!(self, "debug", print_debug, String, String, Array, ()); + + // Register array iterator + self.register_iterator::(|a| { + Box::new(a.downcast_ref::().unwrap().clone().into_iter()) + }); + } // Register range function self.register_iterator::, _>(|a| { @@ -468,6 +476,7 @@ impl Engine<'_> { /// Register the built-in library. #[cfg(not(feature = "no_stdlib"))] pub(crate) fn register_stdlib(&mut self) { + #[cfg(not(feature = "no_index"))] use crate::fn_register::RegisterDynamicFn; // Advanced math functions @@ -547,43 +556,46 @@ impl Engine<'_> { self.register_fn("to_int", |x: f64| x as i64); } - // Register array utility functions - fn push(list: &mut Array, item: T) { - list.push(Box::new(item)); - } - fn pad(list: &mut Array, len: i64, item: T) { - if len >= 0 { - while list.len() < len as usize { - push(list, item.clone()); + #[cfg(not(feature = "no_index"))] + { + // Register array utility functions + fn push(list: &mut Array, item: T) { + list.push(Box::new(item)); + } + fn pad(list: &mut Array, len: i64, item: T) { + if len >= 0 { + while list.len() < len as usize { + push(list, item.clone()); + } } } + + reg_func2x!(self, "push", push, &mut Array, (), i8, u8, i16, u16); + reg_func2x!(self, "push", push, &mut Array, (), i32, i64, u32, u64); + reg_func2x!(self, "push", push, &mut Array, (), f32, f64, bool, char); + reg_func2x!(self, "push", push, &mut Array, (), String, Array, ()); + reg_func3!(self, "pad", pad, &mut Array, i64, (), i8, u8, i16, u16); + reg_func3!(self, "pad", pad, &mut Array, i64, (), i32, u32, f32); + reg_func3!(self, "pad", pad, &mut Array, i64, (), i64, u64, f64); + reg_func3!(self, "pad", pad, &mut Array, i64, (), bool, char); + reg_func3!(self, "pad", pad, &mut Array, i64, (), String, Array, ()); + + self.register_dynamic_fn("pop", |list: &mut Array| { + list.pop().unwrap_or_else(|| ().into_dynamic()) + }); + self.register_dynamic_fn("shift", |list: &mut Array| match list.len() { + 0 => ().into_dynamic(), + _ => list.remove(0), + }); + self.register_fn("len", |list: &mut Array| list.len() as i64); + self.register_fn("clear", |list: &mut Array| list.clear()); + self.register_fn("truncate", |list: &mut Array, len: i64| { + if len >= 0 { + list.truncate(len as usize); + } + }); } - reg_func2x!(self, "push", push, &mut Array, (), i8, u8, i16, u16); - reg_func2x!(self, "push", push, &mut Array, (), i32, i64, u32, u64); - reg_func2x!(self, "push", push, &mut Array, (), f32, f64, bool, char); - reg_func2x!(self, "push", push, &mut Array, (), String, Array, ()); - reg_func3!(self, "pad", pad, &mut Array, i64, (), i8, u8, i16, u16); - reg_func3!(self, "pad", pad, &mut Array, i64, (), i32, u32, f32); - reg_func3!(self, "pad", pad, &mut Array, i64, (), i64, u64, f64); - reg_func3!(self, "pad", pad, &mut Array, i64, (), bool, char); - reg_func3!(self, "pad", pad, &mut Array, i64, (), String, Array, ()); - - self.register_dynamic_fn("pop", |list: &mut Array| { - list.pop().unwrap_or_else(|| ().into_dynamic()) - }); - self.register_dynamic_fn("shift", |list: &mut Array| match list.len() { - 0 => ().into_dynamic(), - _ => list.remove(0), - }); - self.register_fn("len", |list: &mut Array| list.len() as i64); - self.register_fn("clear", |list: &mut Array| list.clear()); - self.register_fn("truncate", |list: &mut Array, len: i64| { - if len >= 0 { - list.truncate(len as usize); - } - }); - // Register string concatenate functions fn prepend(x: T, y: String) -> String { format!("{}{}", x, y) @@ -596,16 +608,20 @@ impl Engine<'_> { self, "+", append, String, String, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, bool, char ); - self.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y)); self.register_fn("+", |x: String, _: ()| format!("{}", x)); reg_func2y!( self, "+", prepend, String, String, i8, u8, i16, u16, i32, i64, u32, u64, f32, f64, bool, char ); - self.register_fn("+", |x: Array, y: String| format!("{:?}{}", x, y)); self.register_fn("+", |_: (), y: String| format!("{}", y)); + #[cfg(not(feature = "no_index"))] + { + self.register_fn("+", |x: String, y: Array| format!("{}{:?}", x, y)); + self.register_fn("+", |x: Array, y: String| format!("{:?}{}", x, y)); + } + // Register string utility functions self.register_fn("len", |s: &mut String| s.chars().count() as i64); self.register_fn("contains", |s: &mut String, ch: char| s.contains(ch)); diff --git a/src/engine.rs b/src/engine.rs index 89dac01c..4ac2d67e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -14,6 +14,7 @@ use std::{ }; /// An dynamic array of `Dynamic` values. +#[cfg(not(feature = "no_index"))] pub type Array = Vec; pub type FnCallArgs<'a> = Vec<&'a mut Variant>; @@ -29,6 +30,7 @@ pub(crate) const FUNC_GETTER: &'static str = "get$"; pub(crate) const FUNC_SETTER: &'static str = "set$"; #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] +#[cfg(not(feature = "no_index"))] enum IndexSourceType { Array, String, @@ -82,8 +84,9 @@ impl Engine<'_> { // User-friendly names for built-in types let type_names = [ (type_name::(), "string"), - (type_name::(), "array"), (type_name::(), "dynamic"), + #[cfg(not(feature = "no_index"))] + (type_name::(), "array"), ] .iter() .map(|(k, v)| (k.to_string(), v.to_string())) @@ -251,7 +254,7 @@ impl Engine<'_> { match dot_rhs { // xxx.fn_name(args) Expr::FunctionCall(fn_name, args, def_val, pos) => { - let mut args: Array = args + let mut args = args .iter() .map(|arg| self.eval_expr(scope, arg)) .collect::, _>>()?; @@ -271,6 +274,7 @@ impl Engine<'_> { } // xxx.idx_lhs[idx_expr] + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, idx_expr, idx_pos) => { let (expr, _) = match idx_lhs.as_ref() { // xxx.id[idx_expr] @@ -309,6 +313,7 @@ impl Engine<'_> { .and_then(|mut v| self.get_dot_val_helper(scope, v.as_mut(), rhs)) } // xxx.idx_lhs[idx_expr].rhs + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, idx_expr, idx_pos) => { let (expr, _) = match idx_lhs.as_ref() { // xxx.id[idx_expr].rhs @@ -371,6 +376,7 @@ impl Engine<'_> { } // idx_lhs[idx_expr].??? + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, idx_expr, idx_pos) => { let (src_type, src, idx, mut target) = self.eval_index_expr(scope, idx_lhs, idx_expr, *idx_pos)?; @@ -414,6 +420,7 @@ impl Engine<'_> { } /// Evaluate the value of an index (must evaluate to i64) + #[cfg(not(feature = "no_index"))] fn eval_index_value( &mut self, scope: &mut Scope, @@ -426,6 +433,7 @@ impl Engine<'_> { } /// Get the value at the indexed position of a base type + #[cfg(not(feature = "no_index"))] fn get_indexed_value( &self, val: Dynamic, @@ -473,6 +481,7 @@ impl Engine<'_> { } /// Evaluate an index expression + #[cfg(not(feature = "no_index"))] fn eval_index_expr<'a>( &mut self, scope: &mut Scope, @@ -505,6 +514,7 @@ impl Engine<'_> { } /// Replace a character at an index position in a mutable string + #[cfg(not(feature = "no_index"))] fn str_replace_char(s: &mut String, idx: usize, new_ch: char) { let mut chars: Vec = s.chars().collect(); let ch = *chars.get(idx).expect("string index out of bounds"); @@ -518,6 +528,7 @@ impl Engine<'_> { } /// Update the value at an index position in a variable inside the scope + #[cfg(not(feature = "no_index"))] fn update_indexed_var_in_scope( src_type: IndexSourceType, scope: &mut Scope, @@ -550,6 +561,7 @@ impl Engine<'_> { } /// Update the value at an index position + #[cfg(not(feature = "no_index"))] fn update_indexed_value( mut target: Dynamic, idx: usize, @@ -593,6 +605,7 @@ impl Engine<'_> { // xxx.lhs[idx_expr] // TODO - Allow chaining of indexing! + #[cfg(not(feature = "no_index"))] Expr::Index(lhs, idx_expr, idx_pos) => match lhs.as_ref() { // xxx.id[idx_expr] Expr::Identifier(id, pos) => { @@ -636,6 +649,7 @@ impl Engine<'_> { // xxx.lhs[idx_expr].rhs // TODO - Allow chaining of indexing! + #[cfg(not(feature = "no_index"))] Expr::Index(lhs, idx_expr, idx_pos) => match lhs.as_ref() { // xxx.id[idx_expr].rhs Expr::Identifier(id, pos) => { @@ -720,6 +734,7 @@ impl Engine<'_> { // lhs[idx_expr].??? // TODO - Allow chaining of indexing! + #[cfg(not(feature = "no_index"))] Expr::Index(lhs, idx_expr, idx_pos) => { let (src_type, src, idx, mut target) = self.eval_index_expr(scope, lhs, idx_expr, *idx_pos)?; @@ -762,6 +777,7 @@ impl Engine<'_> { } // lhs[idx_expr] + #[cfg(not(feature = "no_index"))] Expr::Index(lhs, idx_expr, idx_pos) => self .eval_index_expr(scope, lhs, idx_expr, *idx_pos) .map(|(_, _, _, x)| x), @@ -785,6 +801,7 @@ impl Engine<'_> { } // idx_lhs[idx_expr] = rhs + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, idx_expr, idx_pos) => { let (src_type, src, idx, _) = self.eval_index_expr(scope, idx_lhs, idx_expr, *idx_pos)?; @@ -818,6 +835,7 @@ impl Engine<'_> { Expr::Dot(lhs, rhs, _) => self.get_dot_val(scope, lhs, rhs), + #[cfg(not(feature = "no_index"))] Expr::Array(contents, _) => { let mut arr = Vec::new(); @@ -836,7 +854,7 @@ impl Engine<'_> { let mut args = args .iter() .map(|expr| self.eval_expr(scope, expr)) - .collect::>()?; + .collect::, _>>()?; self.call_fn_raw( fn_name, diff --git a/src/lib.rs b/src/lib.rs index 56df1ae2..fb23e27c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,9 +75,12 @@ mod scope; pub use any::{Any, AnyExt, Dynamic, Variant}; pub use call::FuncArgs; -pub use engine::{Array, Engine}; +pub use engine::Engine; pub use error::{ParseError, ParseErrorType}; pub use fn_register::{RegisterDynamicFn, RegisterFn, RegisterResultFn}; pub use parser::{Position, AST}; pub use result::EvalAltResult; pub use scope::Scope; + +#[cfg(not(feature = "no_index"))] +pub use engine::Array; diff --git a/src/optimize.rs b/src/optimize.rs index 4a0b26b1..0f2eb585 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -139,11 +139,24 @@ fn optimize_expr(expr: Expr, changed: &mut bool) -> Expr { Box::new(optimize_expr(*rhs, changed)), pos, ), - Expr::Index(lhs, rhs, pos) => Expr::Index( - Box::new(optimize_expr(*lhs, changed)), - Box::new(optimize_expr(*rhs, changed)), - pos, - ), + #[cfg(not(feature = "no_index"))] + Expr::Index(lhs, rhs, pos) => match (*lhs, *rhs) { + (Expr::Array(mut items, _), Expr::IntegerConstant(i, _)) + if i >= 0 + && (i as usize) < items.len() + && !items.iter().any(|x| x.is_constant()) => + { + // Array where everything is a constant - promote the item + *changed = true; + items.remove(i as usize) + } + (lhs, rhs) => Expr::Index( + Box::new(optimize_expr(lhs, changed)), + Box::new(optimize_expr(rhs, changed)), + pos, + ), + }, + #[cfg(not(feature = "no_index"))] Expr::Array(items, pos) => { let original_len = items.len(); diff --git a/src/parser.rs b/src/parser.rs index 10e629d0..9009305b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -167,7 +167,9 @@ pub enum Expr { FunctionCall(String, Vec, Option, Position), Assignment(Box, Box, Position), Dot(Box, Box, Position), + #[cfg(not(feature = "no_index"))] Index(Box, Box, Position), + #[cfg(not(feature = "no_index"))] Array(Vec, Position), And(Box, Box), Or(Box, Box), @@ -186,16 +188,19 @@ impl Expr { | Expr::StringConstant(_, pos) | Expr::FunctionCall(_, _, _, pos) | Expr::Stmt(_, pos) - | Expr::Array(_, pos) | Expr::True(pos) | Expr::False(pos) | Expr::Unit(pos) => *pos, - Expr::Index(e, _, _) - | Expr::Assignment(e, _, _) - | Expr::Dot(e, _, _) - | Expr::And(e, _) - | Expr::Or(e, _) => e.position(), + Expr::Assignment(e, _, _) | Expr::Dot(e, _, _) | Expr::And(e, _) | Expr::Or(e, _) => { + e.position() + } + + #[cfg(not(feature = "no_index"))] + Expr::Index(e, _, _) => e.position(), + + #[cfg(not(feature = "no_index"))] + Expr::Array(_, pos) => *pos, } } @@ -1166,6 +1171,7 @@ fn parse_call_expr<'a>( } } +#[cfg(not(feature = "no_index"))] fn parse_index_expr<'a>( lhs: Box, input: &mut Peekable>, @@ -1260,6 +1266,7 @@ fn parse_ident_expr<'a>( input.next(); parse_call_expr(id, input, begin) } + #[cfg(not(feature = "no_index"))] Some(&(Token::LeftBracket, pos)) => { input.next(); parse_index_expr(Box::new(Expr::Identifier(id, begin)), input, pos) @@ -1269,6 +1276,7 @@ fn parse_ident_expr<'a>( } } +#[cfg(not(feature = "no_index"))] fn parse_array_expr<'a>( input: &mut Peekable>, begin: Position, @@ -1320,26 +1328,28 @@ fn parse_primary<'a>(input: &mut Peekable>) -> Result Ok(Expr::IntegerConstant(x, pos)), Some((Token::FloatConstant(x), pos)) => Ok(Expr::FloatConstant(x, pos)), Some((Token::CharConstant(c), pos)) => Ok(Expr::CharConstant(c, pos)), Some((Token::StringConst(s), pos)) => { - follow_on = true; + can_be_indexed = true; Ok(Expr::StringConstant(s, pos)) } Some((Token::Identifier(s), pos)) => { - follow_on = true; + can_be_indexed = true; parse_ident_expr(s, input, pos) } Some((Token::LeftParen, pos)) => { - follow_on = true; + can_be_indexed = true; parse_paren_expr(input, pos) } + #[cfg(not(feature = "no_index"))] Some((Token::LeftBracket, pos)) => { - follow_on = true; + can_be_indexed = true; parse_array_expr(input, pos) } Some((Token::True, pos)) => Ok(Expr::True(pos)), @@ -1354,14 +1364,13 @@ fn parse_primary<'a>(input: &mut Peekable>) -> Result Err(ParseError::new(PERR::InputPastEndOfFile, Position::eof())), }?; - if !follow_on { - return Ok(root_expr); - } - - // Tail processing all possible indexing - while let Some(&(Token::LeftBracket, pos)) = input.peek() { - input.next(); - root_expr = parse_index_expr(Box::new(root_expr), input, pos)?; + if can_be_indexed { + // Tail processing all possible indexing + #[cfg(not(feature = "no_index"))] + while let Some(&(Token::LeftBracket, pos)) = input.peek() { + input.next(); + root_expr = parse_index_expr(Box::new(root_expr), input, pos)?; + } } Ok(root_expr) @@ -1408,6 +1417,7 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result (true, *pos), + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, _, _) => match idx_lhs.as_ref() { Expr::Identifier(_, _) => (true, idx_lhs.position()), _ => (false, idx_lhs.position()), @@ -1415,10 +1425,13 @@ fn parse_assignment(lhs: Expr, rhs: Expr, pos: Position) -> Result match dot_lhs.as_ref() { Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs), + + #[cfg(not(feature = "no_index"))] Expr::Index(idx_lhs, _, _) => match idx_lhs.as_ref() { Expr::Identifier(_, _) => valid_assignment_chain(dot_rhs), _ => (false, idx_lhs.position()), }, + _ => (false, dot_lhs.position()), }, diff --git a/src/result.rs b/src/result.rs index 224c8232..f95e4b6a 100644 --- a/src/result.rs +++ b/src/result.rs @@ -173,6 +173,12 @@ impl From for EvalAltResult { } } +impl> From for EvalAltResult { + fn from(err: T) -> Self { + Self::ErrorRuntime(err.as_ref().to_string(), Position::none()) + } +} + impl EvalAltResult { pub fn position(&self) -> Position { match self { @@ -225,9 +231,3 @@ impl EvalAltResult { } } } - -impl> From for EvalAltResult { - fn from(err: T) -> Self { - Self::ErrorRuntime(err.as_ref().to_string(), Position::none()) - } -} diff --git a/src/scope.rs b/src/scope.rs index 2e2c492b..d097f422 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -93,6 +93,7 @@ impl<'a> Scope<'a> { } /// Get a mutable reference to a variable in the Scope and downcast it to a specific type + #[cfg(not(feature = "no_index"))] pub(crate) fn get_mut_by_type(&mut self, key: &str, index: usize) -> &mut T { self.get_mut(key, index) .downcast_mut::()