mirror of
https://github.com/golang/go
synced 2024-11-21 13:44:45 -07:00
go/ast: reflect communication operator changes accurately in ast
- go/ast: introduce SendStmt; adjust SelectStmt - go/parser: accept new communication syntax, minor unrelated cleanups - go/printer: adjustments for new ast, fewer binary expression precedences - go/token: remove one binary precedence Adjusted dependent code. gofmt -w src -misc. Ran all tests. R=rsc, gri CC=golang-dev https://golang.org/cl/3989056
This commit is contained in:
parent
7fc4e37853
commit
288a39c86b
@ -23,7 +23,7 @@ func link(left chan<- int, right <-chan int) {
|
||||
for {
|
||||
v := <-right
|
||||
stdio.Stdout.WriteString(strconv.Itoa(v) + "\n")
|
||||
left <- 1+v
|
||||
left <- 1 + v
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,6 +305,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
|
||||
f.walk(n.Stmt, "stmt", visit)
|
||||
case *ast.ExprStmt:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
case *ast.SendStmt:
|
||||
f.walk(&n.Chan, "expr", visit)
|
||||
f.walk(&n.Value, "expr", visit)
|
||||
case *ast.IncDecStmt:
|
||||
f.walk(&n.X, "expr", visit)
|
||||
case *ast.AssignStmt:
|
||||
@ -343,8 +346,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
|
||||
f.walk(n.Assign, "stmt", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.CommClause:
|
||||
f.walk(n.Lhs, "expr", visit)
|
||||
f.walk(n.Rhs, "expr", visit)
|
||||
f.walk(n.Comm, "stmt", visit)
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
case *ast.SelectStmt:
|
||||
f.walk(n.Body, "stmt", visit)
|
||||
|
@ -535,6 +535,13 @@ type (
|
||||
X Expr // expression
|
||||
}
|
||||
|
||||
// A SendStmt node represents a send statement.
|
||||
SendStmt struct {
|
||||
Chan Expr
|
||||
Arrow token.Pos // position of "<-"
|
||||
Value Expr
|
||||
}
|
||||
|
||||
// An IncDecStmt node represents an increment or decrement statement.
|
||||
IncDecStmt struct {
|
||||
X Expr
|
||||
@ -629,11 +636,10 @@ type (
|
||||
|
||||
// A CommClause node represents a case of a select statement.
|
||||
CommClause struct {
|
||||
Case token.Pos // position of "case" or "default" keyword
|
||||
Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil)
|
||||
Lhs, Rhs Expr // Rhs == nil means default case
|
||||
Colon token.Pos // position of ":"
|
||||
Body []Stmt // statement list; or nil
|
||||
Case token.Pos // position of "case" or "default" keyword
|
||||
Comm Stmt // send or receive statement; nil means default case
|
||||
Colon token.Pos // position of ":"
|
||||
Body []Stmt // statement list; or nil
|
||||
}
|
||||
|
||||
// An SelectStmt node represents a select statement.
|
||||
@ -670,6 +676,7 @@ func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
|
||||
func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
|
||||
func (s *LabeledStmt) Pos() token.Pos { return s.Label.Pos() }
|
||||
func (s *ExprStmt) Pos() token.Pos { return s.X.Pos() }
|
||||
func (s *SendStmt) Pos() token.Pos { return s.Chan.Pos() }
|
||||
func (s *IncDecStmt) Pos() token.Pos { return s.X.Pos() }
|
||||
func (s *AssignStmt) Pos() token.Pos { return s.Lhs[0].Pos() }
|
||||
func (s *GoStmt) Pos() token.Pos { return s.Go }
|
||||
@ -695,6 +702,7 @@ func (s *EmptyStmt) End() token.Pos {
|
||||
}
|
||||
func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
|
||||
func (s *ExprStmt) End() token.Pos { return s.X.End() }
|
||||
func (s *SendStmt) End() token.Pos { return s.Value.End() }
|
||||
func (s *IncDecStmt) End() token.Pos {
|
||||
return s.TokPos + 2 /* len("++") */
|
||||
}
|
||||
@ -753,6 +761,7 @@ func (s *DeclStmt) stmtNode() {}
|
||||
func (s *EmptyStmt) stmtNode() {}
|
||||
func (s *LabeledStmt) stmtNode() {}
|
||||
func (s *ExprStmt) stmtNode() {}
|
||||
func (s *SendStmt) stmtNode() {}
|
||||
func (s *IncDecStmt) stmtNode() {}
|
||||
func (s *AssignStmt) stmtNode() {}
|
||||
func (s *GoStmt) stmtNode() {}
|
||||
|
@ -258,11 +258,8 @@ func Walk(v Visitor, node Node) {
|
||||
Walk(v, n.Body)
|
||||
|
||||
case *CommClause:
|
||||
if n.Lhs != nil {
|
||||
Walk(v, n.Lhs)
|
||||
}
|
||||
if n.Rhs != nil {
|
||||
Walk(v, n.Rhs)
|
||||
if n.Comm != nil {
|
||||
Walk(v, n.Comm)
|
||||
}
|
||||
walkStmtList(v, n.Body)
|
||||
|
||||
|
@ -1193,18 +1193,6 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
|
||||
x := p.parseExprList()
|
||||
|
||||
switch p.tok {
|
||||
case token.COLON:
|
||||
// labeled statement
|
||||
colon := p.pos
|
||||
p.next()
|
||||
if labelOk && len(x) == 1 {
|
||||
if label, isIdent := x[0].(*ast.Ident); isIdent {
|
||||
return &ast.LabeledStmt{label, colon, p.parseStmt()}
|
||||
}
|
||||
}
|
||||
p.error(x[0].Pos(), "illegal label declaration")
|
||||
return &ast.BadStmt{x[0].Pos(), colon + 1}
|
||||
|
||||
case
|
||||
token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
|
||||
token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
|
||||
@ -1218,11 +1206,29 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
|
||||
}
|
||||
|
||||
if len(x) > 1 {
|
||||
p.error(x[0].Pos(), "only one expression allowed")
|
||||
p.errorExpected(x[0].Pos(), "1 expression")
|
||||
// continue with first expression
|
||||
}
|
||||
|
||||
if p.tok == token.INC || p.tok == token.DEC {
|
||||
switch p.tok {
|
||||
case token.COLON:
|
||||
// labeled statement
|
||||
colon := p.pos
|
||||
p.next()
|
||||
if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent {
|
||||
return &ast.LabeledStmt{label, colon, p.parseStmt()}
|
||||
}
|
||||
p.error(x[0].Pos(), "illegal label declaration")
|
||||
return &ast.BadStmt{x[0].Pos(), colon + 1}
|
||||
|
||||
case token.ARROW:
|
||||
// send statement
|
||||
arrow := p.pos
|
||||
p.next() // consume "<-"
|
||||
y := p.parseExpr()
|
||||
return &ast.SendStmt{x[0], arrow, y}
|
||||
|
||||
case token.INC, token.DEC:
|
||||
// increment or decrement
|
||||
s := &ast.IncDecStmt{x[0], p.pos, p.tok}
|
||||
p.next() // consume "++" or "--"
|
||||
@ -1486,28 +1492,52 @@ func (p *parser) parseCommClause() *ast.CommClause {
|
||||
|
||||
// CommCase
|
||||
pos := p.pos
|
||||
var tok token.Token
|
||||
var lhs, rhs ast.Expr
|
||||
var comm ast.Stmt
|
||||
if p.tok == token.CASE {
|
||||
p.next()
|
||||
lhs := p.parseExprList()
|
||||
if p.tok == token.ARROW {
|
||||
// RecvExpr without assignment
|
||||
rhs = p.parseExpr()
|
||||
} else {
|
||||
// SendExpr or RecvExpr
|
||||
rhs = p.parseExpr()
|
||||
if p.tok == token.ASSIGN || p.tok == token.DEFINE {
|
||||
// RecvExpr with assignment
|
||||
tok = p.tok
|
||||
p.next()
|
||||
lhs = rhs
|
||||
if p.tok == token.ARROW {
|
||||
rhs = p.parseExpr()
|
||||
} else {
|
||||
p.expect(token.ARROW) // use expect() error handling
|
||||
}
|
||||
// SendStmt
|
||||
if len(lhs) > 1 {
|
||||
p.errorExpected(lhs[0].Pos(), "1 expression")
|
||||
// continue with first expression
|
||||
}
|
||||
arrow := p.pos
|
||||
p.next()
|
||||
rhs := p.parseExpr()
|
||||
comm = &ast.SendStmt{lhs[0], arrow, rhs}
|
||||
} else {
|
||||
// RecvStmt
|
||||
pos := p.pos
|
||||
tok := p.tok
|
||||
var rhs ast.Expr
|
||||
if p.tok == token.ASSIGN || p.tok == token.DEFINE {
|
||||
// RecvStmt with assignment
|
||||
if len(lhs) > 2 {
|
||||
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
|
||||
// continue with first two expressions
|
||||
lhs = lhs[0:2]
|
||||
}
|
||||
p.next()
|
||||
rhs = p.parseExpr()
|
||||
} else {
|
||||
// rhs must be single receive operation
|
||||
if len(lhs) > 1 {
|
||||
p.errorExpected(lhs[0].Pos(), "1 expression")
|
||||
// continue with first expression
|
||||
}
|
||||
rhs = lhs[0]
|
||||
lhs = nil // there is no lhs
|
||||
}
|
||||
if x, isUnary := rhs.(*ast.UnaryExpr); !isUnary || x.Op != token.ARROW {
|
||||
p.errorExpected(rhs.Pos(), "send or receive operation")
|
||||
rhs = &ast.BadExpr{rhs.Pos(), rhs.End()}
|
||||
}
|
||||
if lhs != nil {
|
||||
comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
|
||||
} else {
|
||||
comm = &ast.ExprStmt{rhs}
|
||||
}
|
||||
// else SendExpr
|
||||
}
|
||||
} else {
|
||||
p.expect(token.DEFAULT)
|
||||
@ -1516,7 +1546,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
|
||||
colon := p.expect(token.COLON)
|
||||
body := p.parseStmtList()
|
||||
|
||||
return &ast.CommClause{pos, tok, lhs, rhs, colon, body}
|
||||
return &ast.CommClause{pos, comm, colon, body}
|
||||
}
|
||||
|
||||
|
||||
@ -1568,7 +1598,7 @@ func (p *parser) parseForStmt() ast.Stmt {
|
||||
}
|
||||
// check rhs
|
||||
if len(as.Rhs) != 1 {
|
||||
p.errorExpected(as.Rhs[0].Pos(), "1 expressions")
|
||||
p.errorExpected(as.Rhs[0].Pos(), "1 expression")
|
||||
return &ast.BadStmt{pos, body.End()}
|
||||
}
|
||||
if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
|
||||
|
@ -46,6 +46,7 @@ var validPrograms = []interface{}{
|
||||
`package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
|
||||
`package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
|
||||
`package main; var a = T{{1, 2}, {3, 4}}`,
|
||||
`package main; func f() { select { case <- c: case c <- d: case c <- <- d: case <-c <- d: } };`,
|
||||
}
|
||||
|
||||
|
||||
|
@ -506,12 +506,12 @@ const (
|
||||
)
|
||||
|
||||
|
||||
func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
|
||||
func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
|
||||
switch e.Op.Precedence() {
|
||||
case 4:
|
||||
has4 = true
|
||||
case 5:
|
||||
has5 = true
|
||||
case 6:
|
||||
has6 = true
|
||||
}
|
||||
|
||||
switch l := e.X.(type) {
|
||||
@ -521,9 +521,9 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
|
||||
// pretend this is an *ast.ParenExpr and do nothing.
|
||||
break
|
||||
}
|
||||
h5, h6, mp := walkBinary(l)
|
||||
h4, h5, mp := walkBinary(l)
|
||||
has4 = has4 || h4
|
||||
has5 = has5 || h5
|
||||
has6 = has6 || h6
|
||||
if maxProblem < mp {
|
||||
maxProblem = mp
|
||||
}
|
||||
@ -536,25 +536,25 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
|
||||
// pretend this is an *ast.ParenExpr and do nothing.
|
||||
break
|
||||
}
|
||||
h5, h6, mp := walkBinary(r)
|
||||
h4, h5, mp := walkBinary(r)
|
||||
has4 = has4 || h4
|
||||
has5 = has5 || h5
|
||||
has6 = has6 || h6
|
||||
if maxProblem < mp {
|
||||
maxProblem = mp
|
||||
}
|
||||
|
||||
case *ast.StarExpr:
|
||||
if e.Op.String() == "/" {
|
||||
maxProblem = 6
|
||||
maxProblem = 5
|
||||
}
|
||||
|
||||
case *ast.UnaryExpr:
|
||||
switch e.Op.String() + r.Op.String() {
|
||||
case "/*", "&&", "&^":
|
||||
maxProblem = 6
|
||||
maxProblem = 5
|
||||
case "++", "--":
|
||||
if maxProblem < 5 {
|
||||
maxProblem = 5
|
||||
if maxProblem < 4 {
|
||||
maxProblem = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -563,20 +563,20 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
|
||||
|
||||
|
||||
func cutoff(e *ast.BinaryExpr, depth int) int {
|
||||
has5, has6, maxProblem := walkBinary(e)
|
||||
has4, has5, maxProblem := walkBinary(e)
|
||||
if maxProblem > 0 {
|
||||
return maxProblem + 1
|
||||
}
|
||||
if has5 && has6 {
|
||||
if has4 && has5 {
|
||||
if depth == 1 {
|
||||
return 6
|
||||
return 5
|
||||
}
|
||||
return 5
|
||||
return 4
|
||||
}
|
||||
if depth == 1 {
|
||||
return 7
|
||||
return 6
|
||||
}
|
||||
return 5
|
||||
return 4
|
||||
}
|
||||
|
||||
|
||||
@ -603,15 +603,14 @@ func reduceDepth(depth int) int {
|
||||
// (Algorithm suggestion by Russ Cox.)
|
||||
//
|
||||
// The precedences are:
|
||||
// 6 * / % << >> & &^
|
||||
// 5 + - | ^
|
||||
// 4 == != < <= > >=
|
||||
// 3 <-
|
||||
// 5 * / % << >> & &^
|
||||
// 4 + - | ^
|
||||
// 3 == != < <= > >=
|
||||
// 2 &&
|
||||
// 1 ||
|
||||
//
|
||||
// The only decision is whether there will be spaces around levels 5 and 6.
|
||||
// There are never spaces at level 7 (unary), and always spaces at levels 4 and below.
|
||||
// The only decision is whether there will be spaces around levels 4 and 5.
|
||||
// There are never spaces at level 6 (unary), and always spaces at levels 3 and below.
|
||||
//
|
||||
// To choose the cutoff, look at the whole expression but excluding primary
|
||||
// expressions (function calls, parenthesized exprs), and apply these rules:
|
||||
@ -619,21 +618,21 @@ func reduceDepth(depth int) int {
|
||||
// 1) If there is a binary operator with a right side unary operand
|
||||
// that would clash without a space, the cutoff must be (in order):
|
||||
//
|
||||
// /* 7
|
||||
// && 7
|
||||
// &^ 7
|
||||
// ++ 6
|
||||
// -- 6
|
||||
// /* 6
|
||||
// && 6
|
||||
// &^ 6
|
||||
// ++ 5
|
||||
// -- 5
|
||||
//
|
||||
// (Comparison operators always have spaces around them.)
|
||||
//
|
||||
// 2) If there is a mix of level 6 and level 5 operators, then the cutoff
|
||||
// is 6 (use spaces to distinguish precedence) in Normal mode
|
||||
// and 5 (never use spaces) in Compact mode.
|
||||
// 2) If there is a mix of level 5 and level 4 operators, then the cutoff
|
||||
// is 5 (use spaces to distinguish precedence) in Normal mode
|
||||
// and 4 (never use spaces) in Compact mode.
|
||||
//
|
||||
// 3) If there are no level 5 operators or no level 6 operators, then the
|
||||
// cutoff is 7 (always use spaces) in Normal mode
|
||||
// and 5 (never use spaces) in Compact mode.
|
||||
// 3) If there are no level 4 operators or no level 5 operators, then the
|
||||
// cutoff is 6 (always use spaces) in Normal mode
|
||||
// and 4 (never use spaces) in Compact mode.
|
||||
//
|
||||
// Sets multiLine to true if the binary expression spans multiple lines.
|
||||
func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiLine *bool) {
|
||||
@ -1083,6 +1082,12 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
|
||||
const depth = 1
|
||||
p.expr0(s.X, depth, multiLine)
|
||||
|
||||
case *ast.SendStmt:
|
||||
const depth = 1
|
||||
p.expr0(s.Chan, depth, multiLine)
|
||||
p.print(blank, s.Arrow, token.ARROW, blank)
|
||||
p.expr0(s.Value, depth, multiLine)
|
||||
|
||||
case *ast.IncDecStmt:
|
||||
const depth = 1
|
||||
p.expr0(s.X, depth+1, multiLine)
|
||||
@ -1179,13 +1184,9 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
|
||||
*multiLine = true
|
||||
|
||||
case *ast.CommClause:
|
||||
if s.Rhs != nil {
|
||||
if s.Comm != nil {
|
||||
p.print(token.CASE, blank)
|
||||
if s.Lhs != nil {
|
||||
p.expr(s.Lhs, multiLine)
|
||||
p.print(blank, s.Tok, blank)
|
||||
}
|
||||
p.expr(s.Rhs, multiLine)
|
||||
p.stmt(s.Comm, false, ignoreMultiLine)
|
||||
} else {
|
||||
p.print(token.DEFAULT)
|
||||
}
|
||||
|
@ -252,8 +252,8 @@ func (tok Token) String() string {
|
||||
//
|
||||
const (
|
||||
LowestPrec = 0 // non-operators
|
||||
UnaryPrec = 7
|
||||
HighestPrec = 8
|
||||
UnaryPrec = 6
|
||||
HighestPrec = 7
|
||||
)
|
||||
|
||||
|
||||
@ -267,14 +267,12 @@ func (op Token) Precedence() int {
|
||||
return 1
|
||||
case LAND:
|
||||
return 2
|
||||
case ARROW:
|
||||
return 3
|
||||
case EQL, NEQ, LSS, LEQ, GTR, GEQ:
|
||||
return 4
|
||||
return 3
|
||||
case ADD, SUB, OR, XOR:
|
||||
return 5
|
||||
return 4
|
||||
case MUL, QUO, REM, SHL, SHR, AND, AND_NOT:
|
||||
return 6
|
||||
return 5
|
||||
}
|
||||
return LowestPrec
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
|
||||
}
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
ch <- base+i
|
||||
ch <- base + i
|
||||
}
|
||||
close(ch)
|
||||
if done != nil {
|
||||
@ -61,7 +61,7 @@ func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
|
||||
}
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
ch <- base+i
|
||||
ch <- base + i
|
||||
}
|
||||
close(ch)
|
||||
if done != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user