Allow if-expressions and switch-expressions in Engine::eval_expression.
This commit is contained in:
parent
204284f4f7
commit
d80184ba14
@ -23,6 +23,11 @@ New features
|
|||||||
|
|
||||||
* For very special needs, the ability to register fallible type iterators is added.
|
* For very special needs, the ability to register fallible type iterators is added.
|
||||||
|
|
||||||
|
### Expressions
|
||||||
|
|
||||||
|
* `if`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that both statement blocks each contain at most a single expression.
|
||||||
|
* `switch`-expressions are allowed in `Engine::eval_expression` and `Engine::compile_expression` provided that match actions are expressions only.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -291,6 +291,8 @@ struct ParseSettings {
|
|||||||
in_closure: bool,
|
in_closure: bool,
|
||||||
/// Is the construct being parsed located inside a breakable loop?
|
/// Is the construct being parsed located inside a breakable loop?
|
||||||
is_breakable: bool,
|
is_breakable: bool,
|
||||||
|
/// Allow statements in blocks?
|
||||||
|
allow_statements: bool,
|
||||||
/// Language options in effect (overrides Engine options).
|
/// Language options in effect (overrides Engine options).
|
||||||
options: LangOptions,
|
options: LangOptions,
|
||||||
/// Current expression nesting level.
|
/// Current expression nesting level.
|
||||||
@ -1193,12 +1195,21 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (action_expr, need_comma) = if settings.allow_statements {
|
||||||
let stmt = self.parse_stmt(input, state, lib, settings.level_up())?;
|
let stmt = self.parse_stmt(input, state, lib, settings.level_up())?;
|
||||||
let need_comma = !stmt.is_self_terminated();
|
let need_comma = !stmt.is_self_terminated();
|
||||||
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
|
|
||||||
|
|
||||||
let stmt_block: StmtBlock = stmt.into();
|
let stmt_block: StmtBlock = stmt.into();
|
||||||
expressions.push((condition, Expr::Stmt(stmt_block.into())).into());
|
(Expr::Stmt(stmt_block.into()), need_comma)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
self.parse_expr(input, state, lib, settings.level_up())?,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
|
||||||
|
|
||||||
|
expressions.push((condition, action_expr).into());
|
||||||
let index = expressions.len() - 1;
|
let index = expressions.len() - 1;
|
||||||
|
|
||||||
if case_expr_list.is_empty() {
|
if case_expr_list.is_empty() {
|
||||||
@ -3076,6 +3087,22 @@ impl Engine {
|
|||||||
|
|
||||||
let mut statements = StaticVec::new_const();
|
let mut statements = StaticVec::new_const();
|
||||||
|
|
||||||
|
if !settings.allow_statements {
|
||||||
|
let stmt = self.parse_expr_stmt(input, state, lib, settings.level_up())?;
|
||||||
|
statements.push(stmt);
|
||||||
|
|
||||||
|
// Must end with }
|
||||||
|
return match input.next().expect(NEVER_ENDS) {
|
||||||
|
(Token::RightBrace, pos) => Ok((statements, settings.pos, pos).into()),
|
||||||
|
(Token::LexError(err), pos) => Err(err.into_err(pos)),
|
||||||
|
(.., pos) => Err(PERR::MissingToken(
|
||||||
|
Token::LeftBrace.into(),
|
||||||
|
"to start a statement block".into(),
|
||||||
|
)
|
||||||
|
.into_err(pos)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let prev_entry_stack_len = state.block_stack_len;
|
let prev_entry_stack_len = state.block_stack_len;
|
||||||
state.block_stack_len = state.stack.len();
|
state.block_stack_len = state.stack.len();
|
||||||
|
|
||||||
@ -3290,6 +3317,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
in_closure: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
|
allow_statements: true,
|
||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
pos,
|
pos,
|
||||||
@ -3761,7 +3789,7 @@ impl Engine {
|
|||||||
let mut functions = BTreeMap::new();
|
let mut functions = BTreeMap::new();
|
||||||
|
|
||||||
let mut options = self.options;
|
let mut options = self.options;
|
||||||
options.remove(LangOptions::IF_EXPR | LangOptions::SWITCH_EXPR | LangOptions::STMT_EXPR);
|
options.remove(LangOptions::STMT_EXPR);
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
options.remove(LangOptions::ANON_FN);
|
options.remove(LangOptions::ANON_FN);
|
||||||
|
|
||||||
@ -3773,6 +3801,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
in_closure: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
|
allow_statements: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
pos: Position::NONE,
|
pos: Position::NONE,
|
||||||
@ -3828,6 +3857,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
in_closure: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
|
allow_statements: true,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
level: 0,
|
level: 0,
|
||||||
pos: Position::NONE,
|
pos: Position::NONE,
|
||||||
|
@ -12,8 +12,47 @@ fn test_expressions() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine.eval_expression_with_scope::<INT>(&mut scope, "2 + (x + 10) * 2")?,
|
engine.eval_expression_with_scope::<INT>(&mut scope, "2 + (x + 10) * 2")?,
|
||||||
42
|
42
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(&mut scope, "if x > 0 { 42 } else { 123 }")?,
|
||||||
|
42
|
||||||
|
);
|
||||||
assert!(engine
|
assert!(engine
|
||||||
.eval_expression_with_scope::<INT>(&mut scope, "if x > 0 { 42 } else { 123 }")
|
.eval_expression_with_scope::<INT>(&mut scope, "if x > 0 { let y = 42; y } else { 123 }")
|
||||||
|
.is_err());
|
||||||
|
assert!(engine
|
||||||
|
.eval_expression_with_scope::<INT>(&mut scope, "if x > 0 { 42 } else { let y = 123; y }")
|
||||||
|
.is_err());
|
||||||
|
assert!(engine
|
||||||
|
.eval_expression_with_scope::<INT>(&mut scope, "if x > 0 { 42 } else {}")
|
||||||
|
.is_err());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval_expression_with_scope::<INT>(
|
||||||
|
&mut scope,
|
||||||
|
"
|
||||||
|
switch x {
|
||||||
|
0 => 1,
|
||||||
|
1..10 => 123,
|
||||||
|
10 => 42,
|
||||||
|
}
|
||||||
|
"
|
||||||
|
)?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
assert!(engine
|
||||||
|
.eval_expression_with_scope::<INT>(
|
||||||
|
&mut scope,
|
||||||
|
"
|
||||||
|
switch x {
|
||||||
|
0 => 1,
|
||||||
|
1..10 => {
|
||||||
|
let y = 123;
|
||||||
|
y
|
||||||
|
}
|
||||||
|
10 => 42,
|
||||||
|
}
|
||||||
|
"
|
||||||
|
)
|
||||||
.is_err());
|
.is_err());
|
||||||
|
|
||||||
assert!(engine.eval_expression::<()>("40 + 2;").is_err());
|
assert!(engine.eval_expression::<()>("40 + 2;").is_err());
|
||||||
|
Loading…
Reference in New Issue
Block a user