Fix constant assignment.
This commit is contained in:
parent
b9de8eaa7f
commit
f74d947c6b
@ -156,11 +156,16 @@ fn call_fn_with_constant_arguments(
|
|||||||
/// Optimize a statement.
|
/// Optimize a statement.
|
||||||
fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
||||||
match stmt {
|
match stmt {
|
||||||
// id op= expr
|
// expr op= expr
|
||||||
Stmt::Assignment(x, pos) => Stmt::Assignment(
|
Stmt::Assignment(x, pos) => match x.0 {
|
||||||
|
Expr::Variable(_) => {
|
||||||
|
Stmt::Assignment(Box::new((x.0, x.1, optimize_expr(x.2, state))), pos)
|
||||||
|
}
|
||||||
|
_ => Stmt::Assignment(
|
||||||
Box::new((optimize_expr(x.0, state), x.1, optimize_expr(x.2, state))),
|
Box::new((optimize_expr(x.0, state), x.1, optimize_expr(x.2, state))),
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
|
},
|
||||||
// if false { if_block } -> Noop
|
// if false { if_block } -> Noop
|
||||||
Stmt::IfThenElse(Expr::False(pos), x, _) if x.1.is_none() => {
|
Stmt::IfThenElse(Expr::False(pos), x, _) if x.1.is_none() => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -462,6 +467,11 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
.map(|(_, mut expr)| { expr.set_position(pos); expr })
|
.map(|(_, mut expr)| { expr.set_position(pos); expr })
|
||||||
.unwrap_or_else(|| Expr::Unit(pos))
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
|
// var.rhs
|
||||||
|
(lhs @ Expr::Variable(_), rhs) => Expr::Dot(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
}), dot_pos),
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
(lhs, rhs) => Expr::Dot(Box::new(BinaryExpr {
|
(lhs, rhs) => Expr::Dot(Box::new(BinaryExpr {
|
||||||
lhs: optimize_expr(lhs, state),
|
lhs: optimize_expr(lhs, state),
|
||||||
@ -498,6 +508,11 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
Expr::CharConstant(s.name.chars().nth(i as usize).unwrap(), s.pos)
|
Expr::CharConstant(s.name.chars().nth(i as usize).unwrap(), s.pos)
|
||||||
}
|
}
|
||||||
|
// var[rhs]
|
||||||
|
(lhs @ Expr::Variable(_), rhs) => Expr::Index(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
}), idx_pos),
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
(lhs, rhs) => Expr::Index(Box::new(BinaryExpr {
|
(lhs, rhs) => Expr::Index(Box::new(BinaryExpr {
|
||||||
lhs: optimize_expr(lhs, state),
|
lhs: optimize_expr(lhs, state),
|
||||||
|
@ -1087,7 +1087,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
match &lhs {
|
match &lhs {
|
||||||
// var (non-indexed) = rhs
|
// var (non-indexed) = rhs
|
||||||
Expr::Variable(x) if x.1.is_none() => {
|
Expr::Variable(x) if x.0.is_none() => {
|
||||||
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// var (indexed) = rhs
|
// var (indexed) = rhs
|
||||||
@ -1114,7 +1114,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
// xxx[???] = rhs, xxx.??? = rhs
|
// xxx[???] = rhs, xxx.??? = rhs
|
||||||
Expr::Index(x, _) | Expr::Dot(x, _) => match &x.lhs {
|
Expr::Index(x, _) | Expr::Dot(x, _) => match &x.lhs {
|
||||||
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
||||||
Expr::Variable(x) if x.1.is_none() => {
|
Expr::Variable(x) if x.0.is_none() => {
|
||||||
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
Ok(Stmt::Assignment(Box::new((lhs, fn_name.into(), rhs)), pos))
|
||||||
}
|
}
|
||||||
// var[???] (indexed) = rhs, var.??? (indexed) = rhs
|
// var[???] (indexed) = rhs, var.??? (indexed) = rhs
|
||||||
|
@ -127,7 +127,7 @@ impl EvalAltResult {
|
|||||||
Self::ErrorVariableNotFound(_, _) => "Variable not found",
|
Self::ErrorVariableNotFound(_, _) => "Variable not found",
|
||||||
Self::ErrorModuleNotFound(_, _) => "Module not found",
|
Self::ErrorModuleNotFound(_, _) => "Module not found",
|
||||||
Self::ErrorDataRace(_, _) => "Data race detected when accessing variable",
|
Self::ErrorDataRace(_, _) => "Data race detected when accessing variable",
|
||||||
Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable",
|
Self::ErrorAssignmentToConstant(_, _) => "Cannot assign to a constant",
|
||||||
Self::ErrorMismatchOutputType(_, _, _) => "Output type is incorrect",
|
Self::ErrorMismatchOutputType(_, _, _) => "Output type is incorrect",
|
||||||
Self::ErrorInExpr(_) => "Malformed 'in' expression",
|
Self::ErrorInExpr(_) => "Malformed 'in' expression",
|
||||||
Self::ErrorDotExpr(_, _) => "Malformed dot expression",
|
Self::ErrorDotExpr(_, _) => "Malformed dot expression",
|
||||||
@ -194,7 +194,9 @@ impl fmt::Display for EvalAltResult {
|
|||||||
Self::ErrorRuntime(d, _) if d.is::<()>() => f.write_str(desc)?,
|
Self::ErrorRuntime(d, _) if d.is::<()>() => f.write_str(desc)?,
|
||||||
Self::ErrorRuntime(d, _) => write!(f, "{}: {}", desc, d)?,
|
Self::ErrorRuntime(d, _) => write!(f, "{}: {}", desc, d)?,
|
||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, _) => write!(f, "{}: '{}'", desc, s)?,
|
Self::ErrorAssignmentToConstant(s, _) => {
|
||||||
|
write!(f, "Cannot assign to constant '{}'", s)?
|
||||||
|
}
|
||||||
Self::ErrorMismatchOutputType(r, s, _) => {
|
Self::ErrorMismatchOutputType(r, s, _) => {
|
||||||
write!(f, "Output type is incorrect: {} (expecting {})", r, s)?
|
write!(f, "Output type is incorrect: {} (expecting {})", r, s)?
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use rhai::{Engine, EvalAltResult, ParseErrorType, INT};
|
use rhai::{Engine, EvalAltResult, ParseErrorType, Scope, INT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_constant() -> Result<(), Box<EvalAltResult>> {
|
fn test_constant() -> Result<(), Box<EvalAltResult>> {
|
||||||
@ -15,13 +15,28 @@ fn test_constant() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>("const x = [1, 2, 3, 4, 5]; x[2] = 42;").expect_err("expects error"),
|
*engine.consume("const x = [1, 2, 3, 4, 5]; x[2] = 42;").expect_err("expects error"),
|
||||||
EvalAltResult::ErrorParsing(ParseErrorType::AssignmentToConstant(x), _) if x == "x"
|
EvalAltResult::ErrorParsing(ParseErrorType::AssignmentToConstant(x), _) if x == "x"
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_constant_scope() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
scope.push_constant("x", 42 as INT);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
*engine.consume_with_scope(&mut scope, "x = 1").expect_err("expects error"),
|
||||||
|
EvalAltResult::ErrorAssignmentToConstant(x, _) if x == "x"
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_var_is_def() -> Result<(), Box<EvalAltResult>> {
|
fn test_var_is_def() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user