Add constant NO_POS.

This commit is contained in:
Stephen Chung 2020-11-02 12:50:27 +08:00
parent 6f3ce96d9d
commit d7d6f74dfd
29 changed files with 253 additions and 292 deletions

View File

@ -22,6 +22,7 @@ Breaking changes
* `EvalAltResult::ErrorAssignmentToUnknownLHS` is moved to `ParseError::AssignmentToInvalidLHS`. `ParseError::AssignmentToCopy` is removed. * `EvalAltResult::ErrorAssignmentToUnknownLHS` is moved to `ParseError::AssignmentToInvalidLHS`. `ParseError::AssignmentToCopy` is removed.
* `EvalAltResult::ErrorDataTooLarge` is simplified. * `EvalAltResult::ErrorDataTooLarge` is simplified.
* `Engine::on_progress` closure signature now returns `Option<Dynamic>` with the termination value passed on to `EvalAltResult::ErrorTerminated`. * `Engine::on_progress` closure signature now returns `Option<Dynamic>` with the termination value passed on to `EvalAltResult::ErrorTerminated`.
* `ParseErrorType::BadInput` now wraps a `LexError` instead of a text string.
New features New features
------------ ------------

View File

@ -294,9 +294,8 @@ engine.register_custom_syntax_raw(
"update" | "check" | "add" | "remove" => Ok(Some("$ident$".to_string())), "update" | "check" | "add" | "remove" => Ok(Some("$ident$".to_string())),
"cleanup" => Ok(None), "cleanup" => Ok(None),
cmd => Err(ParseError(Box::new(ParseErrorType::BadInput( cmd => Err(ParseError(Box::new(ParseErrorType::BadInput(
format!("Improper command: {}", cmd))), LexError::ImproperSymbol(format!("Improper command: {}", cmd))
Position::none(), )), NO_POS)),
)),
}, },
// perform command arg ... // perform command arg ...
3 => match (stream[1].as_str(), stream[2].as_str()) { 3 => match (stream[1].as_str(), stream[2].as_str()) {
@ -308,9 +307,10 @@ engine.register_custom_syntax_raw(
("add", arg) => Ok(None), ("add", arg) => Ok(None),
("remove", arg) => Ok(None), ("remove", arg) => Ok(None),
(cmd, arg) => Err(ParseError(Box::new(ParseErrorType::BadInput( (cmd, arg) => Err(ParseError(Box::new(ParseErrorType::BadInput(
format!("Invalid argument for command {}: {}", cmd, arg))), LexError::ImproperSymbol(
Position::none(), format!("Invalid argument for command {}: {}", cmd, arg)
)), )
)), NO_POS)),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
@ -336,7 +336,7 @@ where:
The return value is `Result<Option<String>, ParseError>` where: The return value is `Result<Option<String>, ParseError>` where:
| Value | Description | | Value | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Ok(None)` | parsing complete and there are no more symbols to match | | `Ok(None)` | parsing complete and there are no more symbols to match |
| `Ok(Some(symbol))` | next symbol to match, which can also be `"$expr$"`, `"$ident$"` or `"$block$"` | | `Ok(Some(symbol))` | next symbol to match, which can also be `"$expr$"`, `"$ident$"` or `"$block$"` |
| `Err(ParseError)` | error that is reflected back to the [`Engine`].<br/>Normally this is `ParseError(ParseErrorType::BadInput(message), Position::none())` to indicate that there is a syntax error, but it can be any `ParseError`. | | `Err(ParseError)` | error that is reflected back to the [`Engine`].<br/>Normally this is `ParseError(ParseErrorType::BadInput(LexError::ImproperSymbol(message)), NO_POS)` to indicate that there is a syntax error, but it can be any `ParseError`. |

View File

@ -21,11 +21,11 @@ engine.on_var(|name, index, context| {
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())), "MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
// Override a variable - make it not found even if it exists! // Override a variable - make it not found even if it exists!
"DO_NOT_USE" => Err(Box::new( "DO_NOT_USE" => Err(Box::new(
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()) EvalAltResult::ErrorVariableNotFound(name.to_string(), NO_POS)
)), )),
// Silently maps 'chameleon' into 'innocent'. // Silently maps 'chameleon' into 'innocent'.
"chameleon" => context.scope.get_value("innocent").map(Some).ok_or_else(|| Box::new( "chameleon" => context.scope.get_value("innocent").map(Some).ok_or_else(|| Box::new(
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()) EvalAltResult::ErrorVariableNotFound(name.to_string(), NO_POS)
)), )),
// Return Ok(None) to continue with the normal variable resolution process. // Return Ok(None) to continue with the normal variable resolution process.
_ => Ok(None) _ => Ok(None)
@ -83,7 +83,7 @@ where:
The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where: The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where:
| Value | Description | | Value | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Ok(None)` | normal variable resolution process should continue, i.e. continue searching through the [`Scope`] | | `Ok(None)` | normal variable resolution process should continue, i.e. continue searching through the [`Scope`] |
| `Ok(Some(Dynamic))` | value of the variable, treated as a constant | | `Ok(Some(Dynamic))` | value of the variable, treated as a constant |
| `Err(Box<EvalAltResult>)` | error that is reflected back to the [`Engine`].<br/>Normally this is `EvalAltResult::ErrorVariableNotFound(var_name, Position::none())` to indicate that the variable does not exist, but it can be any `EvalAltResult`. | | `Err(Box<EvalAltResult>)` | error that is reflected back to the [`Engine`].<br/>Normally this is `EvalAltResult::ErrorVariableNotFound(var_name, NO_POS)` to indicate that the variable does not exist, but it can be any `EvalAltResult`. |

View File

@ -117,7 +117,7 @@ pub fn greet(context: NativeCallContext, callback: FnPtr)
The native call context is also useful in another scenario: protecting a function from malicious scripts. The native call context is also useful in another scenario: protecting a function from malicious scripts.
```rust ```rust
use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, NO_POS};
use rhai::plugin::*; // a "prelude" import for macros use rhai::plugin::*; // a "prelude" import for macros
// This function builds an array of arbitrary size, but is protected // This function builds an array of arbitrary size, but is protected
@ -137,7 +137,7 @@ pub fn grow(context: NativeCallContext, size: i64)
"Size to grow".to_string(), "Size to grow".to_string(),
context.engine().max_array_size(), context.engine().max_array_size(),
size as usize, size as usize,
Position::none(), NO_POS,
).into(); ).into();
} }

View File

@ -376,7 +376,7 @@ mod my_module {
The native call context is also useful in another scenario: protecting a function from malicious scripts. The native call context is also useful in another scenario: protecting a function from malicious scripts.
```rust ```rust
use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, Position}; use rhai::{Dynamic, Array, NativeCallContext, EvalAltResult, NO_POS};
use rhai::plugin::*; // a "prelude" import for macros use rhai::plugin::*; // a "prelude" import for macros
#[export_module] #[export_module]
@ -397,7 +397,7 @@ mod my_module {
"Size to grow".to_string(), "Size to grow".to_string(),
context.engine().max_array_size(), context.engine().max_array_size(),
size as usize, size as usize,
Position::none(), NO_POS,
).into(); ).into();
} }

