Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.

Commit 6f282f7

Browse files
committed
Ensure there is only a single default-case in switch expression
Added basic test of this.
1 parent c57ee2e commit 6f282f7

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

parser/parser.go

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,20 +397,17 @@ func (p *Parser) parseSwitchStatement() ast.Expression {
397397

398398
// switch
399399
expression := &ast.SwitchExpression{Token: p.curToken}
400-
if expression == nil {
401-
return nil
402-
}
400+
401+
// look for (xx)
403402
if !p.expectPeek(token.LPAREN) {
404403
return nil
405404
}
406405
p.nextToken()
407406
expression.Value = p.parseExpression(LOWEST)
408407
if expression.Value == nil {
409-
fmt.Printf("error\n")
410408
return nil
411409
}
412410
if !p.expectPeek(token.RPAREN) {
413-
fmt.Printf("error\n")
414411
return nil
415412
}
416413

@@ -424,6 +421,10 @@ func (p *Parser) parseSwitchStatement() ast.Expression {
424421
// various case-statements
425422
for !p.curTokenIs(token.RBRACE) {
426423

424+
if p.curTokenIs(token.EOF) {
425+
p.errors = append(p.errors, "unterminated switch statement")
426+
return nil
427+
}
427428
tmp := &ast.CaseExpression{Token: p.curToken}
428429

429430
// Default will be handled specially
@@ -437,8 +438,15 @@ func (p *Parser) parseSwitchStatement() ast.Expression {
437438
// skip "case"
438439
p.nextToken()
439440

440-
// parse the match-expression.
441-
tmp.Expr = p.parseExpression(LOWEST)
441+
// Here we allow "case default" even though
442+
// most people would prefer to write "default".
443+
if p.curTokenIs(token.DEFAULT) {
444+
tmp.Default = true
445+
} else {
446+
447+
// parse the match-expression.
448+
tmp.Expr = p.parseExpression(LOWEST)
449+
}
442450
}
443451

444452
if !p.expectPeek(token.LBRACE) {
@@ -471,6 +479,19 @@ func (p *Parser) parseSwitchStatement() ast.Expression {
471479
return nil
472480
}
473481

482+
// More than one default is a bug
483+
count := 0
484+
for _, c := range expression.Choices {
485+
if c.Default {
486+
count++
487+
}
488+
}
489+
if count > 1 {
490+
msg := fmt.Sprintf("A switch-statement should only have one default block")
491+
p.errors = append(p.errors, msg)
492+
return nil
493+
494+
}
474495
return expression
475496

476497
}

parser/parser_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,7 @@ func TestIncompleThings(t *testing.T) {
881881
`const x =`,
882882
`function foo( a, b ="steve", `,
883883
`function foo() {`,
884+
`switch (foo) { `,
884885
}
885886

886887
for _, str := range input {
@@ -897,3 +898,33 @@ func TestIncompleThings(t *testing.T) {
897898
}
898899
}
899900
}
901+
902+
func TestMultiDefault(t *testing.T) {
903+
input := `
904+
switch( val ) {
905+
case 1 {
906+
printf("yksi");
907+
}
908+
case 2 {
909+
printf("kaksi");
910+
}
911+
case default {
912+
printf("OK\n");
913+
}
914+
default {
915+
printf("Two default blocks? Oh noes\n" );
916+
}
917+
}`
918+
919+
l := lexer.New(input)
920+
p := New(l)
921+
_ = p.ParseProgram()
922+
923+
if len(p.errors) < 1 {
924+
t.Errorf("unexpected error-count, got %d expected %d", len(p.errors), 1)
925+
}
926+
927+
if !strings.Contains(p.errors[0], "only have one default block") {
928+
t.Errorf("Unexpected error-message %s\n", p.errors[0])
929+
}
930+
}

0 commit comments

Comments
 (0)