Merge branch 'master' into plugins

This commit is contained in:
Stephen Chung
2020-06-15 21:52:15 +08:00
14 changed files with 494 additions and 175 deletions

View File

@@ -751,7 +751,6 @@ impl Engine {
) -> Result<AST, ParseError> {
let scripts = [script];
let stream = lex(&scripts, self.max_string_size);
{
let mut peekable = stream.peekable();
self.parse_global_expr(&mut peekable, scope, self.optimization_level)
@@ -906,11 +905,8 @@ impl Engine {
let scripts = [script];
let stream = lex(&scripts, self.max_string_size);
let ast = self.parse_global_expr(
&mut stream.peekable(),
scope,
OptimizationLevel::None, // No need to optimize a lone expression
)?;
// No need to optimize a lone expression
let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?;
self.eval_ast_with_scope(scope, &ast)
}
@@ -983,6 +979,7 @@ impl Engine {
});
}
/// Evaluate an `AST` with own scope.
pub(crate) fn eval_ast_with_scope_raw(
&self,
scope: &mut Scope,
@@ -1035,7 +1032,6 @@ impl Engine {
) -> Result<(), Box<EvalAltResult>> {
let scripts = [script];
let stream = lex(&scripts, self.max_string_size);
let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?;
self.consume_ast_with_scope(scope, &ast)
}

View File

@@ -63,16 +63,9 @@ pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
#[cfg(feature = "unchecked")]
pub const MAX_CALL_STACK_DEPTH: usize = usize::MAX;
#[cfg(feature = "unchecked")]
pub const MAX_EXPR_DEPTH: usize = usize::MAX;
pub const MAX_EXPR_DEPTH: usize = 0;
#[cfg(feature = "unchecked")]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = usize::MAX;
#[cfg(feature = "unchecked")]
pub const MAX_STRING_SIZE: usize = usize::MAX;
#[cfg(feature = "unchecked")]
pub const MAX_ARRAY_SIZE: usize = usize::MAX;
#[cfg(feature = "unchecked")]
pub const MAX_MAP_SIZE: usize = usize::MAX;
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 0;
pub const KEYWORD_PRINT: &str = "print";
pub const KEYWORD_DEBUG: &str = "debug";
@@ -189,7 +182,7 @@ pub struct State {
/// Number of operations performed.
pub operations: u64,
/// Number of modules loaded.
pub modules: u64,
pub modules: usize,
}
impl State {
@@ -268,7 +261,7 @@ pub struct Engine {
/// Maximum number of operations allowed to run.
pub(crate) max_operations: u64,
/// Maximum number of modules allowed to load.
pub(crate) max_modules: u64,
pub(crate) max_modules: usize,
/// Maximum length of a string.
pub(crate) max_string_size: usize,
/// Maximum length of an array.
@@ -309,11 +302,11 @@ impl Default for Engine {
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH,
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
max_operations: u64::MAX,
max_modules: u64::MAX,
max_string_size: usize::MAX,
max_array_size: usize::MAX,
max_map_size: usize::MAX,
max_operations: 0,
max_modules: usize::MAX,
max_string_size: 0,
max_array_size: 0,
max_map_size: 0,
};
engine.load_package(StandardPackage::new().get());
@@ -456,11 +449,11 @@ impl Engine {
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
max_expr_depth: MAX_EXPR_DEPTH,
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
max_operations: u64::MAX,
max_modules: u64::MAX,
max_string_size: usize::MAX,
max_array_size: usize::MAX,
max_map_size: usize::MAX,
max_operations: 0,
max_modules: usize::MAX,
max_string_size: 0,
max_array_size: 0,
max_map_size: 0,
}
}
@@ -501,17 +494,13 @@ impl Engine {
/// consuming too much resources (0 for unlimited).
#[cfg(not(feature = "unchecked"))]
pub fn set_max_operations(&mut self, operations: u64) {
self.max_operations = if operations == 0 {
u64::MAX
} else {
operations
};
self.max_operations = operations;
}
/// Set the maximum number of imported modules allowed for a script (0 for unlimited).
/// Set the maximum number of imported modules allowed for a script.
#[cfg(not(feature = "unchecked"))]
pub fn set_max_modules(&mut self, modules: u64) {
self.max_modules = if modules == 0 { u64::MAX } else { modules };
pub fn set_max_modules(&mut self, modules: usize) {
self.max_modules = modules;
}
/// Set the depth limits for expressions/statements (0 for unlimited).
@@ -656,7 +645,7 @@ impl Engine {
return Ok((result, false));
} else {
// Run external function
let result = func.get_native_fn()(args)?;
let result = func.get_native_fn()(self, args)?;
// Restore the original reference
restore_first_arg(old_this_ptr, args);
@@ -1485,7 +1474,7 @@ impl Engine {
.or_else(|| self.packages.get_fn(hash_fn))
{
// Overriding exact implementation
func(&mut [lhs_ptr, &mut rhs_val])?;
func(self, &mut [lhs_ptr, &mut rhs_val])?;
} else if run_builtin_op_assignment(op, lhs_ptr, &rhs_val)?.is_none() {
// Not built in, map to `var = var op rhs`
let op = &op[..op.len() - 1]; // extract operator without =
@@ -1717,7 +1706,9 @@ impl Engine {
.map_err(|err| EvalAltResult::new_position(err, *pos))
}
Ok(f) if f.is_plugin_fn() => f.get_plugin_fn().call(args.as_mut(), *pos),
Ok(f) => f.get_native_fn()(args.as_mut()).map_err(|err| err.new_position(*pos)),
Ok(f) => {
f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos))
}
Err(err)
if def_val.is_some()
&& matches!(*err, EvalAltResult::ErrorFunctionNotFound(_, _)) =>
@@ -1773,11 +1764,7 @@ impl Engine {
_ => unreachable!(),
};
if let Ok(val) = &result {
self.check_data_size(val)?;
}
result
self.check_data_size(result)
}
/// Evaluate a statement
@@ -2046,50 +2033,102 @@ impl Engine {
}
};
if let Ok(val) = &result {
self.check_data_size(val)?;
}
result
self.check_data_size(result)
}
/// Check a `Dynamic` value to ensure that its size is within allowable limit.
fn check_data_size(&self, value: &Dynamic) -> Result<(), Box<EvalAltResult>> {
/// Check a result to ensure that the data size is within allowable limit.
fn check_data_size(
&self,
result: Result<Dynamic, Box<EvalAltResult>>,
) -> Result<Dynamic, Box<EvalAltResult>> {
#[cfg(feature = "unchecked")]
return Ok(());
return result;
match value {
Dynamic(Union::Str(s))
if self.max_string_size > 0 && s.len() > self.max_string_size =>
{
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(),
self.max_string_size,
s.len(),
Position::none(),
)))
// If no data size limits, just return
if self.max_string_size + self.max_array_size + self.max_map_size == 0 {
return result;
}
// Recursively calculate the size of a value (especially `Array` and `Map`)
fn calc_size(value: &Dynamic) -> (usize, usize, usize) {
match value {
#[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(arr)) => {
let mut arrays = 0;
let mut maps = 0;
arr.iter().for_each(|value| match value {
Dynamic(Union::Array(_)) | Dynamic(Union::Map(_)) => {
let (a, m, _) = calc_size(value);
arrays += a;
maps += m;
}
_ => arrays += 1,
});
(arrays, maps, 0)
}
#[cfg(not(feature = "no_object"))]
Dynamic(Union::Map(map)) => {
let mut arrays = 0;
let mut maps = 0;
map.values().for_each(|value| match value {
Dynamic(Union::Array(_)) | Dynamic(Union::Map(_)) => {
let (a, m, _) = calc_size(value);
arrays += a;
maps += m;
}
_ => maps += 1,
});
(arrays, maps, 0)
}
Dynamic(Union::Str(s)) => (0, 0, s.len()),
_ => (0, 0, 0),
}
}
match result {
// Simply return all errors
Err(_) => return result,
// String with limit
Ok(Dynamic(Union::Str(_))) if self.max_string_size > 0 => (),
// Array with limit
#[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(arr))
if self.max_array_size > 0 && arr.len() > self.max_array_size =>
{
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of array".to_string(),
self.max_array_size,
arr.len(),
Position::none(),
)))
}
Ok(Dynamic(Union::Array(_))) if self.max_array_size > 0 => (),
// Map with limit
#[cfg(not(feature = "no_object"))]
Dynamic(Union::Map(map)) if self.max_map_size > 0 && map.len() > self.max_map_size => {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Number of properties in object map".to_string(),
self.max_map_size,
map.len(),
Position::none(),
)))
}
_ => Ok(()),
Ok(Dynamic(Union::Map(_))) if self.max_map_size > 0 => (),
// Everything else is simply returned
Ok(_) => return result,
};
let (arr, map, s) = calc_size(result.as_ref().unwrap());
if s > self.max_string_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(),
self.max_string_size,
s,
Position::none(),
)))
} else if arr > self.max_array_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(),
self.max_array_size,
arr,
Position::none(),
)))
} else if map > self.max_map_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Number of properties in object map".to_string(),
self.max_map_size,
map,
Position::none(),
)))
} else {
result
}
}
@@ -2101,7 +2140,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))]
{
// Guard against too many operations
if state.operations > self.max_operations {
if self.max_operations > 0 && state.operations > self.max_operations {
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
Position::none(),
)));

