diff --git a/changelog/dmd.with-colon.dd b/changelog/dmd.with-colon.dd new file mode 100644 index 000000000000..7a5574f1cf5d --- /dev/null +++ b/changelog/dmd.with-colon.dd @@ -0,0 +1,24 @@ +Adds the with-colon statement. + +Like at the global declarations level, a `with (expression) :` can be used to create +a scope until a `}` is encountered. + +--- +{ + with (E): + statement; + statement; +} +--- + +which is equivalent to: + +--- +{ + with (E) + { + statement; + statement; + } +} +--- diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 415d57824d14..09d5be5c2124 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -5777,7 +5777,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer /***************************************** * Input: - * flags PSxxxx + * flags = ParseStatementFlags * Output: * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement */ @@ -6585,20 +6585,48 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer s = new AST.SynchronizedStatement(loc, exp, _body); break; } - case TOK.with_: + case TOK.with_: // https://dlang.org/spec/statement.html#with-statement { - AST.Expression exp; - AST.Statement _body; - Loc endloc = loc; + Loc withLoc = loc; nextToken(); check(TOK.leftParenthesis); - exp = parseExpression(); + AST.Expression exp = parseExpression(); closeCondition("with", null, exp); - _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); - s = new AST.WithStatement(loc, exp, _body, endloc); + + if (token.value == TOK.colon) // with (Expression) : StatementList + { + nextToken(); + + const lookingForElseSave = lookingForElse; + lookingForElse = Loc.initial; + + auto statements = new AST.Statements(); + while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) + { + statements.push(parseStatement(ParseStatementFlags.curlyScope | ParseStatementFlags.semiOk)); + } + + lookingForElse = lookingForElseSave; + + s = new AST.CompoundStatement(loc, statements); + s = new AST.ScopeStatement(loc, s, token.loc); + s = new AST.WithStatement(loc, exp, s, withLoc); + + if (token.value == TOK.endOfFile) + { + error(token.loc, "matching `}` expected following compound with statement, not `%s`", + token.toChars()); + eSink.errorSupplemental(withLoc, "unmatched `with (exp):`"); + s = new AST.ErrorStatement(); + } + break; + } + AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &withLoc); + s = new AST.WithStatement(loc, exp, _body, withLoc); break; } + case TOK.try_: { AST.Statement _body; diff --git a/compiler/test/compilable/scope.d b/compiler/test/compilable/scope.d index 06549941d255..6017e0a12e61 100644 --- a/compiler/test/compilable/scope.d +++ b/compiler/test/compilable/scope.d @@ -375,3 +375,23 @@ struct Result auto r = Result(&s); r.save(); } + +/********************************************/ + +void withOmatic() +{ + enum E { A, B } + E e; + + { + with (E): + int i; + if (A) + return; + } + { + with (e) + if (A) + return; + } +} diff --git a/compiler/test/fail_compilation/withspoon.d b/compiler/test/fail_compilation/withspoon.d new file mode 100644 index 000000000000..2b9d84fde9b9 --- /dev/null +++ b/compiler/test/fail_compilation/withspoon.d @@ -0,0 +1,16 @@ +/* TEST_OUTPUT: +--- +fail_compilation/withspoon.d(17): Error: matching `}` expected following compound with statement, not `End of File` +fail_compilation/withspoon.d(15): unmatched `with (exp):` +fail_compilation/withspoon.d(17): Error: matching `}` expected following compound statement, not `End of File` +fail_compilation/withspoon.d(14): unmatched `{` +--- +*/ + + +enum E { A, B } + +void test2() +{ + with (E): + return;