Skip to content

Commit eca1c5e

Browse files
authored
Merge pull request #2069 from xushiwei/q
parser parseBranchStmt: allow goto as command name
2 parents 595128a + 4bc8046 commit eca1c5e

File tree

5 files changed

+145
-18
lines changed

5 files changed

+145
-18
lines changed

parser/_testdata/goto1/goto.gop

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
goto "a"
2+
goto 1, 2
3+
goto (1+2)*3

parser/_testdata/goto1/parser.expect

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package main
2+
3+
file goto.gop
4+
noEntrypoint
5+
ast.FuncDecl:
6+
Name:
7+
ast.Ident:
8+
Name: main
9+
Type:
10+
ast.FuncType:
11+
Params:
12+
ast.FieldList:
13+
Body:
14+
ast.BlockStmt:
15+
List:
16+
ast.ExprStmt:
17+
X:
18+
ast.CallExpr:
19+
Fun:
20+
ast.Ident:
21+
Name: goto
22+
Args:
23+
ast.BasicLit:
24+
Kind: STRING
25+
Value: "a"
26+
ast.ExprStmt:
27+
X:
28+
ast.CallExpr:
29+
Fun:
30+
ast.Ident:
31+
Name: goto
32+
Args:
33+
ast.BasicLit:
34+
Kind: INT
35+
Value: 1
36+
ast.BasicLit:
37+
Kind: INT
38+
Value: 2
39+
ast.ExprStmt:
40+
X:
41+
ast.CallExpr:
42+
Fun:
43+
ast.Ident:
44+
Name: goto
45+
Args:
46+
ast.BinaryExpr:
47+
X:
48+
ast.ParenExpr:
49+
X:
50+
ast.BinaryExpr:
51+
X:
52+
ast.BasicLit:
53+
Kind: INT
54+
Value: 1
55+
Op: +
56+
Y:
57+
ast.BasicLit:
58+
Kind: INT
59+
Value: 2
60+
Op: *
61+
Y:
62+
ast.BasicLit:
63+
Kind: INT
64+
Value: 3

parser/_testdata/goto2/goto.gop

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
goto x+y
2+
goto x, y

parser/_testdata/goto2/parser.expect

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package main
2+
3+
file goto.gop
4+
noEntrypoint
5+
ast.FuncDecl:
6+
Name:
7+
ast.Ident:
8+
Name: main
9+
Type:
10+
ast.FuncType:
11+
Params:
12+
ast.FieldList:
13+
Body:
14+
ast.BlockStmt:
15+
List:
16+
ast.ExprStmt:
17+
X:
18+
ast.CallExpr:
19+
Fun:
20+
ast.Ident:
21+
Name: goto
22+
Args:
23+
ast.BinaryExpr:
24+
X:
25+
ast.Ident:
26+
Name: x
27+
Op: +
28+
Y:
29+
ast.Ident:
30+
Name: y
31+
ast.ExprStmt:
32+
X:
33+
ast.CallExpr:
34+
Fun:
35+
ast.Ident:
36+
Name: goto
37+
Args:
38+
ast.Ident:
39+
Name: x
40+
ast.Ident:
41+
Name: y

parser/parser.go

+35-18
Original file line numberDiff line numberDiff line change
@@ -2257,12 +2257,14 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
22572257
}
22582258

