commit
22fe2d2c2e
@ -4,6 +4,11 @@ Rhai Release Notes
|
|||||||
Version 1.11.0
|
Version 1.11.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* A new feature flag, `stable_hash`, is added that forces hashing to be consistent using a fixed seed.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"]
|
|||||||
internals = [] # expose internal data structures
|
internals = [] # expose internal data structures
|
||||||
debugging = ["internals"] # enable debugging
|
debugging = ["internals"] # enable debugging
|
||||||
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
|
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
|
||||||
|
stable_hash = [] # perform all hashing with fixed seed value
|
||||||
|
|
||||||
# compiling for no-std
|
# compiling for no-std
|
||||||
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng", "hashbrown/ahash-compile-time-rng"]
|
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng", "hashbrown/ahash-compile-time-rng"]
|
||||||
|
@ -280,7 +280,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
Token::GreaterThanEqualsTo => Some(impl_op!(FLOAT => $xx >= $yy)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(FLOAT => $xx >= $yy)),
|
||||||
Token::LessThan => Some(impl_op!(FLOAT => $xx < $yy)),
|
Token::LessThan => Some(impl_op!(FLOAT => $xx < $yy)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(FLOAT => $xx <= $yy)),
|
Token::LessThanEqualsTo => Some(impl_op!(FLOAT => $xx <= $yy)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -308,7 +308,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
Token::Divide => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
Token::Divide => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
||||||
Token::Modulo => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
Token::Modulo => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
||||||
Token::PowerOf => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
Token::PowerOf => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
@ -322,17 +322,17 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
Token::Divide => return Some(impl_op!(from Decimal => $xx / $yy)),
|
Token::Divide => return Some(impl_op!(from Decimal => $xx / $yy)),
|
||||||
Token::Modulo => return Some(impl_op!(from Decimal => $xx % $yy)),
|
Token::Modulo => return Some(impl_op!(from Decimal => $xx % $yy)),
|
||||||
Token::PowerOf => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
Token::PowerOf => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(from Decimal => $xx == $yy)),
|
Token::EqualsTo => Some(impl_op!(from Decimal => $xx == $yy)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(from Decimal => $xx != $yy)),
|
Token::NotEqualsTo => Some(impl_op!(from Decimal => $xx != $yy)),
|
||||||
Token::GreaterThan => Some(impl_op!(from Decimal => $xx > $yy)),
|
Token::GreaterThan => Some(impl_op!(from Decimal => $xx > $yy)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(from Decimal => $xx >= $yy)),
|
Token::GreaterThanEqualsTo => Some(impl_op!(from Decimal => $xx >= $yy)),
|
||||||
Token::LessThan => Some(impl_op!(from Decimal => $xx < $yy)),
|
Token::LessThan => Some(impl_op!(from Decimal => $xx < $yy)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(from Decimal => $xx <= $yy)),
|
Token::LessThanEqualsTo => Some(impl_op!(from Decimal => $xx <= $yy)),
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -680,7 +680,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
Token::DivideAssign => Some(impl_op!($x /= $yy)),
|
Token::DivideAssign => Some(impl_op!($x /= $yy)),
|
||||||
Token::ModuloAssign => Some(impl_op!($x %= $yy)),
|
Token::ModuloAssign => Some(impl_op!($x %= $yy)),
|
||||||
Token::PowerOfAssign => Some(impl_op!($x => $xx.powf($yy as $x))),
|
Token::PowerOfAssign => Some(impl_op!($x => $xx.powf($yy as $x))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -707,7 +707,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
Token::DivideAssign => Some(impl_op!(from $x => divide($xx, $yy))),
|
Token::DivideAssign => Some(impl_op!(from $x => divide($xx, $yy))),
|
||||||
Token::ModuloAssign => Some(impl_op!(from $x => modulo($xx, $yy))),
|
Token::ModuloAssign => Some(impl_op!(from $x => modulo($xx, $yy))),
|
||||||
Token::PowerOfAssign => Some(impl_op!(from $x => power($xx, $yy))),
|
Token::PowerOfAssign => Some(impl_op!(from $x => power($xx, $yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
@ -715,13 +715,13 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(impl_op!(from $x += $yy)),
|
Token::PlusAssign => Some(impl_op!(from $x += $yy)),
|
||||||
Token::MinusAssign => Some(impl_op!(from $x -= $yy)),
|
Token::MinusAssign => Some(impl_op!(from $x -= $yy)),
|
||||||
Token::MultiplyAssign => Some(impl_op!(from $x *= $yy)),
|
Token::MultiplyAssign => Some(impl_op!(from $x *= $yy)),
|
||||||
Token::DivideAssign => Some(impl_op!(from $x /= $yy)),
|
Token::DivideAssign => Some(impl_op!(from $x /= $yy)),
|
||||||
Token::ModuloAssign => Some(impl_op!(from $x %= $yy)),
|
Token::ModuloAssign => Some(impl_op!(from $x %= $yy)),
|
||||||
Token::PowerOfAssign => Some(impl_op!(from $x => $xx.powd($yy))),
|
Token::PowerOfAssign => Some(impl_op!(from $x => $xx.powd($yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -74,7 +74,11 @@ impl BuildHasher for StraightHasherBuilder {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_hasher() -> ahash::AHasher {
|
pub fn get_hasher() -> ahash::AHasher {
|
||||||
ahash::AHasher::default()
|
if cfg!(feature = "stable_hash") {
|
||||||
|
ahash::RandomState::with_seeds(42, 999, 123, 0).build_hasher()
|
||||||
|
} else {
|
||||||
|
ahash::AHasher::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate a non-zero [`u64`] hash key from a namespace-qualified variable name.
|
/// Calculate a non-zero [`u64`] hash key from a namespace-qualified variable name.
|
||||||
|
@ -254,7 +254,7 @@ fn optimize_stmt_block(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Optimize each statement in the block
|
// Optimize each statement in the block
|
||||||
for stmt in statements.iter_mut() {
|
for stmt in &mut statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Stmt::Var(x, options, ..) => {
|
Stmt::Var(x, options, ..) => {
|
||||||
if options.contains(ASTFlags::CONSTANT) {
|
if options.contains(ASTFlags::CONSTANT) {
|
||||||
@ -688,7 +688,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
optimize_expr(match_expr, state, false);
|
optimize_expr(match_expr, state, false);
|
||||||
|
|
||||||
// Optimize blocks
|
// Optimize blocks
|
||||||
for b in expressions.iter_mut() {
|
for b in expressions.as_mut() {
|
||||||
optimize_expr(&mut b.condition, state, false);
|
optimize_expr(&mut b.condition, state, false);
|
||||||
optimize_expr(&mut b.expr, state, false);
|
optimize_expr(&mut b.expr, state, false);
|
||||||
|
|
||||||
@ -1204,7 +1204,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
x.args.iter_mut().for_each(|a| optimize_expr(a, state, false));
|
x.args.iter_mut().for_each(|a| optimize_expr(a, state, false));
|
||||||
|
|
||||||
// Move constant arguments
|
// Move constant arguments
|
||||||
for arg in x.args.iter_mut() {
|
for arg in &mut x.args {
|
||||||
match arg {
|
match arg {
|
||||||
Expr::DynamicConstant(..) | Expr::Unit(..)
|
Expr::DynamicConstant(..) | Expr::Unit(..)
|
||||||
| Expr::StringConstant(..) | Expr::CharConstant(..)
|
| Expr::StringConstant(..) | Expr::CharConstant(..)
|
||||||
@ -1254,7 +1254,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// id(args ..) or xxx.id(args ..) -> optimize function call arguments
|
// id(args ..) or xxx.id(args ..) -> optimize function call arguments
|
||||||
Expr::FnCall(x, ..) | Expr::MethodCall(x, ..) => for arg in x.args.iter_mut() {
|
Expr::FnCall(x, ..) | Expr::MethodCall(x, ..) => for arg in &mut x.args {
|
||||||
optimize_expr(arg, state, false);
|
optimize_expr(arg, state, false);
|
||||||
|
|
||||||
// Move constant arguments
|
// Move constant arguments
|
||||||
|
@ -834,7 +834,7 @@ pub mod array_functions {
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for item in array.iter_mut() {
|
for item in array {
|
||||||
if ctx
|
if ctx
|
||||||
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
.call_fn_raw(OP_EQUALS, true, false, &mut [item, &mut value.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
|
@ -928,7 +928,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref mut a, _, ref mut access) => {
|
Union::Array(ref mut a, _, ref mut access) => {
|
||||||
*access = typ;
|
*access = typ;
|
||||||
for v in a.iter_mut() {
|
for v in a.as_mut() {
|
||||||
v.set_access_mode(typ);
|
v.set_access_mode(typ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,47 +126,45 @@ impl Error for EvalAltResult {}
|
|||||||
impl fmt::Display for EvalAltResult {
|
impl fmt::Display for EvalAltResult {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(s, err) => match s.as_str() {
|
Self::ErrorSystem(s, err) if s.is_empty() => write!(f, "{err}")?,
|
||||||
"" => write!(f, "{}", err),
|
Self::ErrorSystem(s, err) => write!(f, "{s}: {err}")?,
|
||||||
s => write!(f, "{}: {}", s, err),
|
|
||||||
}?,
|
|
||||||
|
|
||||||
Self::ErrorParsing(p, ..) => write!(f, "Syntax error: {}", p)?,
|
Self::ErrorParsing(p, ..) => write!(f, "Syntax error: {p}")?,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::ErrorInFunctionCall(s, src, err, ..) if crate::parser::is_anonymous_fn(s) => {
|
Self::ErrorInFunctionCall(s, src, err, ..) if crate::parser::is_anonymous_fn(s) => {
|
||||||
write!(f, "{} in call to closure", err)?;
|
write!(f, "{err} in call to closure")?;
|
||||||
if !src.is_empty() {
|
if !src.is_empty() {
|
||||||
write!(f, " @ '{}'", src)?;
|
write!(f, " @ '{src}'")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::ErrorInFunctionCall(s, src, err, ..) => {
|
Self::ErrorInFunctionCall(s, src, err, ..) => {
|
||||||
write!(f, "{} in call to function {}", err, s)?;
|
write!(f, "{err} in call to function {s}")?;
|
||||||
if !src.is_empty() {
|
if !src.is_empty() {
|
||||||
write!(f, " @ '{}'", src)?;
|
write!(f, " @ '{src}'")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::ErrorInModule(s, err, ..) if s.is_empty() => {
|
Self::ErrorInModule(s, err, ..) if s.is_empty() => {
|
||||||
write!(f, "Error in module > {}", err)?
|
write!(f, "Error in module > {err}")?
|
||||||
}
|
}
|
||||||
Self::ErrorInModule(s, err, ..) => write!(f, "Error in module '{}' > {}", s, err)?,
|
Self::ErrorInModule(s, err, ..) => write!(f, "Error in module '{s}' > {err}")?,
|
||||||
|
|
||||||
Self::ErrorVariableExists(s, ..) => write!(f, "Variable already defined: {}", s)?,
|
Self::ErrorVariableExists(s, ..) => write!(f, "Variable already defined: {s}")?,
|
||||||
Self::ErrorForbiddenVariable(s, ..) => write!(f, "Forbidden variable name: {}", s)?,
|
Self::ErrorForbiddenVariable(s, ..) => write!(f, "Forbidden variable name: {s}")?,
|
||||||
Self::ErrorVariableNotFound(s, ..) => write!(f, "Variable not found: {}", s)?,
|
Self::ErrorVariableNotFound(s, ..) => write!(f, "Variable not found: {s}")?,
|
||||||
Self::ErrorPropertyNotFound(s, ..) => write!(f, "Property not found: {}", s)?,
|
Self::ErrorPropertyNotFound(s, ..) => write!(f, "Property not found: {s}")?,
|
||||||
Self::ErrorIndexNotFound(s, ..) => write!(f, "Invalid index: {}", s)?,
|
Self::ErrorIndexNotFound(s, ..) => write!(f, "Invalid index: {s}")?,
|
||||||
Self::ErrorFunctionNotFound(s, ..) => write!(f, "Function not found: {}", s)?,
|
Self::ErrorFunctionNotFound(s, ..) => write!(f, "Function not found: {s}")?,
|
||||||
Self::ErrorModuleNotFound(s, ..) => write!(f, "Module not found: {}", s)?,
|
Self::ErrorModuleNotFound(s, ..) => write!(f, "Module not found: {s}")?,
|
||||||
Self::ErrorDataRace(s, ..) => {
|
Self::ErrorDataRace(s, ..) => {
|
||||||
write!(f, "Data race detected when accessing variable: {}", s)?
|
write!(f, "Data race detected when accessing variable: {s}")?
|
||||||
}
|
}
|
||||||
Self::ErrorDotExpr(s, ..) => match s.as_str() {
|
|
||||||
"" => f.write_str("Malformed dot expression"),
|
Self::ErrorDotExpr(s, ..) if s.is_empty() => f.write_str("Malformed dot expression")?,
|
||||||
s => f.write_str(s),
|
Self::ErrorDotExpr(s, ..) => f.write_str(s)?,
|
||||||
}?,
|
|
||||||
Self::ErrorIndexingType(s, ..) => write!(f, "Indexer unavailable: {}", s)?,
|
Self::ErrorIndexingType(s, ..) => write!(f, "Indexer unavailable: {s}")?,
|
||||||
Self::ErrorUnboundThis(..) => f.write_str("'this' not bound")?,
|
Self::ErrorUnboundThis(..) => f.write_str("'this' not bound")?,
|
||||||
Self::ErrorFor(..) => f.write_str("For loop expects an iterable type")?,
|
Self::ErrorFor(..) => f.write_str("For loop expects an iterable type")?,
|
||||||
Self::ErrorTooManyOperations(..) => f.write_str("Too many operations")?,
|
Self::ErrorTooManyOperations(..) => f.write_str("Too many operations")?,
|
||||||
@ -181,63 +179,57 @@ impl fmt::Display for EvalAltResult {
|
|||||||
{
|
{
|
||||||
write!(f, "Runtime error")?
|
write!(f, "Runtime error")?
|
||||||
}
|
}
|
||||||
Self::ErrorRuntime(d, ..) => write!(f, "Runtime error: {}", d)?,
|
Self::ErrorRuntime(d, ..) => write!(f, "Runtime error: {d}")?,
|
||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, ..) => write!(f, "Cannot modify constant: {}", s)?,
|
Self::ErrorAssignmentToConstant(s, ..) => write!(f, "Cannot modify constant: {s}")?,
|
||||||
Self::ErrorMismatchOutputType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
Self::ErrorMismatchOutputType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
||||||
("", e) => write!(f, "Output type incorrect, expecting {}", e),
|
("", e) => write!(f, "Output type incorrect, expecting {e}"),
|
||||||
(a, "") => write!(f, "Output type incorrect: {}", a),
|
(a, "") => write!(f, "Output type incorrect: {a}"),
|
||||||
(a, e) => write!(f, "Output type incorrect: {} (expecting {})", a, e),
|
(a, e) => write!(f, "Output type incorrect: {a} (expecting {e})"),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorMismatchDataType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
Self::ErrorMismatchDataType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
||||||
("", e) => write!(f, "Data type incorrect, expecting {}", e),
|
("", e) => write!(f, "Data type incorrect, expecting {e}"),
|
||||||
(a, "") => write!(f, "Data type incorrect: {}", a),
|
(a, "") => write!(f, "Data type incorrect: {a}"),
|
||||||
(a, e) => write!(f, "Data type incorrect: {} (expecting {})", a, e),
|
(a, e) => write!(f, "Data type incorrect: {a} (expecting {e})"),
|
||||||
}?,
|
|
||||||
Self::ErrorArithmetic(s, ..) => match s.as_str() {
|
|
||||||
"" => f.write_str("Arithmetic error"),
|
|
||||||
s => f.write_str(s),
|
|
||||||
}?,
|
}?,
|
||||||
|
|
||||||
|
Self::ErrorArithmetic(s, ..) if s.is_empty() => f.write_str("Arithmetic error")?,
|
||||||
|
Self::ErrorArithmetic(s, ..) => f.write_str(s)?,
|
||||||
|
|
||||||
Self::LoopBreak(true, ..) => f.write_str("'break' not inside a loop")?,
|
Self::LoopBreak(true, ..) => f.write_str("'break' not inside a loop")?,
|
||||||
Self::LoopBreak(false, ..) => f.write_str("'continue' not inside a loop")?,
|
Self::LoopBreak(false, ..) => f.write_str("'continue' not inside a loop")?,
|
||||||
|
|
||||||
Self::Return(..) => f.write_str("NOT AN ERROR - function returns value")?,
|
Self::Return(..) => f.write_str("NOT AN ERROR - function returns value")?,
|
||||||
|
|
||||||
Self::ErrorArrayBounds(max, index, ..) => match max {
|
Self::ErrorArrayBounds(max, index, ..) => match max {
|
||||||
0 => write!(f, "Array index {} out of bounds: array is empty", index),
|
0 => write!(f, "Array index {index} out of bounds: array is empty"),
|
||||||
1 => write!(
|
1 => write!(
|
||||||
f,
|
f,
|
||||||
"Array index {} out of bounds: only 1 element in array",
|
"Array index {index} out of bounds: only 1 element in array",
|
||||||
index
|
|
||||||
),
|
),
|
||||||
_ => write!(
|
_ => write!(
|
||||||
f,
|
f,
|
||||||
"Array index {} out of bounds: only {} elements in array",
|
"Array index {index} out of bounds: only {max} elements in array",
|
||||||
index, max
|
|
||||||
),
|
),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorStringBounds(max, index, ..) => match max {
|
Self::ErrorStringBounds(max, index, ..) => match max {
|
||||||
0 => write!(f, "String index {} out of bounds: string is empty", index),
|
0 => write!(f, "String index {index} out of bounds: string is empty"),
|
||||||
1 => write!(
|
1 => write!(
|
||||||
f,
|
f,
|
||||||
"String index {} out of bounds: only 1 character in string",
|
"String index {index} out of bounds: only 1 character in string",
|
||||||
index
|
|
||||||
),
|
),
|
||||||
_ => write!(
|
_ => write!(
|
||||||
f,
|
f,
|
||||||
"String index {} out of bounds: only {} characters in string",
|
"String index {index} out of bounds: only {max} characters in string",
|
||||||
index, max
|
|
||||||
),
|
),
|
||||||
}?,
|
}?,
|
||||||
Self::ErrorBitFieldBounds(max, index, ..) => write!(
|
Self::ErrorBitFieldBounds(max, index, ..) => write!(
|
||||||
f,
|
f,
|
||||||
"Bit-field index {} out of bounds: only {} bits in bit-field",
|
"Bit-field index {index} out of bounds: only {max} bits in bit-field",
|
||||||
index, max
|
|
||||||
)?,
|
)?,
|
||||||
Self::ErrorDataTooLarge(typ, ..) => write!(f, "{} exceeds maximum limit", typ)?,
|
Self::ErrorDataTooLarge(typ, ..) => write!(f, "{typ} exceeds maximum limit")?,
|
||||||
|
|
||||||
Self::ErrorCustomSyntax(s, tokens, ..) => write!(f, "{}: {}", s, tokens.join(" "))?,
|
Self::ErrorCustomSyntax(s, tokens, ..) => write!(f, "{s}: {}", tokens.join(" "))?,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not write any position if None
|
// Do not write any position if None
|
||||||
|
@ -184,77 +184,69 @@ 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(err) => write!(f, "{}", err),
|
Self::BadInput(err) => write!(f, "{err}"),
|
||||||
|
|
||||||
Self::UnknownOperator(s) => write!(f, "Unknown operator: '{}'", s),
|
Self::UnknownOperator(s) => write!(f, "Unknown operator: '{s}'"),
|
||||||
|
|
||||||
Self::MalformedCallExpr(s) => match s.as_str() {
|
Self::MalformedCallExpr(s) if s.is_empty() => f.write_str(s),
|
||||||
"" => f.write_str("Invalid expression in function call arguments"),
|
Self::MalformedCallExpr(..) => f.write_str("Invalid expression in function call arguments"),
|
||||||
s => f.write_str(s)
|
|
||||||
},
|
Self::MalformedIndexExpr(s) if s.is_empty() => f.write_str("Invalid index in indexing expression"),
|
||||||
Self::MalformedIndexExpr(s) => match s.as_str() {
|
Self::MalformedIndexExpr(s) => f.write_str(s),
|
||||||
"" => f.write_str("Invalid index in indexing expression"),
|
|
||||||
s => f.write_str(s)
|
Self::MalformedInExpr(s) if s.is_empty() => f.write_str("Invalid 'in' expression"),
|
||||||
},
|
Self::MalformedInExpr(s) => f.write_str(s),
|
||||||
Self::MalformedInExpr(s) => match s.as_str() {
|
|
||||||
"" => f.write_str("Invalid 'in' expression"),
|
Self::MalformedCapture(s) if s.is_empty() => f.write_str("Invalid capturing"),
|
||||||
s => f.write_str(s)
|
Self::MalformedCapture(s) => f.write_str(s),
|
||||||
},
|
|
||||||
Self::MalformedCapture(s) => match s.as_str() {
|
|
||||||
"" => f.write_str("Invalid capturing"),
|
|
||||||
s => f.write_str(s)
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::FnDuplicatedDefinition(s, n) => {
|
Self::FnDuplicatedDefinition(s, n) => {
|
||||||
write!(f, "Function {} with ", s)?;
|
write!(f, "Function {s} with ")?;
|
||||||
match n {
|
match n {
|
||||||
0 => f.write_str("no parameters already exists"),
|
0 => f.write_str("no parameters already exists"),
|
||||||
1 => f.write_str("1 parameter already exists"),
|
1 => f.write_str("1 parameter already exists"),
|
||||||
_ => write!(f, "{} parameters already exists", n),
|
_ => write!(f, "{n} parameters already exists"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::FnMissingBody(s) => match s.as_str() {
|
|
||||||
"" => f.write_str("Expecting body statement block for anonymous function"),
|
|
||||||
s => write!(f, "Expecting body statement block for function {}", s)
|
|
||||||
},
|
|
||||||
Self::FnMissingParams(s) => write!(f, "Expecting parameters for function {}", s),
|
|
||||||
Self::FnDuplicatedParam(s, arg) => write!(f, "Duplicated parameter {} for function {}", arg, s),
|
|
||||||
|
|
||||||
Self::DuplicatedProperty(s) => write!(f, "Duplicated property for object map literal: {}", s),
|
Self::FnMissingBody(s) if s.is_empty() => f.write_str("Expecting body statement block for anonymous function"),
|
||||||
|
Self::FnMissingBody(s) => write!(f, "Expecting body statement block for function {s}"),
|
||||||
|
|
||||||
|
Self::FnMissingParams(s) => write!(f, "Expecting parameters for function {s}"),
|
||||||
|
Self::FnDuplicatedParam(s, arg) => write!(f, "Duplicated parameter {arg} for function {s}"),
|
||||||
|
|
||||||
|
Self::DuplicatedProperty(s) => write!(f, "Duplicated property for object map literal: {s}"),
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
Self::DuplicatedSwitchCase => f.write_str("Duplicated switch case"),
|
Self::DuplicatedSwitchCase => f.write_str("Duplicated switch case"),
|
||||||
Self::DuplicatedVariable(s) => write!(f, "Duplicated variable name: {}", s),
|
Self::DuplicatedVariable(s) => write!(f, "Duplicated variable name: {s}"),
|
||||||
|
|
||||||
Self::VariableExists(s) => write!(f, "Variable already defined: {}", s),
|
Self::VariableExists(s) => write!(f, "Variable already defined: {s}"),
|
||||||
Self::VariableUndefined(s) => write!(f, "Undefined variable: {}", s),
|
Self::VariableUndefined(s) => write!(f, "Undefined variable: {s}"),
|
||||||
Self::ModuleUndefined(s) => write!(f, "Undefined module: {}", s),
|
Self::ModuleUndefined(s) => write!(f, "Undefined module: {s}"),
|
||||||
|
|
||||||
Self::MismatchedType(r, a) => write!(f, "Expecting {}, not {}", r, a),
|
Self::MismatchedType(r, a) => write!(f, "Expecting {r}, not {a}"),
|
||||||
Self::ExprExpected(s) => write!(f, "Expecting {} expression", s),
|
Self::ExprExpected(s) => write!(f, "Expecting {} expression", s),
|
||||||
Self::MissingToken(token, s) => write!(f, "Expecting '{}' {}", token, s),
|
Self::MissingToken(token, s) => write!(f, "Expecting '{token}' {s}"),
|
||||||
|
|
||||||
Self::MissingSymbol(s) if s.is_empty() => f.write_str("Expecting a symbol"),
|
Self::MissingSymbol(s) if s.is_empty() => f.write_str("Expecting a symbol"),
|
||||||
Self::MissingSymbol(s) => f.write_str(s),
|
Self::MissingSymbol(s) => f.write_str(s),
|
||||||
|
|
||||||
Self::AssignmentToConstant(s) => match s.as_str() {
|
Self::AssignmentToConstant(s) if s.is_empty() => f.write_str("Cannot assign to a constant value"),
|
||||||
"" => f.write_str("Cannot assign to a constant value"),
|
Self::AssignmentToConstant(s) => write!(f, "Cannot assign to constant {s}"),
|
||||||
s => write!(f, "Cannot assign to constant {}", s)
|
|
||||||
},
|
|
||||||
Self::AssignmentToInvalidLHS(s) => match s.as_str() {
|
|
||||||
"" => f.write_str("Expression cannot be assigned to"),
|
|
||||||
s => f.write_str(s)
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::LiteralTooLarge(typ, max) => write!(f, "{} exceeds the maximum limit ({})", typ, max),
|
Self::AssignmentToInvalidLHS(s) if s.is_empty() => f.write_str("Expression cannot be assigned to"),
|
||||||
Self::Reserved(s) if is_valid_identifier(s.chars()) => write!(f, "'{}' is a reserved keyword", s),
|
Self::AssignmentToInvalidLHS(s) => f.write_str(s),
|
||||||
Self::Reserved(s) => write!(f, "'{}' is a reserved symbol", s),
|
|
||||||
|
Self::LiteralTooLarge(typ, max) => write!(f, "{typ} exceeds the maximum limit ({max})"),
|
||||||
|
Self::Reserved(s) if is_valid_identifier(s.chars()) => write!(f, "'{s}' is a reserved keyword"),
|
||||||
|
Self::Reserved(s) => write!(f, "'{s}' is a reserved symbol"),
|
||||||
Self::UnexpectedEOF => f.write_str("Script is incomplete"),
|
Self::UnexpectedEOF => f.write_str("Script is incomplete"),
|
||||||
Self::WrongSwitchIntegerCase => f.write_str("Integer switch case cannot follow a range case"),
|
Self::WrongSwitchIntegerCase => f.write_str("Integer switch case cannot follow a range case"),
|
||||||
Self::WrongSwitchDefaultCase => f.write_str("Default switch case must be the last"),
|
Self::WrongSwitchDefaultCase => f.write_str("Default switch case must be the last"),
|
||||||
Self::WrongSwitchCaseCondition => f.write_str("This switch case cannot have a condition"),
|
Self::WrongSwitchCaseCondition => f.write_str("This switch case cannot have a condition"),
|
||||||
Self::PropertyExpected => f.write_str("Expecting name of a property"),
|
Self::PropertyExpected => f.write_str("Expecting name of a property"),
|
||||||
Self::VariableExpected => f.write_str("Expecting name of a variable"),
|
Self::VariableExpected => f.write_str("Expecting name of a variable"),
|
||||||
Self::ForbiddenVariable(s) => write!(f, "Forbidden variable name: {}", s),
|
Self::ForbiddenVariable(s) => write!(f, "Forbidden variable name: {s}"),
|
||||||
Self::WrongFnDefinition => f.write_str("Function definitions must be at global level and cannot be inside a block or another function"),
|
Self::WrongFnDefinition => f.write_str("Function definitions must be at global level and cannot be inside a block or another function"),
|
||||||
Self::FnMissingName => f.write_str("Expecting function name in function declaration"),
|
Self::FnMissingName => f.write_str("Expecting function name in function declaration"),
|
||||||
Self::WrongDocComment => f.write_str("Doc-comment must be followed immediately by a function definition"),
|
Self::WrongDocComment => f.write_str("Doc-comment must be followed immediately by a function definition"),
|
||||||
|
Loading…
Reference in New Issue
Block a user