Fix parser bug.

This commit is contained in:
Stephen Chung 2022-02-18 11:05:58 +08:00
parent 1011602cf6
commit 83786c992b
2 changed files with 57 additions and 37 deletions

View File

@ -1,6 +1,15 @@
Rhai Release Notes
==================
Version 1.6.0
=============
Bug fixes
---------
* Invalid property or method access such as `a.b::c.d` or `a.b::func()` no longer panics but properly returns a syntax error.
Version 1.5.0
=============

View File

@ -1908,7 +1908,7 @@ fn make_dot_expr(
// lhs.module::id - syntax error
#[cfg(not(feature = "no_module"))]
(.., Expr::Variable(.., x)) => {
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0[0].pos))
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0.position()))
}
#[cfg(feature = "no_module")]
(.., Expr::Variable(..)) => unreachable!("qualified property name"),
@ -1918,6 +1918,41 @@ fn make_dot_expr(
false,
op_pos,
)),
// lhs.nnn::func(...) - syntax error
(.., Expr::FnCall(func, ..)) if func.is_qualified() => {
Err(PERR::PropertyExpected.into_err(func.namespace.expect("`Some`").position()))
}
// lhs.Fn() or lhs.eval()
(.., Expr::FnCall(func, func_pos))
if func.args.is_empty()
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
.contains(&func.name.as_ref()) =>
{
let err_msg = format!(
"'{}' should not be called in method style. Try {}(...);",
func.name, func.name
);
Err(LexError::ImproperSymbol(func.name.to_string(), err_msg).into_err(func_pos))
}
// lhs.func!(...)
(.., Expr::FnCall(func, func_pos)) if func.capture_parent_scope => {
Err(PERR::MalformedCapture(
"method-call style does not support running within the caller's scope".into(),
)
.into_err(func_pos))
}
// lhs.func(...)
(lhs, Expr::FnCall(mut func, func_pos)) => {
// Recalculate hash
func.hashes = FnCallHashes::from_all(
#[cfg(not(feature = "no_function"))]
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
);
let rhs = Expr::FnCall(func, func_pos);
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
}
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
(lhs, rhs @ Expr::Dot(..)) | (lhs, rhs @ Expr::Index(..)) => {
let (x, term, pos, is_dot) = match rhs {
@ -1927,6 +1962,17 @@ fn make_dot_expr(
};
match x.lhs {
// lhs.module::id.dot_rhs or lhs.module::id[idx_rhs] - syntax error
#[cfg(not(feature = "no_module"))]
Expr::Variable(.., x) if x.1.is_some() => {
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0.position()))
}
// lhs.module::func().dot_rhs or lhs.module::func()[idx_rhs] - syntax error
#[cfg(not(feature = "no_module"))]
Expr::FnCall(func, ..) if func.is_qualified() => {
Err(PERR::PropertyExpected.into_err(func.namespace.expect("`Some`").position()))
}
// lhs.id.dot_rhs or lhs.id[idx_rhs]
Expr::Variable(..) | Expr::Property(..) => {
let new_lhs = BinaryExpr {
lhs: x.lhs.into_property(state),
@ -1941,6 +1987,7 @@ fn make_dot_expr(
};
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
}
// lhs.func().dot_rhs or lhs.func()[idx_rhs]
Expr::FnCall(mut func, func_pos) => {
// Recalculate hash
func.hashes = FnCallHashes::from_all(
@ -1965,42 +2012,6 @@ fn make_dot_expr(
expr => unreachable!("invalid dot expression: {:?}", expr),
}
}
// lhs.nnn::func(...)
(.., Expr::FnCall(x, ..)) if x.is_qualified() => {
unreachable!("method call should not be namespace-qualified")
}
// lhs.Fn() or lhs.eval()
(.., Expr::FnCall(x, pos))
if x.args.is_empty()
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
.contains(&x.name.as_ref()) =>
{
Err(LexError::ImproperSymbol(
x.name.to_string(),
format!(
"'{}' should not be called in method style. Try {}(...);",
x.name, x.name
),
)
.into_err(pos))
}
// lhs.func!(...)
(.., Expr::FnCall(x, pos)) if x.capture_parent_scope => Err(PERR::MalformedCapture(
"method-call style does not support running within the caller's scope".into(),
)
.into_err(pos)),
// lhs.func(...)
(lhs, Expr::FnCall(mut func, func_pos)) => {
// Recalculate hash
func.hashes = FnCallHashes::from_all(
#[cfg(not(feature = "no_function"))]
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
);
let rhs = Expr::FnCall(func, func_pos);
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
}
// lhs.rhs
(.., rhs) => Err(PERR::PropertyExpected.into_err(rhs.start_position())),
}