View File

@ -11,7 +11,7 @@ use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::CustomSyntax; use crate::syntax::CustomSyntax;
use crate::token::Position; use crate::token::{Position, NO_POS};
use crate::{calc_native_fn_hash, StaticVec}; use crate::{calc_native_fn_hash, StaticVec};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -351,7 +351,7 @@ impl<'a> Target<'a> {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Self::StringChar(_, _, ch) => { Self::StringChar(_, _, ch) => {
let char_value = ch.clone(); let char_value = ch.clone();
self.set_value((char_value, Position::none())).unwrap(); self.set_value((char_value, NO_POS)).unwrap();
} }
} }
} }
@ -993,7 +993,7 @@ impl Engine {
{ {
EvalAltResult::ErrorIndexingType( EvalAltResult::ErrorIndexingType(
self.map_type_name(val_type_name).into(), self.map_type_name(val_type_name).into(),
Position::none(), NO_POS,
) )
} }
err => err, err => err,
@ -1463,20 +1463,16 @@ impl Engine {
.map(|(v, _)| v.into()) .map(|(v, _)| v.into())
.map_err(|err| match *err { .map_err(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.ends_with(']') => { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.ends_with(']') => {
Box::new(EvalAltResult::ErrorIndexingType( Box::new(EvalAltResult::ErrorIndexingType(type_name.into(), NO_POS))
type_name.into(),
Position::none(),
))
} }
_ => err, _ => err,
}) })
} }
_ => EvalAltResult::ErrorIndexingType( _ => {
self.map_type_name(val.type_name()).into(), EvalAltResult::ErrorIndexingType(self.map_type_name(val.type_name()).into(), NO_POS)
Position::none(), .into()
) }
.into(),
} }
} }
@ -2036,7 +2032,7 @@ impl Engine {
let value = if let EvalAltResult::ErrorRuntime(ref x, _) = err { let value = if let EvalAltResult::ErrorRuntime(ref x, _) = err {
x.clone() x.clone()
} else { } else {
err.set_position(Position::none()); err.set_position(NO_POS);
err.to_string().into() err.to_string().into()
}; };
@ -2298,25 +2294,17 @@ impl Engine {
let (_arr, _map, s) = calc_size(result.as_ref().unwrap()); let (_arr, _map, s) = calc_size(result.as_ref().unwrap());
if s > self.max_string_size() { if s > self.max_string_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), NO_POS).into();
"Length of string".to_string(),
Position::none(),
)
.into();
} }
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
if _arr > self.max_array_size() { if _arr > self.max_array_size() {
return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), Position::none()) return EvalAltResult::ErrorDataTooLarge("Size of array".to_string(), NO_POS).into();
.into();
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
if _map > self.max_map_size() { if _map > self.max_map_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge("Size of object map".to_string(), NO_POS)
"Size of object map".to_string(),
Position::none(),
)
.into(); .into();
} }
@ -2331,14 +2319,14 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
// Guard against too many operations // Guard against too many operations
if self.max_operations() > 0 && state.operations > self.max_operations() { if self.max_operations() > 0 && state.operations > self.max_operations() {
return EvalAltResult::ErrorTooManyOperations(Position::none()).into(); return EvalAltResult::ErrorTooManyOperations(NO_POS).into();
} }
// Report progress - only in steps // Report progress - only in steps
if let Some(progress) = &self.progress { if let Some(progress) = &self.progress {
if let Some(token) = progress(&state.operations) { if let Some(token) = progress(&state.operations) {
// Terminate script if progress returns a termination token // Terminate script if progress returns a termination token
return EvalAltResult::ErrorTerminated(token, Position::none()).into(); return EvalAltResult::ErrorTerminated(token, NO_POS).into();
} }
} }

View File

@ -8,7 +8,7 @@ use crate::optimize::OptimizationLevel;
use crate::parse_error::ParseError; use crate::parse_error::ParseError;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::Scope; use crate::scope::Scope;
use crate::token::Position; use crate::token::{Position, NO_POS};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::{ use crate::{
@ -1391,7 +1391,7 @@ impl Engine {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
self.map_type_name(type_name::<T>()).into(), self.map_type_name(type_name::<T>()).into(),
typ.into(), typ.into(),
Position::none(), NO_POS,
) )
.into() .into()
}); });
@ -1527,7 +1527,7 @@ impl Engine {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
self.map_type_name(type_name::<T>()).into(), self.map_type_name(type_name::<T>()).into(),
typ.into(), typ.into(),
Position::none(), NO_POS,
) )
.into() .into()
}); });
@ -1617,7 +1617,7 @@ impl Engine {
) -> Result<Dynamic, Box<EvalAltResult>> { ) -> Result<Dynamic, Box<EvalAltResult>> {
let fn_def = lib let fn_def = lib
.get_script_fn(name, args.len(), true) .get_script_fn(name, args.len(), true)
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?; .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), NO_POS))?;
let mut state = Default::default(); let mut state = Default::default();
let mut mods = Default::default(); let mut mods = Default::default();

View File

