]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast: track position of <- for channel types
authorRobert Griesemer <gri@golang.org>
Wed, 3 Oct 2012 00:50:36 +0000 (17:50 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 3 Oct 2012 00:50:36 +0000 (17:50 -0700)
This is a backward-compatible API change.

Without the correct <- position information,
certain channel types have incorrect position
information.

R=iant, iant
CC=golang-dev
https://golang.org/cl/6585063

src/pkg/go/ast/ast.go
src/pkg/go/parser/parser.go
src/pkg/go/parser/short_test.go
src/pkg/go/printer/nodes.go

index d2e75dc1c0312bf70fd79c08cc2a96db1f56474f..e1582c30064dc55cdccfa78a6cf3fbf1566566d6 100644 (file)
@@ -407,6 +407,7 @@ type (
        // A ChanType node represents a channel type.
        ChanType struct {
                Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
+               Arrow token.Pos // position of "<-" (noPos if there is no "<-")
                Dir   ChanDir   // channel direction
                Value Expr      // value type
        }
index 9c1459f40c9ce2a813362b518685e87068cc7d95..139de9fb227c493e705414aab1968989dcfcc99b 100644 (file)
@@ -924,20 +924,22 @@ func (p *parser) parseChanType() *ast.ChanType {
 
        pos := p.pos
        dir := ast.SEND | ast.RECV
+       var arrow token.Pos
        if p.tok == token.CHAN {
                p.next()
                if p.tok == token.ARROW {
+                       arrow = p.pos
                        p.next()
                        dir = ast.SEND
                }
        } else {
-               p.expect(token.ARROW)
+               arrow = p.expect(token.ARROW)
                p.expect(token.CHAN)
                dir = ast.RECV
        }
        value := p.parseType()
 
-       return &ast.ChanType{Begin: pos, Dir: dir, Value: value}
+       return &ast.ChanType{Begin: pos, Arrow: arrow, Dir: dir, Value: value}
 }
 
 // If the result is an identifier, it is not resolved.
@@ -1397,7 +1399,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 
        case token.ARROW:
                // channel type or receive expression
-               pos := p.pos
+               arrow := p.pos
                p.next()
 
                // If the next token is token.CHAN we still don't know if it
@@ -1421,29 +1423,25 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
                        // (<-type)
 
                        // re-associate position info and <-
-                       arrow := true
-                       for ok && arrow {
-                               begin := typ.Begin
+                       dir := ast.SEND
+                       for ok && dir == ast.SEND {
                                if typ.Dir == ast.RECV {
                                        // error: (<-type) is (<-(<-chan T))
-                                       p.errorExpected(begin, "'chan'")
+                                       p.errorExpected(typ.Arrow, "'chan'")
                                }
-                               arrow = typ.Dir == ast.SEND
-                               typ.Begin = pos
-                               typ.Dir = ast.RECV
+                               arrow, typ.Begin, typ.Arrow = typ.Arrow, arrow, arrow
+                               dir, typ.Dir = typ.Dir, ast.RECV
                                typ, ok = typ.Value.(*ast.ChanType)
-                               // TODO(gri) ast.ChanType should store exact <- position
-                               pos = begin // estimate (we don't have the exact position of <- for send channels)
                        }
-                       if arrow {
-                               p.errorExpected(pos, "'chan'")
+                       if dir == ast.SEND {
+                               p.errorExpected(arrow, "channel type")
                        }
 
                        return x
                }
 
                // <-(expr)
-               return &ast.UnaryExpr{OpPos: pos, Op: token.ARROW, X: p.checkExpr(x)}
+               return &ast.UnaryExpr{OpPos: arrow, Op: token.ARROW, X: p.checkExpr(x)}
 
        case token.MUL:
                // pointer type or unary "*" expression
index d5856e4f95725bbf2b0dfbe1b60b2dc8a2969b43..daba853088631f4bccfb81d37b666b17866888ef 100644 (file)
@@ -69,7 +69,7 @@ var invalids = []string{
        `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
        `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
        `package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
-       `package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan /* ERROR "expected 'chan'" */ <-int)(nil) };`,
+       `package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan<- /* ERROR "expected channel type" */ int)(nil) };`,
 }
 
 func TestInvalid(t *testing.T) {
index 04f2adbd87b8fabfe5322bb629879bf9e19b01b1..01a7473b8350e3c0bad115018e820a6f1776a900 100644 (file)
@@ -853,9 +853,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
                case ast.SEND | ast.RECV:
                        p.print(token.CHAN)
                case ast.RECV:
-                       p.print(token.ARROW, token.CHAN)
+                       p.print(token.ARROW, token.CHAN) // x.Arrow and x.Pos() are the same
                case ast.SEND:
-                       p.print(token.CHAN, token.ARROW)
+                       p.print(token.CHAN, x.Arrow, token.ARROW)
                }
                p.print(blank)
                p.expr(x.Value)