I found an extremely easy way how drastically reduce complexity (get rid of if-let
and while-let
) and refactor let-chains
such that everything(let-chains
, if
, if-let
, while
, while-let
) work nicely!
We add LetExpression
LetExpr :
let Pattern = Scrutinee
but, it is permitted to use in boolean expressions only:
BoolExpression :
Expression | LetExpr
and finally we point, where boolean expression are acceptable
PredicateLoopExpression :
while BoolExpression /*except struct expression*/ BlockExpression
IfExpression :
if BoolExpression /*except struct expression*/ BlockExpression
(else ( BlockExpression | IfExpression ) )?
LazyBooleanExpression :
Expression || Expression
| BoolExpression && BoolExpression
delete if-let
and while-let
definitions and it is ... done!
Ok, almost. We need some rules for binded variables(BVs). BVs could be used
-
- in next right
Expressions
from "LetExp"
- in next right
-
- till not-inside-grouped "'||'" if it exists
-
- or till end of this group "
)
" if it is grouped
- or till end of this group "
-
- or till used as not a part of
&&
/||
Expressions
- or till used as not a part of
-
- or till end of
Expression
- or till end of
For Controllable expressions (for if
and while
) and "LetExp" is a part of "conditional" Expression
-
- or till end of "conditional"
Expression
only if left to "LetExp" is not-inside-grouped "'||'"
- or till end of "conditional"
-
- or till end of "cross-conditional" Expression (
IfTrueExpr
)
- or till end of "cross-conditional" Expression (
That's means:
let a = c.is_some() && let Some(c) = bar() ;
// ^^^~~ Error(1) 'c' is out of scope!!
let a = let Some(c) = foo() && true || c.is_none();
// Error(2) 'c' is out of scope!! ~~^^^
let a = (let Some(c) = bar() && true) && c.is_none();
// Error(3) 'c' is out of scope!! ~~^^^
let a = baz(let Some(c) = bar() && true) && c.is_none();
// Error(4) 'c' is out of scope!! ~~^^^
if foo() || let Some(c) = bar() && c.is_some() {
let _ = c;
// ~~^^^ Error(6) 'c' is out of scope!!
}
if (foo() || baz()) && let Some(c) = bar() && c.is_some() {
let _ = c;
// OK
}
if let Some(c) = baz() && (c.foo || c.bar) {
let _ = c;
// OK
}
We have 4 advantages:
(1) We automatically forbid to use LetExpr
as part of "simple" not explicitly boolean expressions.
(2) Both if-let
and while-let
become just a specific case of if
and while
and and we could cut extra-code.
(3) Let-chains
become cost-less control flow operations for if
and while
.
(3+) We have simple rules, where binded variables could be used.
(4) We could also get rid of match!(expr, pat)
macro. Use instead next expressions:
let match_macro = true && let pat = expr;