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