Fix unary operators binding.

This commit is contained in:
Stephen Chung
2020-12-21 17:39:37 +08:00
parent 730a7320d6
commit 2955a4ab64
6 changed files with 85 additions and 25 deletions

View File

@@ -1105,6 +1105,12 @@ fn parse_primary(
(expr, Token::LeftBracket) => {
parse_index_chain(input, state, lib, expr, settings.level_up())?
}
// Method access
#[cfg(not(feature = "no_object"))]
(expr, Token::Period) => {
let rhs = parse_unary(input, state, lib, settings.level_up())?;
make_dot_expr(state, expr, rhs, token_pos)?
}
// Unknown postfix operator
(expr, token) => unreachable!(
"unknown postfix operator '{}' for {:?}",
@@ -1114,20 +1120,25 @@ fn parse_primary(
}
}
// Cache the hash key for namespace-qualified variables
match &mut root_expr {
// Cache the hash key for namespace-qualified variables
Expr::Variable(x) if x.1.is_some() => {
let (_, modules, hash, IdentX { name, .. }) = x.as_mut();
let namespace = modules.as_mut().unwrap();
// Qualifiers + variable name
*hash = calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0);
#[cfg(not(feature = "no_module"))]
namespace.set_index(state.find_module(&namespace[0].name));
}
_ => (),
Expr::Variable(x) if x.1.is_some() => Some(x),
Expr::Index(x, _) | Expr::Dot(x, _) => match &mut x.lhs {
Expr::Variable(x) if x.1.is_some() => Some(x),
_ => None,
},
_ => None,
}
.map(|x| {
let (_, modules, hash, IdentX { name, .. }) = x.as_mut();
let namespace = modules.as_mut().unwrap();
// Qualifiers + variable name
*hash = calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0);
#[cfg(not(feature = "no_module"))]
namespace.set_index(state.find_module(&namespace[0].name));
});
// Make sure identifiers are valid
Ok(root_expr)
@@ -1201,8 +1212,33 @@ fn parse_unary(
}
// +expr
Token::UnaryPlus => {
eat_token(input, Token::UnaryPlus);
parse_unary(input, state, lib, settings.level_up())
let pos = eat_token(input, Token::UnaryPlus);
match parse_unary(input, state, lib, settings.level_up())? {
expr @ Expr::IntegerConstant(_, _) => Ok(expr),
#[cfg(not(feature = "no_float"))]
expr @ Expr::FloatConstant(_, _) => Ok(expr),
// Call plus function
expr => {
let op = "+";
let hash = calc_script_fn_hash(empty(), op, 1);
let mut args = StaticVec::new();
args.push(expr);
Ok(Expr::FnCall(
Box::new(FnCallExpr {
name: op.into(),
native_only: true,
namespace: None,
hash,
args,
..Default::default()
}),
pos,
))
}
}
}
// !expr
Token::Bang => {
@@ -1770,6 +1806,7 @@ fn parse_binary_op(
make_in_expr(current_lhs, rhs, pos)?
}
// This is needed to parse closure followed by a dot.
#[cfg(not(feature = "no_object"))]
Token::Period => {
let rhs = args.pop().unwrap();