@ -14,7 +14,7 @@ use crate::parse_error::ParseErrorType;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::scope::Scope; use crate::scope::Scope;
use crate::stdlib::ops::Deref; use crate::stdlib::ops::Deref;
use crate::token::Position; use crate::token::NO_POS;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec, INT}; use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec, INT};
@ -159,7 +159,7 @@ pub fn ensure_no_data_race(
{ {
return EvalAltResult::ErrorDataRace( return EvalAltResult::ErrorDataRace(
format!("argument #{} of function '{}'", n + 1 + skip, fn_name), format!("argument #{} of function '{}'", n + 1 + skip, fn_name),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -223,7 +223,7 @@ impl Engine {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
self.map_type_name(type_name::<ImmutableString>()).into(), self.map_type_name(type_name::<ImmutableString>()).into(),
typ.into(), typ.into(),
Position::none(), NO_POS,
) )
})?) })?)
.into(), .into(),
@ -234,7 +234,7 @@ impl Engine {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(
self.map_type_name(type_name::<ImmutableString>()).into(), self.map_type_name(type_name::<ImmutableString>()).into(),
typ.into(), typ.into(),
Position::none(), NO_POS,
) )
})?) })?)
.into(), .into(),
@ -265,7 +265,7 @@ impl Engine {
prop, prop,
self.map_type_name(args[0].type_name()) self.map_type_name(args[0].type_name())
), ),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -279,7 +279,7 @@ impl Engine {
self.map_type_name(args[0].type_name()), self.map_type_name(args[0].type_name()),
self.map_type_name(args[1].type_name()), self.map_type_name(args[1].type_name()),
), ),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -293,7 +293,7 @@ impl Engine {
self.map_type_name(args[0].type_name()), self.map_type_name(args[0].type_name()),
self.map_type_name(args[1].type_name()), self.map_type_name(args[1].type_name()),
), ),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -307,7 +307,7 @@ impl Engine {
self.map_type_name(args[0].type_name()), self.map_type_name(args[0].type_name()),
self.map_type_name(args[1].type_name()), self.map_type_name(args[1].type_name()),
), ),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -326,7 +326,7 @@ impl Engine {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Position::none(), NO_POS,
) )
.into() .into()
} }
@ -357,9 +357,7 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if level > self.max_call_levels() { if level > self.max_call_levels() {
return Err(Box::new( return Err(Box::new(EvalAltResult::ErrorStackOverflow(NO_POS)));
EvalAltResult::ErrorStackOverflow(Position::none()),
));
} }
let orig_scope_level = state.scope_level; let orig_scope_level = state.scope_level;
@ -396,8 +394,8 @@ impl Engine {
// Evaluate the function at one higher level of call depth // Evaluate the function at one higher level of call depth
let stmt = &fn_def.body; let stmt = &fn_def.body;
let result = self let result =
.eval_stmt(scope, mods, state, unified_lib, this_ptr, stmt, level + 1) self.eval_stmt(scope, mods, state, unified_lib, this_ptr, stmt, level + 1)
.or_else(|err| match *err { .or_else(|err| match *err {
// Convert return statement to return value // Convert return statement to return value
EvalAltResult::Return(x, _) => Ok(x), EvalAltResult::Return(x, _) => Ok(x),
@ -405,18 +403,14 @@ impl Engine {
EvalAltResult::ErrorInFunctionCall( EvalAltResult::ErrorInFunctionCall(
format!("{} > {}", fn_def.name, name), format!("{} > {}", fn_def.name, name),
err, err,
Position::none(), NO_POS,
) )
.into() .into()
} }
// System errors are passed straight-through // System errors are passed straight-through
err if err.is_system_exception() => Err(Box::new(err)), err if err.is_system_exception() => Err(Box::new(err)),
// Other errors are wrapped in `ErrorInFunctionCall` // Other errors are wrapped in `ErrorInFunctionCall`
_ => EvalAltResult::ErrorInFunctionCall( _ => EvalAltResult::ErrorInFunctionCall(fn_def.name.to_string(), err, NO_POS)
fn_def.name.to_string(),
err,
Position::none(),
)
.into(), .into(),
}); });
@ -519,7 +513,7 @@ impl Engine {
fn_name, fn_name fn_name, fn_name
) )
.into(), .into(),
Position::none(), NO_POS,
) )
.into() .into()
} }
@ -656,9 +650,7 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _level > self.max_call_levels() { if _level > self.max_call_levels() {
return Err(Box::new( return Err(Box::new(EvalAltResult::ErrorStackOverflow(NO_POS)));
EvalAltResult::ErrorStackOverflow(Position::none()),
));
} }
// Compile the script text // Compile the script text
@ -1218,7 +1210,7 @@ impl Engine {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Position::none(), NO_POS,
) )
.into(), .into(),
} }

View File

@ -6,7 +6,7 @@ use crate::engine::{Engine, EvalContext};
use crate::module::Module; use crate::module::Module;
use crate::plugin::PluginFunction; use crate::plugin::PluginFunction;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position}; use crate::token::{is_valid_identifier, NO_POS};
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::{calc_script_fn_hash, StaticVec}; use crate::{calc_script_fn_hash, StaticVec};
@ -215,7 +215,7 @@ impl TryFrom<ImmutableString> for FnPtr {
if is_valid_identifier(value.chars()) { if is_valid_identifier(value.chars()) {
Ok(Self(value, Default::default())) Ok(Self(value, Default::default()))
} else { } else {
EvalAltResult::ErrorFunctionNotFound(value.into(), Position::none()).into() EvalAltResult::ErrorFunctionNotFound(value.into(), NO_POS).into()
} }
} }
} }

View File

@ -115,11 +115,11 @@ pub use engine::{Engine, EvalContext};
pub use fn_native::{FnPtr, NativeCallContext}; pub use fn_native::{FnPtr, NativeCallContext};
pub use fn_register::{RegisterFn, RegisterResultFn}; pub use fn_register::{RegisterFn, RegisterResultFn};
pub use module::Module; pub use module::Module;
pub use parse_error::{ParseError, ParseErrorType}; pub use parse_error::{LexError, ParseError, ParseErrorType};
pub use result::EvalAltResult; pub use result::EvalAltResult;
pub use scope::Scope; pub use scope::Scope;
pub use syntax::Expression; pub use syntax::Expression;
pub use token::Position; pub use token::{Position, NO_POS};
pub use utils::ImmutableString; pub use utils::ImmutableString;
#[cfg(feature = "internals")] #[cfg(feature = "internals")]

View File

@ -5,7 +5,7 @@ use crate::dynamic::{Dynamic, Variant};
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync}; use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
use crate::fn_register::by_value as cast_arg; use crate::fn_register::by_value as cast_arg;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::{Position, Token}; use crate::token::{Token, NO_POS};
use crate::utils::{ImmutableString, StraightHasherBuilder}; use crate::utils::{ImmutableString, StraightHasherBuilder};
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec}; use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
@ -271,11 +271,11 @@ impl Module {
hash_var: u64, hash_var: u64,
) -> Result<&mut Dynamic, Box<EvalAltResult>> { ) -> Result<&mut Dynamic, Box<EvalAltResult>> {
if hash_var == 0 { if hash_var == 0 {
Err(EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into()) Err(EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
} else { } else {
self.all_variables.get_mut(&hash_var).ok_or_else(|| { self.all_variables
EvalAltResult::ErrorVariableNotFound(String::new(), Position::none()).into() .get_mut(&hash_var)
}) .ok_or_else(|| EvalAltResult::ErrorVariableNotFound(String::new(), NO_POS).into())
} }
} }

View File