View File

@@ -22,8 +22,8 @@ pub enum LexError {
MalformedChar(String),
/// An identifier is in an invalid format.
MalformedIdentifier(String),
/// Bad keyword encountered when tokenizing the script text.
ImproperKeyword(String),
/// Bad symbol encountered when tokenizing the script text.
ImproperSymbol(String),
}
impl Error for LexError {}
@@ -42,11 +42,18 @@ impl fmt::Display for LexError {
"Length of string literal exceeds the maximum limit ({})",
max
),
Self::ImproperKeyword(s) => write!(f, "{}", s),
Self::ImproperSymbol(s) => write!(f, "{}", s),
}
}
}
impl LexError {
/// Convert a `LexError` into a `ParseError`.
pub fn into_err(&self, pos: Position) -> ParseError {
ParseError(Box::new(self.into()), pos)
}
}
/// Type of error encountered when parsing a script.
///
/// Some errors never appear when certain features are turned on.
@@ -217,6 +224,17 @@ impl fmt::Display for ParseErrorType {
}
}
impl From<&LexError> for ParseErrorType {
fn from(err: &LexError) -> Self {
match err {
LexError::StringTooLong(max) => {
Self::LiteralTooLarge("Length of string literal".to_string(), *max)
}
_ => Self::BadInput(err.to_string()),
}
}
}
/// Error when parsing a script.
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct ParseError(pub Box<ParseErrorType>, pub Position);

