Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for shortened switch #20658

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
30 changes: 30 additions & 0 deletions changelog/dmd.shortened-switch.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Add a shortened form for switch's case expression using `=>` instead of `:` to make `break` optional, it'll automatically break at the end of the scope.

---
enum K = 42;
switch (K)
{
case 42 => printf("yes!\n");

default => printf("no!\n");
}
---

Is equivalent to:

---
enum K = 42;
switch (42)
{
case 42:
{
printf("yes!\n");
break;
}
default:
{
printf("no!\n");
break;
}
}
---
21 changes: 19 additions & 2 deletions compiler/src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -6419,7 +6419,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken(); //comma
}
while (token.value != TOK.colon && token.value != TOK.endOfFile);
check(TOK.colon);

bool insertBreak = false;
if (token.value == TOK.goesTo) {
insertBreak = true;
nextToken();
}
else
check(TOK.colon);

/* case exp: .. case last:
*/
Expand Down Expand Up @@ -6449,6 +6456,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (cur && cur.isBreakStatement())
break;
}
if (insertBreak)
statements.push(new AST.BreakStatement(loc, null));
s = new AST.CompoundStatement(loc, statements);
}
else
Expand All @@ -6475,7 +6484,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.default_:
{
nextToken();
check(TOK.colon);
bool insertBreak = false;
if (token.value == TOK.goesTo) {
insertBreak = true;
nextToken();
}
else
check(TOK.colon);

if (flags & ParseStatementFlags.curlyScope)
{
Expand All @@ -6484,6 +6499,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
statements.push(parseStatement(ParseStatementFlags.curlyScope));
}
if (insertBreak)
statements.push(new AST.BreakStatement(loc, null));
s = new AST.CompoundStatement(loc, statements);
}
else
Expand Down
124 changes: 124 additions & 0 deletions compiler/test/runnable/switch.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
RUN_OUTPUT:
---
A: yes
B: yes
C: yes
---
*/

// main.d -------------------------------------------------------

import core.stdc.stdio: printf;

void simple()
{
enum K = 42;
switch (K)
{
case 0 => printf("A: no0\n");
case 42 => printf("A: yes\n");
case 1 => printf("A: no1\n");

default => printf("A: default\n");
}
switch (K)
{
case 0 => {
printf("B: no0\n");
}
case 42 => {
printf("B: yes\n");
}
case 1 => {
printf("B: no1\n");
}

default => {
printf("B: default\n");
}
}
switch (K)
{
case 0: printf("C: no0\n"); break;
case 42: printf("C: yes\n"); break;
case 1: printf("C: no1\n"); break;

default: printf("C: default\n");
}
}


void send_1(short* to, short* from, int count)
{
auto n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to++ = *from++;
goto case;
case 7: *to++ = *from++;
goto case;
case 6: *to++ = *from++;
goto case;
case 5: *to++ = *from++;
goto case;
case 4: *to++ = *from++;
goto case;
case 3: *to++ = *from++;
goto case;
case 2: *to++ = *from++;
goto case;
case 1: *to++ = *from++;
continue;
} while (--n > 0);
break;
default: break;
}
}

void send_2(short* to, short* from, int count)
{
auto n = (count + 7) / 8;
switch (count % 8) {
case 0 => do { *to++ = *from++;
goto case;
case 7 => *to++ = *from++;
goto case;
case 6 => *to++ = *from++;
goto case;
case 5 => *to++ = *from++;
goto case;
case 4 => *to++ = *from++;
goto case;
case 3 => *to++ = *from++;
goto case;
case 2 => *to++ = *from++;
goto case;
case 1 => *to++ = *from++;
continue;
} while (--n > 0);
break;
default: break;
}
}

void duff_device()
{
{
short[4] data = [1,2,3,4];
short[4] output = 0;
send_1(output.ptr, data.ptr, cast(int) data.length);
assert(output[0] == 1 && output[1] == 2 && output[2] == 3 && output[3] == 4);
}
{
short[4] data = [1,2,3,4];
short[4] output = 0;
send_2(output.ptr, data.ptr, cast(int) data.length);
assert(output[0] == 1 && output[1] == 2 && output[2] == 3 && output[3] == 4);
}
}

void main()
{
simple();
duff_device();
}
Loading