@ -10,7 +10,7 @@ use crate::fn_call::run_builtin_binary_op;
use crate::module::Module; use crate::module::Module;
use crate::parser::map_dynamic_to_expr; use crate::parser::map_dynamic_to_expr;
use crate::scope::Scope; use crate::scope::Scope;
use crate::token::{is_valid_identifier, Position}; use crate::token::{is_valid_identifier, NO_POS};
use crate::{calc_native_fn_hash, StaticVec}; use crate::{calc_native_fn_hash, StaticVec};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
@ -726,7 +726,7 @@ fn optimize(
.iter() .iter()
.filter(|(_, typ, _)| *typ) .filter(|(_, typ, _)| *typ)
.for_each(|(name, _, value)| { .for_each(|(name, _, value)| {
if let Some(val) = map_dynamic_to_expr(value, Position::none()) { if let Some(val) = map_dynamic_to_expr(value, NO_POS) {
state.push_constant(name, val); state.push_constant(name, val);
} }
}); });

View File

@ -4,7 +4,7 @@ use crate::def_package;
use crate::plugin::*; use crate::plugin::*;
use crate::INT; use crate::INT;
use crate::{result::EvalAltResult, token::Position}; use crate::{result::EvalAltResult, token::NO_POS};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::FLOAT; use crate::FLOAT;
@ -17,7 +17,7 @@ use crate::stdlib::{format, string::String};
#[inline(always)] #[inline(always)]
pub fn make_err(msg: impl Into<String>) -> Box<EvalAltResult> { pub fn make_err(msg: impl Into<String>) -> Box<EvalAltResult> {
EvalAltResult::ErrorArithmetic(msg.into(), Position::none()).into() EvalAltResult::ErrorArithmetic(msg.into(), NO_POS).into()
} }
macro_rules! gen_arithmetic_functions { macro_rules! gen_arithmetic_functions {

View File

@ -7,7 +7,7 @@ use crate::engine::Array;
use crate::fn_native::{FnPtr, NativeCallContext}; use crate::fn_native::{FnPtr, NativeCallContext};
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::NO_POS;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::INT; use crate::INT;
@ -46,7 +46,7 @@ macro_rules! gen_array_functions {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_array_size() > 0 && len > 0 && (len as usize) > _ctx.engine().max_array_size() { if _ctx.engine().max_array_size() > 0 && len > 0 && (len as usize) > _ctx.engine().max_array_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(), Position::none() "Size of array".to_string(), NO_POS
).into(); ).into();
} }
@ -219,7 +219,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"map".to_string(), "map".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?, })?,
); );
@ -250,7 +250,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(), "filter".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})? })?
.as_bool() .as_bool()
@ -283,7 +283,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(), "filter".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})? })?
.as_bool() .as_bool()
@ -316,7 +316,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(), "filter".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})? })?
.as_bool() .as_bool()
@ -351,7 +351,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
} }
@ -369,7 +369,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
@ -388,7 +388,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
} }
@ -418,7 +418,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
} }
@ -436,7 +436,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
@ -455,7 +455,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"reduce".to_string(), "reduce".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})?; })?;
} }
@ -525,7 +525,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(), "filter".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})? })?
.as_bool() .as_bool()
@ -584,7 +584,7 @@ mod array_functions {
Box::new(EvalAltResult::ErrorInFunctionCall( Box::new(EvalAltResult::ErrorInFunctionCall(
"filter".to_string(), "filter".to_string(),
err, err,
Position::none(), NO_POS,
)) ))
})? })?
.as_bool() .as_bool()

View File