View File

@@ -1,4 +1,5 @@
use crate::any::Dynamic;
use crate::engine::Engine;
use crate::parser::ScriptFnDef;
use crate::plugin::PluginFunction;
use crate::result::EvalAltResult;
@@ -52,9 +53,10 @@ pub fn shared_take<T: Clone>(value: Shared<T>) -> T {
pub type FnCallArgs<'a> = [&'a mut Dynamic];
#[cfg(not(feature = "sync"))]
pub type FnAny = dyn Fn(&mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
pub type FnAny = dyn Fn(&Engine, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
#[cfg(feature = "sync")]
pub type FnAny = dyn Fn(&mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
pub type FnAny =
dyn Fn(&Engine, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;

View File

@@ -1,5 +1,4 @@
//! Module which defines the function registration mechanism.
#![allow(non_snake_case)]
use crate::any::{Dynamic, Variant};
@@ -206,7 +205,7 @@ macro_rules! make_func {
// ^ function parameter generic type name (A, B, C etc.)
// ^ dereferencing function
Box::new(move |args: &mut FnCallArgs| {
Box::new(move |_: &Engine, args: &mut FnCallArgs| {
// The arguments are assumed to be of the correct number and types!
#[allow(unused_variables, unused_mut)]

View File

@@ -305,6 +305,29 @@ impl Module {
hash_fn
}
/// Set a Rust function taking a reference to the scripting `Engine`, plus a list of
/// mutable `Dynamic` references into the module, returning a hash key.
/// A list of `TypeId`'s is taken as the argument types.
///
/// Use this to register a built-in function which must reference settings on the scripting
/// `Engine` (e.g. to prevent growing an array beyond the allowed maximum size).
///
/// If there is a similar existing Rust function, it is replaced.
pub(crate) fn set_fn_var_args<T: Variant + Clone>(
&mut self,
name: impl Into<String>,
args: &[TypeId],
func: impl Fn(&Engine, &mut [&mut Dynamic]) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |engine: &Engine, args: &mut FnCallArgs| func(engine, args).map(Dynamic::from);
self.set_fn(
name,
Public,
args,
CallableFunction::from_method(Box::new(f)),
)
}
/// Set a Rust function taking no parameters into the module, returning a hash key.
///
/// If there is a similar existing Rust function, it is replaced.
@@ -323,7 +346,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn() -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |_: &mut FnCallArgs| func().map(Dynamic::from);
let f = move |_: &Engine, _: &mut FnCallArgs| func().map(Dynamic::from);
let args = [];
self.set_fn(
name,
@@ -351,8 +374,9 @@ impl Module {
name: impl Into<String>,
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f =
move |args: &mut FnCallArgs| func(mem::take(args[0]).cast::<A>()).map(Dynamic::from);
let f = move |_: &Engine, args: &mut FnCallArgs| {
func(mem::take(args[0]).cast::<A>()).map(Dynamic::from)
};
let args = [TypeId::of::<A>()];
self.set_fn(
name,
@@ -380,7 +404,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
func(args[0].downcast_mut::<A>().unwrap()).map(Dynamic::from)
};
let args = [TypeId::of::<A>()];
@@ -434,7 +458,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(A, B) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
let b = mem::take(args[1]).cast::<B>();
@@ -470,7 +494,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
let a = args[0].downcast_mut::<A>().unwrap();
@@ -561,7 +585,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(A, B, C) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
@@ -603,7 +627,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(&mut A, B, C) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
let a = args[0].downcast_mut::<A>().unwrap();
@@ -640,7 +664,7 @@ impl Module {
&mut self,
func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<A>();
let a = args[0].downcast_mut::<A>().unwrap();
@@ -682,7 +706,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let a = mem::take(args[0]).cast::<A>();
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
@@ -731,7 +755,7 @@ impl Module {
name: impl Into<String>,
func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
) -> u64 {
let f = move |args: &mut FnCallArgs| {
let f = move |_: &Engine, args: &mut FnCallArgs| {
let b = mem::take(args[1]).cast::<B>();
let c = mem::take(args[2]).cast::<C>();
let d = mem::take(args[3]).cast::<D>();
@@ -1019,7 +1043,7 @@ pub trait ModuleResolver: SendSync {
/// Resolve a module based on a path string.
fn resolve(
&self,
engine: &Engine,
_: &Engine,
scope: Scope,
path: &str,
pos: Position,

View File

@@ -2,9 +2,11 @@
use crate::any::{Dynamic, Variant};
use crate::def_package;
use crate::engine::Array;
use crate::engine::{Array, Engine};
use crate::module::FuncReturn;
use crate::parser::{ImmutableString, INT};
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::stdlib::{any::TypeId, boxed::Box};
@@ -23,13 +25,28 @@ fn ins<T: Variant + Clone>(list: &mut Array, position: INT, item: T) -> FuncRetu
}
Ok(())
}
fn pad<T: Variant + Clone>(list: &mut Array, len: INT, item: T) -> FuncReturn<()> {
if len >= 0 {
fn pad<T: Variant + Clone>(engine: &Engine, args: &mut [&mut Dynamic]) -> FuncReturn<()> {
let len = *args[1].downcast_ref::<INT>().unwrap();
// Check if array will be over max size limit
if engine.max_array_size > 0 && len > 0 && (len as usize) > engine.max_array_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(),
engine.max_array_size,
len as usize,
Position::none(),
)))
} else if len >= 0 {
let item = args[2].downcast_ref::<T>().unwrap().clone();
let list = args[0].downcast_mut::<Array>().unwrap();
while list.len() < len as usize {
push(list, item.clone())?;
}
Ok(())
} else {
Ok(())
}
Ok(())
}
macro_rules! reg_op {
@@ -42,11 +59,21 @@ macro_rules! reg_tri {
$( $lib.set_fn_3_mut($op, $func::<$par>); )*
};
}
macro_rules! reg_pad {
($lib:expr, $op:expr, $func:ident, $($par:ty),*) => {
$({
$lib.set_fn_var_args($op,
&[TypeId::of::<Array>(), TypeId::of::<INT>(), TypeId::of::<$par>()],
$func::<$par>
);
})*
};
}
#[cfg(not(feature = "no_index"))]
def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
reg_op!(lib, "push", push, INT, bool, char, ImmutableString, Array, ());
reg_tri!(lib, "pad", pad, INT, bool, char, ImmutableString, Array, ());
reg_pad!(lib, "pad", pad, INT, bool, char, ImmutableString, Array, ());
reg_tri!(lib, "insert", ins, INT, bool, char, ImmutableString, Array, ());
lib.set_fn_2_mut("append", |x: &mut Array, y: Array| {
@@ -69,14 +96,14 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
#[cfg(not(feature = "only_i64"))]
{
reg_op!(lib, "push", push, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
reg_tri!(lib, "pad", pad, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
reg_pad!(lib, "pad", pad, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
reg_tri!(lib, "insert", ins, i8, u8, i16, u16, i32, i64, u32, u64, i128, u128);
}
#[cfg(not(feature = "no_float"))]
{
reg_op!(lib, "push", push, f32, f64);
reg_tri!(lib, "pad", pad, f32, f64);
reg_pad!(lib, "pad", pad, f32, f64);
reg_tri!(lib, "insert", ins, f32, f64);
}

View File

@@ -1,12 +1,17 @@
use crate::any::Dynamic;
use crate::def_package;
use crate::engine::Engine;
use crate::module::FuncReturn;
use crate::parser::{ImmutableString, INT};
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::utils::StaticVec;
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;
use crate::stdlib::{
any::TypeId,
fmt::Display,
format,
string::{String, ToString},
@@ -210,14 +215,40 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
Ok(())
},
);
lib.set_fn_3_mut(
lib.set_fn_var_args(
"pad",
|s: &mut ImmutableString, len: INT, ch: char| {
let copy = s.make_mut();
for _ in 0..copy.chars().count() - len as usize {
copy.push(ch);
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|engine: &Engine, args: &mut [&mut Dynamic]| {
let len = *args[1].downcast_ref::< INT>().unwrap();
// Check if string will be over max size limit
if engine.max_string_size > 0 && len > 0 && (len as usize) > engine.max_string_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(),
engine.max_string_size,
len as usize,
Position::none(),
)))
} else {
let ch = *args[2].downcast_ref::< char>().unwrap();
let s = args[0].downcast_mut::<ImmutableString>().unwrap();
let copy = s.make_mut();
for _ in 0..copy.chars().count() - len as usize {
copy.push(ch);
}
if engine.max_string_size > 0 && copy.len() > engine.max_string_size {
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(),
engine.max_string_size,
copy.len(),
Position::none(),
)))
} else {
Ok(())
}
}
Ok(())
},
);
lib.set_fn_3_mut(

View File

@@ -298,7 +298,9 @@ impl ParseSettings {
}
/// Make sure that the current level of expression nesting is within the maximum limit.
pub fn ensure_level_within_max_limit(&self, limit: usize) -> Result<(), ParseError> {
if self.level > limit {
if limit == 0 {
Ok(())
} else if self.level > limit {
Err(PERR::ExprTooDeep.into_err(self.pos))
} else {
Ok(())
@@ -624,7 +626,7 @@ impl Expr {
Self::Variable(_) => true,
expr => expr.is_constant(),
_ => self.is_constant(),
}
}
@@ -765,7 +767,7 @@ fn parse_paren_expr(
// ( xxx )
(Token::RightParen, _) => Ok(expr),
// ( <error>
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
// ( xxx ???
(_, pos) => Err(PERR::MissingToken(
Token::RightParen.into(),
@@ -798,7 +800,7 @@ fn parse_call_expr(
.into_err(settings.pos))
}
// id <error>
Token::LexError(err) => return Err(PERR::BadInput(err.to_string()).into_err(settings.pos)),
Token::LexError(err) => return Err(err.into_err(settings.pos)),
// id()
Token::RightParen => {
eat_token(input, Token::RightParen);
@@ -878,9 +880,7 @@ fn parse_call_expr(
.into_err(*pos))
}
// id(...args <error>
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
// id(...args ???
(_, pos) => {
return Err(PERR::MissingToken(
@@ -1063,7 +1063,7 @@ fn parse_index_chain(
}
}
}
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(*pos)),
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
(_, pos) => Err(PERR::MissingToken(
Token::RightBracket.into(),
"for a matching [ in this index expression".into(),
@@ -1108,9 +1108,7 @@ fn parse_array_literal(
)
.into_err(*pos))
}
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::Comma.into(),
@@ -1142,9 +1140,7 @@ fn parse_map_literal(
let (name, pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos),
(Token::StringConst(s), pos) => (s, pos),
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) if map.is_empty() => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
@@ -1162,9 +1158,7 @@ fn parse_map_literal(
match input.next().unwrap() {
(Token::Colon, _) => (),
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::Colon.into(),
@@ -1203,9 +1197,7 @@ fn parse_map_literal(
)
.into_err(*pos))
}
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
(_, pos) => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
@@ -1267,8 +1259,8 @@ fn parse_primary(
Token::MapStart => parse_map_literal(input, state, settings.level_up())?,
Token::True => Expr::True(settings.pos),
Token::False => Expr::False(settings.pos),
Token::LexError(err) => return Err(PERR::BadInput(err.to_string()).into_err(settings.pos)),
token => {
Token::LexError(err) => return Err(err.into_err(settings.pos)),
_ => {
return Err(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos)
)
@@ -1378,12 +1370,7 @@ fn parse_unary(
None
}
})
.ok_or_else(|| {
PERR::BadInput(
LexError::MalformedNumber(format!("-{}", x.0)).to_string(),
)
.into_err(pos)
})
.ok_or_else(|| LexError::MalformedNumber(format!("-{}", x.0)).into_err(pos))
}
// Negative float
@@ -1846,7 +1833,7 @@ fn parse_binary_op(
make_dot_expr(current_lhs, rhs, pos)?
}
token => return Err(PERR::UnknownOperator(token.into()).into_err(pos)),
op_token => return Err(PERR::UnknownOperator(op_token.into()).into_err(pos)),
};
}
}
@@ -1988,7 +1975,7 @@ fn parse_for(
// Variable name
(Token::Identifier(s), _) => s,
// Bad identifier
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
// EOF
(Token::EOF, pos) => return Err(PERR::VariableExpected.into_err(pos)),
// Not a variable name
@@ -1998,7 +1985,7 @@ fn parse_for(
// for name in ...
match input.next().unwrap() {
(Token::In, _) => (),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(
PERR::MissingToken(Token::In.into(), "after the iteration variable".into())
@@ -2036,7 +2023,7 @@ fn parse_let(
// let name ...
let (name, pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
};
@@ -2107,7 +2094,7 @@ fn parse_import(
// import expr as name ...
let (name, _) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s, pos),
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
};
@@ -2130,9 +2117,7 @@ fn parse_export(
loop {
let (id, id_pos) = match input.next().unwrap() {
(Token::Identifier(s), pos) => (s.clone(), pos),
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
};
@@ -2187,7 +2172,7 @@ fn parse_block(
// Must start with {
settings.pos = match input.next().unwrap() {
(Token::LeftBrace, pos) => pos,
(Token::LexError(err), pos) => return Err(PERR::BadInput(err.to_string()).into_err(pos)),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::LeftBrace.into(),
@@ -2227,9 +2212,7 @@ fn parse_block(
// { ... { stmt } ???
(_, _) if !need_semicolon => (),
// { ... stmt <error>
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
// { ... stmt ???
(_, pos) => {
// Semicolons are not optional between statements
@@ -2378,9 +2361,7 @@ fn parse_fn(
state.push((s.clone(), ScopeEntryType::Normal));
params.push((s, pos))
}
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(Token::RightParen.into(), end_err).into_err(pos))
}
@@ -2392,9 +2373,7 @@ fn parse_fn(
(Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
}
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
}
@@ -2565,9 +2544,7 @@ impl Engine {
// { stmt } ???
(_, _) if !need_semicolon => (),
// stmt <error>
(Token::LexError(err), pos) => {
return Err(PERR::BadInput(err.to_string()).into_err(*pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(*pos)),
// stmt ???
(_, pos) => {
// Semicolons are not optional between statements

View File

@@ -862,6 +862,14 @@ impl<'a> TokenIterator<'a> {
self.eat_next();
return Some((Token::MinusAssign, pos));
}
('-', '>') => {
return Some((
Token::LexError(Box::new(LERR::ImproperSymbol(
"'->' is not a valid symbol. This is not C or C++!".to_string(),
))),
pos,
))
}
('-', _) if self.can_be_unary => return Some((Token::UnaryMinus, pos)),
('-', _) => return Some((Token::Minus, pos)),
@@ -931,7 +939,7 @@ impl<'a> TokenIterator<'a> {
// Warn against `===`
if self.peek_next() == Some('=') {
return Some((
Token::LexError(Box::new(LERR::ImproperKeyword(
Token::LexError(Box::new(LERR::ImproperSymbol(
"'===' is not a valid operator. This is not JavaScript! Should it be '=='?"
.to_string(),
))),
@@ -941,18 +949,44 @@ impl<'a> TokenIterator<'a> {
return Some((Token::EqualsTo, pos));
}
('=', '>') => {
return Some((
Token::LexError(Box::new(LERR::ImproperSymbol(
"'=>' is not a valid symbol. This is not Rust! Should it be '>='?"
.to_string(),
))),
pos,
))
}
('=', _) => return Some((Token::Equals, pos)),
(':', ':') => {
self.eat_next();
return Some((Token::DoubleColon, pos));
}
(':', '=') => {
return Some((
Token::LexError(Box::new(LERR::ImproperSymbol(
"':=' is not a valid assignment operator. This is not Pascal! Should it be simply '='?"
.to_string(),
))),
pos,
))
}
(':', _) => return Some((Token::Colon, pos)),
('<', '=') => {
self.eat_next();
return Some((Token::LessThanEqualsTo, pos));
}
('<', '-') => {
return Some((
Token::LexError(Box::new(LERR::ImproperSymbol(
"'<-' is not a valid symbol. Should it be '<='?".to_string(),
))),
pos,
))
}
('<', '<') => {
self.eat_next();
@@ -993,7 +1027,7 @@ impl<'a> TokenIterator<'a> {
// Warn against `!==`
if self.peek_next() == Some('=') {
return Some((
Token::LexError(Box::new(LERR::ImproperKeyword(
Token::LexError(Box::new(LERR::ImproperSymbol(
"'!==' is not a valid operator. This is not JavaScript! Should it be '!='?"
.to_string(),
))),