22592259
// If lhs is set and the result is an identifier, it is not resolved.
2260-
func (p *parser) parsePrimaryExpr(lhs, allowTuple, allowCmd bool) (x ast.Expr, isTuple bool) {
2260+
func (p *parser) parsePrimaryExpr(iden *ast.Ident, lhs, allowTuple, allowCmd bool) (x ast.Expr, isTuple bool) {
22612261
if p.trace {
22622262
defer un(trace(p, "PrimaryExpr"))
22632263
}
22642264

2265-
if x, isTuple = p.parseOperand(lhs, allowTuple, allowCmd); isTuple {
2265+
if iden != nil {
2266+
x = iden
2267+
} else if x, isTuple = p.parseOperand(lhs, allowTuple, allowCmd); isTuple {
22662268
return
22672269
}
22682270
L:
@@ -2384,7 +2386,7 @@ func (p *parser) checkCmd() bool {
23842386

23852387
// parseErrWrapExpr: expr! expr? expr?:defval
23862388
func (p *parser) parseErrWrapExpr(lhs, allowTuple, allowCmd bool) (x ast.Expr, isTuple bool) {
2387-
if x, isTuple = p.parsePrimaryExpr(lhs, allowTuple, allowCmd); isTuple {
2389+
if x, isTuple = p.parsePrimaryExpr(nil, lhs, allowTuple, allowCmd); isTuple {
23882390
return
23892391
}
23902392
if expr, ok := x.(*ast.ErrWrapExpr); ok {
@@ -2674,8 +2676,14 @@ const (
26742676
// of a range clause (with mode == rangeOk). The returned statement is an
26752677
// assignment with a right-hand side that is a single unary expression of
26762678
// the form "range x". No guarantees are given for the left-hand side.
2677-
func (p *parser) parseSimpleStmt(mode int, allowCmd bool) (ast.Stmt, bool) {
2678-
return p.parseSimpleStmtEx(mode, allowCmd, false)
2679+
func (p *parser) parseSimpleStmt(mode int, allowCmd bool) ast.Stmt {
2680+
ss, _ /* isRange */ := p.parseSimpleStmtEx(mode, allowCmd, false)
2681+
return ss
2682+
}
2683+
2684+
func (p *parser) parseBranchCmdStmt(iden *ast.Ident) ast.Stmt { // Go+: goto as command
2685+
x, _ := p.parsePrimaryExpr(iden, false, false, true)
2686+
return &ast.ExprStmt{X: x}
26792687
}
26802688

26812689
func (p *parser) parseSimpleStmtEx(mode int, allowCmd, allowRangeExpr bool) (ast.Stmt, bool) {
@@ -2833,20 +2841,29 @@ func (p *parser) parseBranchStmt(tok token.Token) ast.Stmt {
28332841

28342842
oldpos, oldlit := p.pos, p.lit // Go+: save token to allow goto() as a function
28352843
pos := p.expect(tok)
2836-
if p.tok == token.LPAREN { // Go+: allow goto() as a function
2844+
next := p.tok
2845+
if next != token.IDENT && next != token.SEMICOLON { // Go+: allow goto() as a function
28372846
p.unget(oldpos, token.IDENT, oldlit)
2838-
s, _ := p.parseSimpleStmt(basic, false)
2847+
s := p.parseSimpleStmt(basic, true)
28392848
p.expectSemi()
28402849
return s
28412850
}
28422851

28432852
var label *ast.Ident
2844-
if tok != token.FALLTHROUGH && p.tok == token.IDENT {
2853+
if tok != token.FALLTHROUGH && next == token.IDENT {
28452854
label = p.parseIdent()
28462855
// add to list of unresolved targets
28472856
n := len(p.targetStack) - 1
28482857
p.targetStack[n] = append(p.targetStack[n], label)
28492858
}
2859+
if p.tok != token.SEMICOLON { // Go+: goto command
2860+
if label != nil {
2861+
p.unget(label.NamePos, token.IDENT, label.Name)
2862+
}
2863+
s := p.parseBranchCmdStmt(&ast.Ident{NamePos: oldpos, Name: oldlit})
2864+
p.expectSemi()
2865+
return s
2866+
}
28502867
p.expectSemi()
28512868

28522869
return &ast.BranchStmt{TokPos: pos, Tok: tok, Label: label}
@@ -2887,7 +2904,7 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
28872904
p.next()
28882905
p.error(p.pos, "var declaration not allowed in 'IF' initializer")
28892906
}
2890-
init, _ = p.parseSimpleStmt(basic, false)
2907+
init = p.parseSimpleStmt(basic, false)
28912908
}
28922909

28932910
var condStmt ast.Stmt
@@ -2904,7 +2921,7 @@ func (p *parser) parseIfHeader() (init ast.Stmt, cond ast.Expr) {
29042921
p.expect(token.SEMICOLON)
29052922
}
29062923
if p.tok != token.LBRACE {
2907-
condStmt, _ = p.parseSimpleStmt(basic, false)
2924+
condStmt = p.parseSimpleStmt(basic, false)
29082925
}
29092926
} else {
29102927
condStmt = init
@@ -2951,7 +2968,7 @@ func (p *parser) parseForPhraseCond() (init ast.Stmt, cond ast.Expr) {
29512968
p.next()
29522969
p.error(p.pos, "var declaration not allowed in 'IF' initializer")
29532970
}
2954-
init, _ = p.parseSimpleStmt(basic, false)
2971+
init = p.parseSimpleStmt(basic, false)
29552972
}
29562973

29572974
var condStmt ast.Stmt
@@ -2968,7 +2985,7 @@ func (p *parser) parseForPhraseCond() (init ast.Stmt, cond ast.Expr) {
29682985
p.expect(token.SEMICOLON)
29692986
}
29702987
if !isForPhraseCondEnd(p.tok) {
2971-
condStmt, _ = p.parseSimpleStmt(basic, false)
2988+
condStmt = p.parseSimpleStmt(basic, false)
29722989
}
29732990
} else {
29742991
condStmt = init
@@ -3102,7 +3119,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
31023119
prevLev := p.exprLev
31033120
p.exprLev = -1
31043121
if p.tok != token.SEMICOLON {
3105-
s2, _ = p.parseSimpleStmt(basic, false)
3122+
s2 = p.parseSimpleStmt(basic, false)
31063123
}
31073124
if p.tok == token.SEMICOLON {
31083125
p.next()
@@ -3123,7 +3140,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
31233140
// Having the extra nested but empty scope won't affect it.
31243141
p.openScope()
31253142
defer p.closeScope()
3126-
s2, _ = p.parseSimpleStmt(basic, false)
3143+
s2 = p.parseSimpleStmt(basic, false)
31273144
}
31283145
}
31293146
p.exprLev = prevLev
@@ -3329,11 +3346,11 @@ func (p *parser) parseForStmt() ast.Stmt {
33293346
s1 = s2
33303347
s2 = nil
33313348
if p.tok != token.SEMICOLON {
3332-
s2, _ = p.parseSimpleStmt(basic, false)
3349+
s2 = p.parseSimpleStmt(basic, false)
33333350
}
33343351
p.expectSemi()
33353352
if p.tok != token.LBRACE {
3336-
s3, _ = p.parseSimpleStmt(basic, false)
3353+
s3 = p.parseSimpleStmt(basic, false)
33373354
}
33383355
}
33393356
p.exprLev = prevLev
@@ -3412,7 +3429,7 @@ func (p *parser) parseStmt(allowCmd bool) (s ast.Stmt) {
34123429
allowCmd = false
34133430
fallthrough
34143431
case token.IDENT, token.MAP: // operands
3415-
s, _ = p.parseSimpleStmt(labelOk, allowCmd)
3432+
s = p.parseSimpleStmt(labelOk, allowCmd)
34163433
// because of the required look-ahead, labeled statements are
34173434
// parsed by parseSimpleStmt - don't expect a semicolon after
34183435
// them
@@ -3684,7 +3701,7 @@ func (p *parser) parseOverloadFunc() (ast.Expr, bool) {
36843701
case token.FUNC:
36853702
return p.parseFuncTypeOrLit(), true
36863703
case token.LPAREN:
3687-
x, _ := p.parsePrimaryExpr(false, false, false)
3704+
x, _ := p.parsePrimaryExpr(nil, false, false, false)
36883705
return x, true
36893706
}
36903707
return nil, false

0 commit comments

Comments
 (0)