@ -2,7 +2,7 @@
use crate::def_package; use crate::def_package;
use crate::plugin::*; use crate::plugin::*;
use crate::token::Position; use crate::token::NO_POS;
use crate::INT; use crate::INT;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
@ -85,10 +85,7 @@ mod int_functions {
#[rhai_fn(name = "parse_int", return_raw)] #[rhai_fn(name = "parse_int", return_raw)]
pub fn parse_int_radix(s: &str, radix: INT) -> Result<Dynamic, Box<EvalAltResult>> { pub fn parse_int_radix(s: &str, radix: INT) -> Result<Dynamic, Box<EvalAltResult>> {
if radix < 2 || radix > 36 { if radix < 2 || radix > 36 {
return EvalAltResult::ErrorArithmetic( return EvalAltResult::ErrorArithmetic(format!("Invalid radix: '{}'", radix), NO_POS)
format!("Invalid radix: '{}'", radix),
Position::none(),
)
.into(); .into();
} }
@ -97,7 +94,7 @@ mod int_functions {
.map_err(|err| { .map_err(|err| {
EvalAltResult::ErrorArithmetic( EvalAltResult::ErrorArithmetic(
format!("Error parsing integer number '{}': {}", s, err), format!("Error parsing integer number '{}': {}", s, err),
Position::none(), NO_POS,
) )
.into() .into()
}) })
@ -206,10 +203,7 @@ mod float_functions {
#[rhai_fn(name = "to_int", return_raw)] #[rhai_fn(name = "to_int", return_raw)]
pub fn f32_to_int(x: f32) -> Result<Dynamic, Box<EvalAltResult>> { pub fn f32_to_int(x: f32) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f32) { if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f32) {
EvalAltResult::ErrorArithmetic( EvalAltResult::ErrorArithmetic(format!("Integer overflow: to_int({})", x), NO_POS)
format!("Integer overflow: to_int({})", x),
Position::none(),
)
.into() .into()
} else { } else {
Ok((x.trunc() as INT).into()) Ok((x.trunc() as INT).into())
@ -218,10 +212,7 @@ mod float_functions {
#[rhai_fn(name = "to_int", return_raw)] #[rhai_fn(name = "to_int", return_raw)]
pub fn f64_to_int(x: f64) -> Result<Dynamic, Box<EvalAltResult>> { pub fn f64_to_int(x: f64) -> Result<Dynamic, Box<EvalAltResult>> {
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f64) { if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f64) {
EvalAltResult::ErrorArithmetic( EvalAltResult::ErrorArithmetic(format!("Integer overflow: to_int({})", x), NO_POS)
format!("Integer overflow: to_int({})", x),
Position::none(),
)
.into() .into()
} else { } else {
Ok((x.trunc() as INT).into()) Ok((x.trunc() as INT).into())
@ -235,7 +226,7 @@ mod float_functions {
.map_err(|err| { .map_err(|err| {
EvalAltResult::ErrorArithmetic( EvalAltResult::ErrorArithmetic(
format!("Error parsing floating-point number '{}': {}", s, err), format!("Error parsing floating-point number '{}': {}", s, err),
Position::none(), NO_POS,
) )
.into() .into()
}) })

View File

@ -9,7 +9,7 @@ use crate::StaticVec;
use crate::INT; use crate::INT;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position}; use crate::{result::EvalAltResult, token::NO_POS};
use crate::stdlib::{ use crate::stdlib::{
any::TypeId, boxed::Box, format, mem, string::String, string::ToString, vec::Vec, any::TypeId, boxed::Box, format, mem, string::String, string::ToString, vec::Vec,
@ -259,11 +259,7 @@ mod string_functions {
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), NO_POS).into();
"Length of string".to_string(),
Position::none(),
)
.into();
} }
if len > 0 { if len > 0 {
@ -281,7 +277,7 @@ mod string_functions {
{ {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
Position::none(), NO_POS,
) )
.into(); .into();
} }
@ -300,11 +296,7 @@ mod string_functions {
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge("Length of string".to_string(), NO_POS).into();
"Length of string".to_string(),
Position::none(),
)
.into();
} }
if len > 0 { if len > 0 {
@ -329,7 +321,7 @@ mod string_functions {
{ {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
Position::none(), NO_POS,
) )
.into(); .into();
} }

View File

@ -1,7 +1,7 @@
//! Module containing error definitions for the parsing process. //! Module containing error definitions for the parsing process.
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::{Position, NO_POS};
use crate::stdlib::{ use crate::stdlib::{
boxed::Box, boxed::Box,
@ -43,26 +43,34 @@ impl fmt::Display for LexError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::UnexpectedInput(s) => write!(f, "Unexpected '{}'", s), Self::UnexpectedInput(s) => write!(f, "Unexpected '{}'", s),
Self::MalformedEscapeSequence(s) => write!(f, "Invalid escape sequence: '{}'", s), Self::MalformedEscapeSequence(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::MalformedNumber(s) => write!(f, "Invalid number: '{}'", s), Self::MalformedNumber(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::MalformedChar(s) => write!(f, "Invalid character: '{}'", s), Self::MalformedChar(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::MalformedIdentifier(s) => write!(f, "Variable name is not proper: '{}'", s), Self::MalformedIdentifier(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::UnterminatedString => write!(f, "Open string is not terminated"), Self::UnterminatedString => f.write_str(self.desc()),
Self::StringTooLong(max) => write!( Self::StringTooLong(max) => write!(f, "{} ({})", self.desc(), max),
f,
"Length of string literal exceeds the maximum limit ({})",
max
),
Self::ImproperSymbol(s) => f.write_str(s), Self::ImproperSymbol(s) => f.write_str(s),
} }
} }
} }
impl LexError { impl LexError {
/// Convert a `LexError` into a `ParseError`. pub(crate) fn desc(&self) -> &str {
match self {
Self::UnexpectedInput(_) => "Unexpected character encountered",
Self::UnterminatedString => "Open string is not terminated",
Self::StringTooLong(_) => "Length of string literal exceeds the maximum limit",
Self::MalformedEscapeSequence(_) => "Invalid escape sequence",
Self::MalformedNumber(_) => "Invalid number",
Self::MalformedChar(_) => "Invalid character",
Self::MalformedIdentifier(_) => "Variable name is not proper",
Self::ImproperSymbol(_) => "Invalid symbol encountered",
}
}
/// Convert a `&LexError` into a `ParseError`.
#[inline(always)] #[inline(always)]
pub fn into_err(&self, pos: Position) -> ParseError { pub fn into_err(&self, pos: Position) -> ParseError {
ParseError(Box::new(self.into()), pos) ParseError(Box::new(self.clone().into()), pos)
} }
} }
@ -74,10 +82,10 @@ impl LexError {
#[derive(Debug, Eq, PartialEq, Clone, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Hash)]
#[non_exhaustive] #[non_exhaustive]
pub enum ParseErrorType { pub enum ParseErrorType {
/// Error in the script text. Wrapped value is the error message.
BadInput(String),
/// The script ends prematurely. /// The script ends prematurely.
UnexpectedEOF, UnexpectedEOF,
/// Error in the script text. Wrapped value is the lex error.
BadInput(LexError),
/// An unknown operator is encountered. Wrapped value is the operator. /// An unknown operator is encountered. Wrapped value is the operator.
UnknownOperator(String), UnknownOperator(String),
/// Expecting a particular token but not finding one. Wrapped values are the token and description. /// Expecting a particular token but not finding one. Wrapped values are the token and description.
@ -164,8 +172,8 @@ impl ParseErrorType {
pub(crate) fn desc(&self) -> &str { pub(crate) fn desc(&self) -> &str {
match self { match self {
Self::BadInput(p) => p,
Self::UnexpectedEOF => "Script is incomplete", Self::UnexpectedEOF => "Script is incomplete",
Self::BadInput(p) => p.desc(),
Self::UnknownOperator(_) => "Unknown operator", Self::UnknownOperator(_) => "Unknown operator",
Self::MissingToken(_, _) => "Expecting a certain token that is missing", Self::MissingToken(_, _) => "Expecting a certain token that is missing",
Self::MalformedCallExpr(_) => "Invalid expression in function call arguments", Self::MalformedCallExpr(_) => "Invalid expression in function call arguments",
@ -196,9 +204,9 @@ impl ParseErrorType {
impl fmt::Display for ParseErrorType { impl fmt::Display for ParseErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::BadInput(s) | ParseErrorType::MalformedCallExpr(s) => { Self::BadInput(err) => write!(f, "{}", err),
f.write_str(if s.is_empty() { self.desc() } else { s })
} Self::MalformedCallExpr(s) => f.write_str(if s.is_empty() { self.desc() } else { s }),
Self::UnknownOperator(s) => write!(f, "{}: '{}'", self.desc(), s), Self::UnknownOperator(s) => write!(f, "{}: '{}'", self.desc(), s),
Self::MalformedIndexExpr(s) | Self::MalformedInExpr(s) | Self::MalformedCapture(s) => { Self::MalformedIndexExpr(s) | Self::MalformedInExpr(s) | Self::MalformedCapture(s) => {
@ -247,14 +255,14 @@ impl fmt::Display for ParseErrorType {
} }
} }
impl From<&LexError> for ParseErrorType { impl From<LexError> for ParseErrorType {
#[inline(always)] #[inline(always)]
fn from(err: &LexError) -> Self { fn from(err: LexError) -> Self {
match err { match err {
LexError::StringTooLong(max) => { LexError::StringTooLong(max) => {
Self::LiteralTooLarge("Length of string literal".to_string(), *max) Self::LiteralTooLarge("Length of string literal".to_string(), max)
} }
_ => Self::BadInput(err.to_string()), _ => Self::BadInput(err),
} }
} }
} }
@ -282,7 +290,7 @@ impl fmt::Display for ParseError {
impl From<ParseErrorType> for Box<EvalAltResult> { impl From<ParseErrorType> for Box<EvalAltResult> {
#[inline(always)] #[inline(always)]
fn from(err: ParseErrorType) -> Self { fn from(err: ParseErrorType) -> Self {
Box::new(EvalAltResult::ErrorParsing(err, Position::none())) Box::new(EvalAltResult::ErrorParsing(err, NO_POS))
} }
} }

View File

@ -10,7 +10,9 @@ use crate::optimize::{optimize_into_ast, OptimizationLevel};
use crate::parse_error::{LexError, ParseError, ParseErrorType}; use crate::parse_error::{LexError, ParseError, ParseErrorType};
use crate::scope::{EntryType as ScopeEntryType, Scope}; use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::CustomSyntax; use crate::syntax::CustomSyntax;
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream}; use crate::token::{
is_keyword_function, is_valid_identifier, Position, Token, TokenStream, NO_POS,
};
use crate::utils::StraightHasherBuilder; use crate::utils::StraightHasherBuilder;
use crate::{calc_script_fn_hash, StaticVec}; use crate::{calc_script_fn_hash, StaticVec};
@ -816,10 +818,11 @@ fn parse_primary(
// Access to `this` as a variable is OK // Access to `this` as a variable is OK
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => { Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
if !settings.is_function_scope { if !settings.is_function_scope {
return Err( return Err(PERR::BadInput(LexError::ImproperSymbol(format!(
PERR::BadInput(format!("'{}' can only be used in functions", s)) "'{}' can only be used in functions",
.into_err(settings.pos), s
); )))
.into_err(settings.pos));
} else { } else {
Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None))) Expr::Variable(Box::new((Ident::new(s, settings.pos), None, 0, None)))
} }
@ -840,7 +843,8 @@ fn parse_primary(
_ => { _ => {
return Err( return Err(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos) PERR::BadInput(LexError::UnexpectedInput(token.syntax().to_string()))
.into_err(settings.pos),
); );
} }
}; };
@ -862,7 +866,9 @@ fn parse_primary(
return Err(if !match_token(input, Token::LeftParen).0 { return Err(if !match_token(input, Token::LeftParen).0 {
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos) LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(token_pos)
} else { } else {
PERR::BadInput("'!' cannot be used to call module functions".to_string()) PERR::BadInput(LexError::ImproperSymbol(
"'!' cannot be used to call module functions".to_string(),
))
.into_err(token_pos) .into_err(token_pos)
}); });
} }
@ -1140,9 +1146,10 @@ fn make_assignment_stmt<'a>(
Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position())) Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position()))
} }
// ??? && ??? = rhs, ??? || ??? = rhs // ??? && ??? = rhs, ??? || ??? = rhs
Expr::And(_, _) | Expr::Or(_, _) => { Expr::And(_, _) | Expr::Or(_, _) => Err(PERR::BadInput(LexError::ImproperSymbol(
Err(PERR::BadInput("Possibly a typo of '=='?".to_string()).into_err(pos)) "Possibly a typo of '=='?".to_string(),
} ))
.into_err(pos)),
// expr = rhs // expr = rhs
_ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())), _ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())),
} }
@ -1238,10 +1245,10 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
(_, Expr::FnCall(x, pos)) (_, Expr::FnCall(x, pos))
if x.args.len() == 0 && [KEYWORD_FN_PTR, KEYWORD_EVAL].contains(&x.name.as_ref()) => if x.args.len() == 0 && [KEYWORD_FN_PTR, KEYWORD_EVAL].contains(&x.name.as_ref()) =>
{ {
return Err(PERR::BadInput(format!( return Err(PERR::BadInput(LexError::ImproperSymbol(format!(
"'{}' should not be called in method style. Try {}(...);", "'{}' should not be called in method style. Try {}(...);",
x.name, x.name x.name, x.name
)) )))
.into_err(pos)); .into_err(pos));
} }
// lhs.func!(...) // lhs.func!(...)
@ -1734,9 +1741,10 @@ fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result
/// Make sure that the expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`). /// Make sure that the expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> { fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
match input.peek().unwrap() { match input.peek().unwrap() {
(Token::Equals, pos) => { (Token::Equals, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
Err(PERR::BadInput("Possibly a typo of '=='?".to_string()).into_err(*pos)) "Possibly a typo of '=='?".to_string(),
} ))
.into_err(*pos)),
(Token::PlusAssign, pos) (Token::PlusAssign, pos)
| (Token::MinusAssign, pos) | (Token::MinusAssign, pos)
| (Token::MultiplyAssign, pos) | (Token::MultiplyAssign, pos)
@ -1747,9 +1755,9 @@ fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
| (Token::PowerOfAssign, pos) | (Token::PowerOfAssign, pos)
| (Token::AndAssign, pos) | (Token::AndAssign, pos)
| (Token::OrAssign, pos) | (Token::OrAssign, pos)
| (Token::XOrAssign, pos) => Err(PERR::BadInput( | (Token::XOrAssign, pos) => Err(PERR::BadInput(LexError::ImproperSymbol(
"Expecting a boolean expression, not an assignment".to_string(), "Expecting a boolean expression, not an assignment".to_string(),
) ))
.into_err(*pos)), .into_err(*pos)),
_ => Ok(()), _ => Ok(()),
@ -2683,7 +2691,7 @@ impl Engine {
is_function_scope: false, is_function_scope: false,
is_breakable: false, is_breakable: false,
level: 0, level: 0,
pos: Position::none(), pos: NO_POS,
}; };
let expr = parse_expr(input, &mut state, &mut functions, settings)?; let expr = parse_expr(input, &mut state, &mut functions, settings)?;
@ -2694,7 +2702,8 @@ impl Engine {
// Return error if the expression doesn't end // Return error if the expression doesn't end
(token, pos) => { (token, pos) => {
return Err( return Err(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(*pos) PERR::BadInput(LexError::UnexpectedInput(token.syntax().to_string()))
.into_err(*pos),
) )
} }
} }
@ -2732,7 +2741,7 @@ impl Engine {
is_function_scope: false, is_function_scope: false,
is_breakable: false, is_breakable: false,
level: 0, level: 0,
pos: Position::none(), pos: NO_POS,
}; };
let stmt = match parse_stmt(input, &mut state, &mut functions, settings)? { let stmt = match parse_stmt(input, &mut state, &mut functions, settings)? {

View File

@ -2,7 +2,7 @@
use crate::dynamic::Dynamic; use crate::dynamic::Dynamic;
use crate::parse_error::ParseErrorType; use crate::parse_error::ParseErrorType;
use crate::token::Position; use crate::token::{Position, NO_POS};
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::INT; use crate::INT;
@ -252,7 +252,7 @@ impl fmt::Display for EvalAltResult {
impl<T: AsRef<str>> From<T> for EvalAltResult { impl<T: AsRef<str>> From<T> for EvalAltResult {
#[inline(always)] #[inline(always)]
fn from(err: T) -> Self { fn from(err: T) -> Self {
Self::ErrorRuntime(err.as_ref().to_string().into(), Position::none()) Self::ErrorRuntime(err.as_ref().to_string().into(), NO_POS)
} }
} }
@ -261,7 +261,7 @@ impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
fn from(err: T) -> Self { fn from(err: T) -> Self {
Box::new(EvalAltResult::ErrorRuntime( Box::new(EvalAltResult::ErrorRuntime(
err.as_ref().to_string().into(), err.as_ref().to_string().into(),
Position::none(), NO_POS,
)) ))
} }
} }
@ -324,7 +324,7 @@ impl EvalAltResult {
/// Get the `Position` of this error. /// Get the `Position` of this error.
pub fn position(&self) -> Position { pub fn position(&self) -> Position {
match self { match self {
Self::ErrorSystem(_, _) => Position::none(), Self::ErrorSystem(_, _) => NO_POS,
Self::ErrorParsing(_, pos) Self::ErrorParsing(_, pos)
| Self::ErrorFunctionNotFound(_, pos) | Self::ErrorFunctionNotFound(_, pos)

View File

@ -4,7 +4,7 @@ use super::str::ImmutableStringDeserializer;
use crate::dynamic::{Dynamic, Union}; use crate::dynamic::{Dynamic, Union};
use crate::parse_error::ParseErrorType; use crate::parse_error::ParseErrorType;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::NO_POS;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use serde::de::{ use serde::de::{
@ -45,11 +45,7 @@ impl<'de> DynamicDeserializer<'de> {
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> { fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(error.into(), self.value.type_name().into(), NO_POS)
error.into(),
self.value.type_name().into(),
Position::none(),
)
.into() .into()
} }
fn deserialize_int<V: Visitor<'de>>( fn deserialize_int<V: Visitor<'de>>(
@ -127,7 +123,10 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
impl Error for Box<EvalAltResult> { impl Error for Box<EvalAltResult> {
fn custom<T: fmt::Display>(err: T) -> Self { fn custom<T: fmt::Display>(err: T) -> Self {
EvalAltResult::ErrorParsing(ParseErrorType::BadInput(err.to_string()), Position::none()) EvalAltResult::ErrorParsing(ParseErrorType::BadInput(
LexError::ImproperSymbol(err.to_string()),
NO_POS,
))
.into() .into()
} }
} }

View File

@ -2,7 +2,7 @@
use crate::dynamic::Dynamic; use crate::dynamic::Dynamic;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::NO_POS;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;
@ -99,7 +99,7 @@ pub fn to_dynamic<T: Serialize>(value: T) -> Result<Dynamic, Box<EvalAltResult>>
impl Error for Box<EvalAltResult> { impl Error for Box<EvalAltResult> {
fn custom<T: fmt::Display>(err: T) -> Self { fn custom<T: fmt::Display>(err: T) -> Self {
EvalAltResult::ErrorRuntime(err.to_string().into(), Position::none()).into() EvalAltResult::ErrorRuntime(err.to_string().into(), NO_POS).into()
} }
} }
@ -295,11 +295,7 @@ impl Serializer for &mut DynamicSerializer {
make_variant(_variant, content) make_variant(_variant, content)
} }
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
return EvalAltResult::ErrorMismatchOutputType( return EvalAltResult::ErrorMismatchOutputType("Dynamic".into(), "map".into(), NO_POS)
"Dynamic".into(),
"map".into(),
Position::none(),
)
.into(); .into();
} }
@ -307,11 +303,7 @@ impl Serializer for &mut DynamicSerializer {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
return Ok(DynamicSerializer::new(Array::new().into())); return Ok(DynamicSerializer::new(Array::new().into()));
#[cfg(feature = "no_index")] #[cfg(feature = "no_index")]
return EvalAltResult::ErrorMismatchOutputType( return EvalAltResult::ErrorMismatchOutputType("Dynamic".into(), "array".into(), NO_POS)
"Dynamic".into(),
"array".into(),
Position::none(),
)
.into(); .into();
} }
@ -345,12 +337,7 @@ impl Serializer for &mut DynamicSerializer {
let err_type = "map"; let err_type = "map";
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
let err_type = "array"; let err_type = "array";
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType("Dynamic".into(), err_type.into(), NO_POS).into()
"Dynamic".into(),
err_type.into(),
Position::none(),
)
.into()
} }
} }
@ -358,11 +345,7 @@ impl Serializer for &mut DynamicSerializer {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
return Ok(DynamicSerializer::new(Map::new().into())); return Ok(DynamicSerializer::new(Map::new().into()));
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
return EvalAltResult::ErrorMismatchOutputType( return EvalAltResult::ErrorMismatchOutputType("Dynamic".into(), "map".into(), NO_POS)
"Dynamic".into(),
"map".into(),
Position::none(),
)
.into(); .into();
} }
@ -387,11 +370,7 @@ impl Serializer for &mut DynamicSerializer {
map: Map::with_capacity(_len), map: Map::with_capacity(_len),
}); });
#[cfg(feature = "no_object")] #[cfg(feature = "no_object")]
return EvalAltResult::ErrorMismatchOutputType( return EvalAltResult::ErrorMismatchOutputType("Dynamic".into(), "map".into(), NO_POS)
"Dynamic".into(),
"map".into(),
Position::none(),
)
.into(); .into();
} }
} }
@ -501,11 +480,7 @@ impl SerializeMap for DynamicSerializer {
let key = mem::take(&mut self._key) let key = mem::take(&mut self._key)
.take_immutable_string() .take_immutable_string()
.map_err(|typ| { .map_err(|typ| {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType("string".into(), typ.into(), NO_POS)
"string".into(),
typ.into(),
Position::none(),
)
})?; })?;
let _value = _value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let map = self._value.downcast_mut::<Map>().unwrap(); let map = self._value.downcast_mut::<Map>().unwrap();
@ -525,11 +500,7 @@ impl SerializeMap for DynamicSerializer {
{ {
let _key: Dynamic = _key.serialize(&mut *self)?; let _key: Dynamic = _key.serialize(&mut *self)?;
let _key = _key.take_immutable_string().map_err(|typ| { let _key = _key.take_immutable_string().map_err(|typ| {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType("string".into(), typ.into(), NO_POS)
"string".into(),
typ.into(),
Position::none(),
)
})?; })?;
let _value = _value.serialize(&mut *self)?; let _value = _value.serialize(&mut *self)?;
let map = self._value.downcast_mut::<Map>().unwrap(); let map = self._value.downcast_mut::<Map>().unwrap();

View File

@ -1,7 +1,7 @@
//! Implement deserialization support of `ImmutableString` for [`serde`](https://crates.io/crates/serde). //! Implement deserialization support of `ImmutableString` for [`serde`](https://crates.io/crates/serde).
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::NO_POS;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use serde::de::{Deserializer, Visitor}; use serde::de::{Deserializer, Visitor};
@ -20,11 +20,7 @@ impl<'a> ImmutableStringDeserializer<'a> {
} }
/// Shortcut for a type conversion error. /// Shortcut for a type conversion error.
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> { fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
EvalAltResult::ErrorMismatchOutputType( EvalAltResult::ErrorMismatchOutputType(type_name::<T>().into(), "string".into(), NO_POS)
type_name::<T>().into(),
"string".into(),
Position::none(),
)
.into() .into()
} }
} }

