From ae3df3e2f2eab1724de2cef0199e215d998c1ee5 Mon Sep 17 00:00:00 2001 From: Mai-Lapyst Date: Wed, 18 Oct 2023 02:16:26 +0200 Subject: [PATCH 1/2] Add support for declarations in switch expressions closes #504 --- src/dparse/ast.d | 11 ++++-- src/dparse/formatter.d | 4 +-- src/dparse/parser.d | 14 +++----- test/ast_checks/switch_condition.d | 35 +++++++++++++++++++ test/ast_checks/switch_condition.txt | 28 +++++++++++++++ test/pass_files/switch_condition_assignment.d | 14 ++++++++ 6 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 test/ast_checks/switch_condition.d create mode 100644 test/ast_checks/switch_condition.txt create mode 100644 test/pass_files/switch_condition_assignment.d diff --git a/src/dparse/ast.d b/src/dparse/ast.d index cb1b0ec9..988c2292 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -3147,11 +3147,18 @@ final class SwitchStatement : BaseNode { override void accept(ASTVisitor visitor) const { - mixin (visitIfNotNull!(expression, statement)); + mixin (visitIfNotNull!(condition, statement)); } - /** */ Expression expression; + /** */ IfCondition condition; /** */ Statement statement; mixin OpEquals; + + deprecated("use condition.expression") inout(Expression) expression() inout @property + { + if (!condition) + return null; + return condition.expression; + } } /// diff --git a/src/dparse/formatter.d b/src/dparse/formatter.d index 3d26eb0e..1474f682 100644 --- a/src/dparse/formatter.d +++ b/src/dparse/formatter.d @@ -2958,7 +2958,7 @@ class Formatter(Sink) debug(verbose) writeln("SwitchStatement"); /** - Expression expression; + IfCondition condition; Statement statement; **/ @@ -2966,7 +2966,7 @@ class Formatter(Sink) { newThing(What.other); isFinal ? put(" final switch(") : put("switch("); - format(expression); + format(condition); put(")"); bool needBlock = statement.statementNoCaseNoDefault && diff --git a/src/dparse/parser.d b/src/dparse/parser.d index dc2daa62..572dd6d8 100644 --- a/src/dparse/parser.d +++ b/src/dparse/parser.d @@ -6755,17 +6755,13 @@ class Parser // DCD #453 // with just `switch(stuff` returns a non null node, // which allows DCD to gives completion on `stuff`. - if (auto e = parseExpression()) + mixin(parseNodeQ!(`node.condition`, `IfCondition`)); + if (currentIs(tok!")")) { - node.expression = e; - if (currentIs(tok!")")) - { - advance(); - // returns null only from here. - mixin(parseNodeQ!(`node.statement`, `Statement`)); - } + advance(); + // returns null only from here. + mixin(parseNodeQ!(`node.statement`, `Statement`)); } - else error("Expression expected after `switch(`", false); node.tokens = tokens[startIndex .. index]; return node; } diff --git a/test/ast_checks/switch_condition.d b/test/ast_checks/switch_condition.d new file mode 100644 index 00000000..afe8f52c --- /dev/null +++ b/test/ast_checks/switch_condition.d @@ -0,0 +1,35 @@ +void a() +{ + switch (auto line = readln) + { + default: + line.strip; + } +} + +void b() +{ + switch (scope line = readln) + { + default: + line.strip; + } +} + +void c() +{ + switch (const line = readln) + { + default: + line.strip; + } +} + +void d() +{ + switch (const inout string line = readln) + { + default: + line.strip; + } +} \ No newline at end of file diff --git a/test/ast_checks/switch_condition.txt b/test/ast_checks/switch_condition.txt new file mode 100644 index 00000000..36e650a2 --- /dev/null +++ b/test/ast_checks/switch_condition.txt @@ -0,0 +1,28 @@ +//functionDeclaration[name = 'a']//functionBody//switchStatement/condition/auto +not(//functionDeclaration[name = 'a']//functionBody//switchStatement/condition/scope) +//functionDeclaration[name = 'a']//functionBody//switchStatement/condition/identifier[text()='line'] +//functionDeclaration[name = 'a']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'a']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line'] +//functionDeclaration[name = 'a']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip'] +not(//functionDeclaration[name = 'b']//functionBody//switchStatement/condition/auto) +//functionDeclaration[name = 'b']//functionBody//switchStatement/condition/scope +//functionDeclaration[name = 'b']//functionBody//switchStatement/condition/identifier[text()='line'] +//functionDeclaration[name = 'b']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'b']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line'] +//functionDeclaration[name = 'b']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip'] +not(//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/auto) +not(//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/scope) +//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/typeConstructor[text()='const'] +//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/identifier[text()='line'] +//functionDeclaration[name = 'c']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'c']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line'] +//functionDeclaration[name = 'c']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip'] +not(//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/auto) +not(//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/scope) +//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/typeConstructor[text()='const'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/typeConstructor[text()='inout'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/type[@pretty='string'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/identifier[text()='line'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/condition/unaryExpression//identifier[text()='readln'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='line'] +//functionDeclaration[name = 'd']//functionBody//switchStatement/statement//defaultStatement//identifier[text()='strip'] diff --git a/test/pass_files/switch_condition_assignment.d b/test/pass_files/switch_condition_assignment.d new file mode 100644 index 00000000..938be33b --- /dev/null +++ b/test/pass_files/switch_condition_assignment.d @@ -0,0 +1,14 @@ +import std : writeln, format; + +int get() +{ + return 1; +} + +void main() +{ + switch (auto x = get()) { + default: + writeln("inside switch: ", x); + } +} From 82ca5eff9b598d96044a59868f0a90abc82faaae Mon Sep 17 00:00:00 2001 From: Mai-Lapyst <67418776+Mai-Lapyst@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:18:35 +0200 Subject: [PATCH 2/2] Update src/dparse/ast.d Adding additional attributes to deprecation-wrapper of SwitchStatement.expression to avoid breakage Co-authored-by: Jan Jurzitza --- src/dparse/ast.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dparse/ast.d b/src/dparse/ast.d index 988c2292..eba8d1a3 100644 --- a/src/dparse/ast.d +++ b/src/dparse/ast.d @@ -3153,7 +3153,7 @@ final class SwitchStatement : BaseNode /** */ Statement statement; mixin OpEquals; - deprecated("use condition.expression") inout(Expression) expression() inout @property + deprecated("use condition.expression") inout(Expression) expression() inout @property @safe nothrow @nogc pure { if (!condition) return null;