View File

@ -6,7 +6,7 @@ use crate::engine::{Engine, EvalContext, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT
use crate::fn_native::{SendSync, Shared}; use crate::fn_native::{SendSync, Shared};
use crate::parse_error::{LexError, ParseError}; use crate::parse_error::{LexError, ParseError};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position, Token}; use crate::token::{is_valid_identifier, Position, Token, NO_POS};
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::StaticVec; use crate::StaticVec;
@ -139,7 +139,7 @@ impl Engine {
segments.len() + 1, segments.len() + 1,
s s
)) ))
.into_err(Position::none()) .into_err(NO_POS)
.into()); .into());
} }
// Identifier in first position // Identifier in first position
@ -156,7 +156,7 @@ impl Engine {
segments.len() + 1, segments.len() + 1,
s s
)) ))
.into_err(Position::none()) .into_err(NO_POS)
.into()); .into());
} }
}; };

View File

@ -44,6 +44,9 @@ pub struct Position {
pos: u16, pos: u16,
} }
/// No `Position`.
pub const NO_POS: Position = Position { line: 0, pos: 0 };
impl Position { impl Position {
/// Create a new `Position`. /// Create a new `Position`.
/// ///
@ -121,7 +124,7 @@ impl Position {
/// Create a `Position` representing no position. /// Create a `Position` representing no position.
#[inline(always)] #[inline(always)]
pub fn none() -> Self { pub fn none() -> Self {
Self { line: 0, pos: 0 } NO_POS
} }
/// Is there no `Position`? /// Is there no `Position`?

View File

@ -38,7 +38,7 @@ fn test_max_string_size() -> Result<(), Box<EvalAltResult>> {
"# "#
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 13, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -52,7 +52,7 @@ fn test_max_string_size() -> Result<(), Box<EvalAltResult>> {
"# "#
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 100, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
engine.set_max_string_size(0); engine.set_max_string_size(0);
@ -98,7 +98,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -112,7 +112,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 100, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
assert!(matches!( assert!(matches!(
@ -124,7 +124,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -137,7 +137,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
assert!(matches!( assert!(matches!(
@ -151,7 +151,7 @@ fn test_max_array_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
engine.set_max_array_size(0); engine.set_max_array_size(0);
@ -216,7 +216,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
assert!(matches!( assert!(matches!(
@ -228,7 +228,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -241,7 +241,7 @@ fn test_max_map_size() -> Result<(), Box<EvalAltResult>> {
" "
) )
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorDataTooLarge(_, 10, 12, _) EvalAltResult::ErrorDataTooLarge(_, _)
)); ));
engine.set_max_map_size(0); engine.set_max_map_size(0);

View File

@ -1,5 +1,5 @@
#![cfg(not(feature = "unchecked"))] #![cfg(not(feature = "unchecked"))]
use rhai::{Engine, EvalAltResult}; use rhai::{Engine, EvalAltResult, INT};
#[test] #[test]
fn test_max_operations() -> Result<(), Box<EvalAltResult>> { fn test_max_operations() -> Result<(), Box<EvalAltResult>> {
@ -10,7 +10,7 @@ fn test_max_operations() -> Result<(), Box<EvalAltResult>> {
if count % 100 == 0 { if count % 100 == 0 {
println!("{}", count); println!("{}", count);
} }
true None
}); });
engine.eval::<()>("let x = 0; while x < 20 { x += 1; }")?; engine.eval::<()>("let x = 0; while x < 20 { x += 1; }")?;
@ -38,7 +38,7 @@ fn test_max_operations_functions() -> Result<(), Box<EvalAltResult>> {
if count % 100 == 0 { if count % 100 == 0 {
println!("{}", count); println!("{}", count);
} }
true None
}); });
engine.eval::<()>( engine.eval::<()>(
@ -94,7 +94,7 @@ fn test_max_operations_eval() -> Result<(), Box<EvalAltResult>> {
if count % 100 == 0 { if count % 100 == 0 {
println!("{}", count); println!("{}", count);
} }
true None
}); });
assert!(matches!( assert!(matches!(
@ -117,13 +117,19 @@ fn test_max_operations_progress() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new(); let mut engine = Engine::new();
engine.set_max_operations(500); engine.set_max_operations(500);
engine.on_progress(|&count| count < 100); engine.on_progress(|&count| {
if count < 100 {
None
} else {
Some((42 as INT).into())
}
});
assert!(matches!( assert!(matches!(
*engine *engine
.eval::<()>("for x in range(0, 500) {}") .eval::<()>("for x in range(0, 500) {}")
.expect_err("should error"), .expect_err("should error"),
EvalAltResult::ErrorTerminated(_) EvalAltResult::ErrorTerminated(x, _) if x.as_int()? == 42
)); ));
Ok(()) Ok(())

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult, ParseError, ParseErrorType, Position, INT}; use rhai::{Engine, EvalAltResult, LexError, ParseError, ParseErrorType, INT, NO_POS};
#[test] #[test]
fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> { fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
@ -68,9 +68,9 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
.register_custom_syntax(&["!"], 0, |_, _| Ok(().into())) .register_custom_syntax(&["!"], 0, |_, _| Ok(().into()))
.expect_err("should error") .expect_err("should error")
.0, .0,
ParseErrorType::BadInput( ParseErrorType::BadInput(LexError::ImproperSymbol(
"Improper symbol for custom syntax at position #1: '!'".to_string() "Improper symbol for custom syntax at position #1: '!'".to_string()
) ))
); );
Ok(()) Ok(())
@ -88,8 +88,10 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
2 => match stream[1].as_str() { 2 => match stream[1].as_str() {
"world" | "kitty" => Ok(None), "world" | "kitty" => Ok(None),
s => Err(ParseError( s => Err(ParseError(
Box::new(ParseErrorType::BadInput(s.to_string())), Box::new(ParseErrorType::BadInput(LexError::ImproperSymbol(
Position::none(), s.to_string(),
))),
NO_POS,
)), )),
}, },
_ => unreachable!(), _ => unreachable!(),
@ -109,7 +111,7 @@ fn test_custom_syntax_raw() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<INT>("hello kitty")?, 42); assert_eq!(engine.eval::<INT>("hello kitty")?, 42);
assert_eq!( assert_eq!(
*engine.compile("hello hey").expect_err("should error").0, *engine.compile("hello hey").expect_err("should error").0,
ParseErrorType::BadInput("hey".to_string()) ParseErrorType::BadInput(LexError::ImproperSymbol("hey".to_string()))
); );
Ok(()) Ok(())

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult, ParseErrorType, RegisterFn, INT}; use rhai::{Engine, EvalAltResult, LexError, ParseErrorType, RegisterFn, INT};
#[test] #[test]
fn test_tokens_disabled() { fn test_tokens_disabled() {
@ -16,10 +16,13 @@ fn test_tokens_disabled() {
engine.disable_symbol("+="); // disable the '+=' operator engine.disable_symbol("+="); // disable the '+=' operator
assert!(matches!( assert_eq!(
*engine.compile("let x = 40 + 2; x += 1;").expect_err("should error").0, *engine
ParseErrorType::BadInput(ref s) if s == "Unexpected '+='" .compile("let x = 40 + 2; x += 1;")
)); .expect_err("should error")
.0,
ParseErrorType::BadInput(LexError::UnexpectedInput("+=".to_string()))
);
} }
#[test] #[test]

View File

@ -1,4 +1,4 @@
use rhai::{Engine, EvalAltResult, Position, Scope, INT}; use rhai::{Engine, EvalAltResult, Scope, INT, NO_POS};
#[test] #[test]
fn test_var_scope() -> Result<(), Box<EvalAltResult>> { fn test_var_scope() -> Result<(), Box<EvalAltResult>> {
@ -67,7 +67,7 @@ fn test_var_resolver() -> Result<(), Box<EvalAltResult>> {
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())), "MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
// Override a variable - make it not found even if it exists! // Override a variable - make it not found even if it exists!
"DO_NOT_USE" => { "DO_NOT_USE" => {
Err(EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()).into()) Err(EvalAltResult::ErrorVariableNotFound(name.to_string(), NO_POS).into())
} }
// Silently maps 'chameleon' into 'innocent'. // Silently maps 'chameleon' into 'innocent'.
"chameleon" => context "chameleon" => context
@ -75,7 +75,7 @@ fn test_var_resolver() -> Result<(), Box<EvalAltResult>> {
.get_value("innocent") .get_value("innocent")
.map(Some) .map(Some)
.ok_or_else(|| { .ok_or_else(|| {
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()).into() EvalAltResult::ErrorVariableNotFound(name.to_string(), NO_POS).into()
}), }),
// Return Ok(None) to continue with the normal variable resolution process. // Return Ok(None) to continue with the normal variable resolution process.
_ => Ok(None), _ => Ok(None),