]> Cypherpunks repositories - gostls13.git/commitdiff
- renamed scanner.Location to token.Position
authorRobert Griesemer <gri@golang.org>
Thu, 26 Mar 2009 23:08:44 +0000 (16:08 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 26 Mar 2009 23:08:44 +0000 (16:08 -0700)
- by moving Position into token, scanner dependencies
  are removed from several files
- clearer field names in token.Position, now possible to
  have a Pos() accessor w/o naming conflicts
- added Pos() accessor
- use anonymous token.Position field in AST nodes

R=r
DELTA=244  (28 added, 55 deleted, 161 changed)
OCL=26786
CL=26793

src/lib/go/scanner.go
src/lib/go/scanner_test.go
src/lib/go/token.go
usr/gri/pretty/ast.go

index 51dca3aa59a892d869ef5e357ee443f8d6946e7e..41ce78218b0307d398dcf18fa13a331150f60262 100644 (file)
@@ -16,28 +16,20 @@ import (
 )
 
 
-// Source locations are represented by a Location value.
-type Location struct {
-       Pos int;  // byte position in source
-       Line int;  // line count, starting at 1
-       Col int;  // column, starting at 1 (character count)
-}
-
-
 // An implementation of an ErrorHandler must be provided to the Scanner.
-// If a syntax error is encountered, Error is called with a location and
-// an error message. The location points at the beginning of the offending
+// If a syntax error is encountered, Error is called with a position and
+// an error message. The position points to the beginning of the offending
 // token.
 //
 type ErrorHandler interface {
-       Error(loc Location, msg string);
+       Error(pos token.Position, msg string);
 }
 
 
 // A Scanner holds the scanner's internal state while processing
 // a given text.  It can be allocated as part of another data
-// structure but must be initialized via Init before use.
-// See also the package comment for a sample use.
+// structure but must be initialized via Init before use. For
+// a sample use, see the implementation of Tokenize.
 //
 type Scanner struct {
        // immutable state
@@ -46,31 +38,32 @@ type Scanner struct {
        scan_comments bool;  // if set, comments are reported as tokens
 
        // scanning state
-       loc Location;  // location before ch (src[loc.Pos] == ch)
-       pos int;  // current reading position (position after ch)
+       pos token.Position;  // previous reading position (position before ch)
+       offset int;  // current reading offset (position after ch)
        ch int;  // one char look-ahead
 }
 
 
 // Read the next Unicode char into S.ch.
 // S.ch < 0 means end-of-file.
+//
 func (S *Scanner) next() {
-       if S.pos < len(S.src) {
-               S.loc.Pos = S.pos;
-               S.loc.Col++;
-               r, w := int(S.src[S.pos]), 1;
+       if S.offset < len(S.src) {
+               S.pos.Offset = S.offset;
+               S.pos.Column++;
+               r, w := int(S.src[S.offset]), 1;
                switch {
                case r == '\n':
-                       S.loc.Line++;
-                       S.loc.Col = 0;
+                       S.pos.Line++;
+                       S.pos.Column = 0;
                case r >= 0x80:
                        // not ASCII
-                       r, w = utf8.DecodeRune(S.src[S.pos : len(S.src)]);
+                       r, w = utf8.DecodeRune(S.src[S.offset : len(S.src)]);
                }
-               S.pos += w;
+               S.offset += w;
                S.ch = r;
        } else {
-               S.loc.Pos = len(S.src);
+               S.pos.Offset = len(S.src);
                S.ch = -1;  // eof
        }
 }
@@ -86,13 +79,13 @@ func (S *Scanner) Init(src []byte, err ErrorHandler, scan_comments bool) {
        S.src = src;
        S.err = err;
        S.scan_comments = scan_comments;
-       S.loc.Line = 1;
+       S.pos.Line = 1;
        S.next();
 }
 
 
 func charString(ch int) string {
-       s := string(ch);
+       var s string;
        switch ch {
        case '\a': s = `\a`;
        case '\b': s = `\b`;
@@ -103,25 +96,26 @@ func charString(ch int) string {
        case '\v': s = `\v`;
        case '\\': s = `\\`;
        case '\'': s = `\'`;
+       default  : s = utf8.EncodeRuneToString(ch);
        }
        return "'" + s + "' (U+" + strconv.Itob(ch, 16) + ")";
 }
 
 
-func (S *Scanner) error(loc Location, msg string) {
-       S.err.Error(loc, msg);
+func (S *Scanner) error(pos token.Position, msg string) {
+       S.err.Error(pos, msg);
 }
 
 
 func (S *Scanner) expect(ch int) {
        if S.ch != ch {
-               S.error(S.loc, "expected " + charString(ch) + ", found " + charString(S.ch));
+               S.error(S.pos, "expected " + charString(ch) + ", found " + charString(S.ch));
        }
        S.next();  // always make progress
 }
 
 
-func (S *Scanner) scanComment(loc Location) {
+func (S *Scanner) scanComment(pos token.Position) {
        // first '/' already consumed
 
        if S.ch == '/' {
@@ -147,7 +141,7 @@ func (S *Scanner) scanComment(loc Location) {
                }
        }
 
-       S.error(loc, "comment not terminated");
+       S.error(pos, "comment not terminated");
 }
 
 
@@ -168,11 +162,11 @@ func isDigit(ch int) bool {
 
 
 func (S *Scanner) scanIdentifier() token.Token {
-       pos := S.loc.Pos;
+       pos := S.pos.Offset;
        for isLetter(S.ch) || isDigit(S.ch) {
                S.next();
        }
-       return token.Lookup(S.src[pos : S.loc.Pos]);
+       return token.Lookup(S.src[pos : S.pos.Offset]);
 }
 
 
@@ -255,13 +249,13 @@ func (S *Scanner) scanDigits(base, length int) {
                length--;
        }
        if length > 0 {
-               S.error(S.loc, "illegal char escape");
+               S.error(S.pos, "illegal char escape");
        }
 }
 
 
 func (S *Scanner) scanEscape(quote int) {
-       loc := S.loc;
+       pos := S.pos;
        ch := S.ch;
        S.next();
        switch ch {
@@ -276,7 +270,7 @@ func (S *Scanner) scanEscape(quote int) {
        case 'U':
                S.scanDigits(16, 8);
        default:
-               S.error(loc, "illegal char escape");
+               S.error(pos, "illegal char escape");
        }
 }
 
@@ -294,14 +288,14 @@ func (S *Scanner) scanChar() {
 }
 
 
-func (S *Scanner) scanString(loc Location) {
+func (S *Scanner) scanString(pos token.Position) {
        // '"' already consumed
 
        for S.ch != '"' {
                ch := S.ch;
                S.next();
                if ch == '\n' || ch < 0 {
-                       S.error(loc, "string not terminated");
+                       S.error(pos, "string not terminated");
                        break;
                }
                if ch == '\\' {
@@ -313,14 +307,14 @@ func (S *Scanner) scanString(loc Location) {
 }
 
 
-func (S *Scanner) scanRawString(loc Location) {
+func (S *Scanner) scanRawString(pos token.Position) {
        // '`' already consumed
 
        for S.ch != '`' {
                ch := S.ch;
                S.next();
                if ch == '\n' || ch < 0 {
-                       S.error(loc, "string not terminated");
+                       S.error(pos, "string not terminated");
                        break;
                }
        }
@@ -374,11 +368,11 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
 }
 
 
-// Scan scans the next token and returns the token location loc,
+// Scan scans the next token and returns the token position pos,
 // the token tok, and the literal text lit corresponding to the
 // token. The source end is indicated by token.EOF.
 //
-func (S *Scanner) Scan() (loc Location, tok token.Token, lit []byte) {
+func (S *Scanner) Scan() (pos token.Position, tok token.Token, lit []byte) {
 scan_again:
        // skip white space
        for S.ch == ' ' || S.ch == '\t' || S.ch == '\n' || S.ch == '\r' {
@@ -386,7 +380,7 @@ scan_again:
        }
 
        // current token start
-       loc, tok = S.loc, token.ILLEGAL;
+       pos, tok = S.pos, token.ILLEGAL;
 
        // determine token value
        switch ch := S.ch; {
@@ -398,9 +392,9 @@ scan_again:
                S.next();  // always make progress
                switch ch {
                case -1  : tok = token.EOF;
-               case '"' : tok = token.STRING; S.scanString(loc);
+               case '"' : tok = token.STRING; S.scanString(pos);
                case '\'': tok = token.CHAR; S.scanChar();
-               case '`' : tok = token.STRING; S.scanRawString(loc);
+               case '`' : tok = token.STRING; S.scanRawString(pos);
                case ':' : tok = S.switch2(token.COLON, token.DEFINE);
                case '.' :
                        if digitVal(S.ch) < 10 {
@@ -427,7 +421,7 @@ scan_again:
                case '*': tok = S.switch2(token.MUL, token.MUL_ASSIGN);
                case '/':
                        if S.ch == '/' || S.ch == '*' {
-                               S.scanComment(loc);
+                               S.scanComment(pos);
                                tok = token.COMMENT;
                                if !S.scan_comments {
                                        goto scan_again;
@@ -455,20 +449,20 @@ scan_again:
                                tok = S.switch3(token.AND, token.AND_ASSIGN, '&', token.LAND);
                        }
                case '|': tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR);
-               default: S.error(loc, "illegal character " + charString(ch));
+               default: S.error(pos, "illegal character " + charString(ch));
                }
        }
 
-       return loc, tok, S.src[loc.Pos : S.loc.Pos];
+       return pos, tok, S.src[pos.Offset : S.pos.Offset];
 }
 
 
-// Tokenize calls a function f with the token location, token value, and token
+// Tokenize calls a function f with the token position, token value, and token
 // text for each token in the source src. The other parameters have the same
 // meaning as for the Init function. Tokenize keeps scanning until f returns
 // false (usually when the token value is token.EOF).
 //
-func Tokenize(src []byte, err ErrorHandler, scan_comments bool, f func (loc Location, tok token.Token, lit []byte) bool) {
+func Tokenize(src []byte, err ErrorHandler, scan_comments bool, f func (pos token.Position, tok token.Token, lit []byte) bool) {
        var s Scanner;
        s.Init(src, err, scan_comments);
        for f(s.Scan()) {
index 2309fcd097fbe7617cb900fc4b67258986b527bb..2042b191f821e51997dc14accc17905fd0f9cbf3 100644 (file)
@@ -160,7 +160,7 @@ type TestErrorHandler struct {
        t *testing.T
 }
 
-func (h *TestErrorHandler) Error(loc scanner.Location, msg string) {
+func (h *TestErrorHandler) Error(pos token.Position, msg string) {
        h.t.Errorf("Error() called (msg = %s)", msg);
 }
 
@@ -186,9 +186,9 @@ func Test(t *testing.T) {
 
        // verify scan
        index := 0;
-       eloc := scanner.Location{0, 1, 1};
+       eloc := token.Position{0, 1, 1};
        scanner.Tokenize(io.StringBytes(src), &TestErrorHandler{t}, true,
-               func (loc Location, tok token.Token, litb []byte) bool {
+               func (pos token.Position, tok token.Token, litb []byte) bool {
                        e := elt{token.EOF, "", special};
                        if index < len(tokens) {
                                e = tokens[index];
@@ -196,16 +196,16 @@ func Test(t *testing.T) {
                        lit := string(litb);
                        if tok == token.EOF {
                                lit = "<EOF>";
-                               eloc.Col = 0;
+                               eloc.Column = 0;
                        }
-                       if loc.Pos != eloc.Pos {
-                               t.Errorf("bad position for %s: got %d, expected %d", lit, loc.Pos, eloc.Pos);
+                       if pos.Offset != eloc.Offset {
+                               t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, eloc.Offset);
                        }
-                       if loc.Line != eloc.Line {
-                               t.Errorf("bad line for %s: got %d, expected %d", lit, loc.Line, eloc.Line);
+                       if pos.Line != eloc.Line {
+                               t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, eloc.Line);
                        }
-                       if loc.Col != eloc.Col {
-                               t.Errorf("bad column for %s: got %d, expected %d", lit, loc.Col, eloc.Col);
+                       if pos.Column!= eloc.Column {
+                               t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, eloc.Column);
                        }
                        if tok != e.tok {
                                t.Errorf("bad token for %s: got %s, expected %s", lit, tok.String(), e.tok.String());
@@ -216,7 +216,7 @@ func Test(t *testing.T) {
                        if tokenclass(tok) != e.class {
                                t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
                        }
-                       eloc.Pos += len(lit) + len(whitespace);
+                       eloc.Offset += len(lit) + len(whitespace);
                        eloc.Line += NewlineCount(lit) + whitespace_linecount;
                        index++;
                        return tok != token.EOF;
index a0439b8687c4bada23c8c10b1be10bc04f61b59a..696210979324bc01f51bbda04e1f63b2f27c67c4 100644 (file)
@@ -255,10 +255,10 @@ const (
 
 
 // Precedence returns the syntax precedence of the operator
-// token tok or LowestPrecedence if tok is not an operator.
+// token op or LowestPrecedence if op is not an operator.
 //
-func (tok Token) Precedence() int {
-       switch tok {
+func (op Token) Precedence() int {
+       switch op {
        case COLON:
                return 0;
        case LOR:
@@ -322,3 +322,19 @@ func (tok Token) IsOperator() bool {
 func (tok Token) IsKeyword() bool {
        return keyword_beg < tok && tok < keyword_end;
 }
+
+
+// Token source positions are represented by a Position value.
+type Position struct {
+       Offset int;  // byte offset, starting at 0
+       Line int;  // line number, starting at 1
+       Column int;  // column number, starting at 1 (character count)
+}
+
+
+// Pos is an accessor method for anonymous Position fields.
+// It returns its receiver.
+//
+func (pos *Position) Pos() Position {
+       return *pos;
+}
index cb3c69c5c5a4814eb5f7f233252bcdc0a730c435..d597e97a02948e3ca11525b6135424fd9d1288fb 100644 (file)
@@ -7,14 +7,7 @@
 //
 package ast
 
-import (
-       "token";
-       "scanner";
-)
-
-
-// TODO rename Position to scanner.Position, possibly factor out
-type Position scanner.Location
+import "token"
 
 
 // ----------------------------------------------------------------------------
@@ -26,18 +19,17 @@ type Position scanner.Location
 // correspond. The node fields correspond to the individual parts
 // of the respective productions.
 //
-// Nodes contain selective position information: a position field
-// marking the beginning of the corresponding source text segment
-// if necessary; and specific position information for language
-// constructs where comments may be found between parts of the
-// construct (typically any larger, parenthesized subpart). The
-// position information is needed to properly position comments
+// All nodes contain position information marking the beginning of
+// the corresponding source text segment; it is accessible via the
+// Pos accessor method. Nodes may contain additional position info
+// for language constructs where comments may be found between parts
+// of the construct (typically any larger, parenthesized subpart).
+// That position information is needed to properly position comments
 // when printing the construct.
 
 // TODO: For comment positioning only the byte position and not
-// a complete Position field is needed. May be able to trim node
-// sizes a bit. Then, embed Position field so we can get rid of
-// most of the Pos() methods.
+// a complete token.Position field is needed. May be able to trim
+// node sizes a bit.
 
 
 type (
@@ -55,7 +47,7 @@ type Expr interface {
        Visit(v ExprVisitor);
        
        // Pos returns the (beginning) position of the expression.
-       Pos() Position;
+       Pos() token.Position;
 }
 
 
@@ -67,7 +59,7 @@ type Stmt interface {
        Visit(v StmtVisitor);
        
        // Pos returns the (beginning) position of the statement.
-       Pos() Position;
+       Pos() token.Position;
 }
 
 
@@ -79,7 +71,7 @@ type Decl interface {
        Visit(v DeclVisitor);
        
        // Pos returns the (beginning) position of the declaration.
-       Pos() Position;
+       Pos() token.Position;
 }
 
 
@@ -88,7 +80,7 @@ type Decl interface {
 
 // A Comment node represents a single //-style or /*-style comment.
 type Comment struct {
-       Pos_ Position;  // beginning position of the comment
+       token.Position;  // beginning position of the comment
        Text []byte;  // the comment text (without '\n' for //-style comments)
        EndLine int;  // the line where the comment ends
 }
@@ -131,12 +123,12 @@ type (
        // created.
        //
        BadExpr struct {
-               Pos_ Position;  // beginning position of bad expression
+               token.Position;  // beginning position of bad expression
        };
 
        // An Ident node represents an identifier.
        Ident struct {
-               Pos_ Position;  // identifier position
+               token.Position;  // identifier position
                Lit []byte;  // identifier string (e.g. foobar)
        };
 
@@ -144,30 +136,30 @@ type (
        // parameter list or the "..." length in an array type.
        //
        Ellipsis struct {
-               Pos_ Position;  // position of "..."
+               token.Position;  // position of "..."
        };
 
        // An IntLit node represents an integer literal.
        IntLit struct {
-               Pos_ Position;  // literal string position
+               token.Position;  // int literal position
                Lit []byte;  // literal string; e.g. 42 or 0x7f
        };
 
        // A FloatLit node represents a floating-point literal.
        FloatLit struct {
-               Pos_ Position;  // literal string position
+               token.Position;  // float literal position
                Lit []byte;  // literal string; e.g. 3.14 or 1e-9
        };
 
        // A CharLit node represents a character literal.
        CharLit struct {
-               Pos_ Position;  // literal string position
+               token.Position;  // char literal position
                Lit []byte;  // literal string, including quotes; e.g. 'a' or '\x7f'
        };
 
        // A StringLit node represents a string literal.
        StringLit struct {
-               Pos_ Position;  // literal string position
+               token.Position;  // string literal position
                Lit []byte;  // literal string, including quotes; e.g. "foo" or `\m\n\o`
        };
 
@@ -187,18 +179,22 @@ type (
        };
 
        // A CompositeLit node represents a composite literal.
+       // A pair (x : y) in a CompositeLit is represented by
+       // a binary expression with the Colon operator.
+       // TODO decide if better to use a Pair node instead.
+       //
        CompositeLit struct {
                Type Expr;  // literal type
-               Lbrace Position;  // position of "{"
+               Lbrace token.Position;  // position of "{"
                Elts []Expr;  // list of composite elements
-               Rbrace Position;  // position of "}"
+               Rbrace token.Position;  // position of "}"
        };
 
        // A ParenExpr node represents a parenthesized expression.
        ParenExpr struct {
-               Lparen Position;  // position of "("
+               token.Position;  // position of "("
                X Expr;  // parenthesized expression
-               Rparen Position;  // position of ")"
+               Rparen token.Position;  // position of ")"
        };
 
        // A SelectorExpr node represents an expression followed by a selector.
@@ -230,15 +226,15 @@ type (
        // A CallExpr node represents an expression followed by an argument list.
        CallExpr struct {
                Fun Expr;  // function expression
-               Lparen Position;  // position of "("
+               Lparen token.Position;  // position of "("
                Args []Expr;  // function arguments
-               Rparen Position;  // positions of ")"
+               Rparen token.Position;  // positions of ")"
        };
 
        // A StarExpr node represents an expression of the form "*" Expression.
        // Semantically it could be a unary "*" expression, or a pointer type.
        StarExpr struct {
-               Star Position;  // position of "*"
+               token.Position;  // position of "*"
                X Expr;  // operand
        };
 
@@ -246,16 +242,20 @@ type (
        // Unary "*" expressions are represented via DerefExpr nodes.
        //
        UnaryExpr struct {
-               Pos_ Position;  // token position
-               Tok token.Token;  // operator
+               token.Position;  // position of Op
+               Op token.Token;  // operator
                X Expr;  // operand
        };
 
        // A BinaryExpr node represents a binary expression.
+       // A pair (x : y) in a CompositeLit is represented by
+       // a binary expression with the Colon operator.
+       // TODO decide if better to use a Pair node instead.
+       //
        BinaryExpr struct {
                X Expr;  // left operand
-               Pos_ Position;  // token position
-               Tok token.Token;  // operator
+               OpPos token.Position;  // position of Op
+               Op token.Token;  // operator
                Y Expr;  // right operand
        };
 )
@@ -278,85 +278,70 @@ const (
 type (
        // An ArrayType node represents an array type.
        ArrayType struct {
-               Lbrack Position;  // position of "["
+               token.Position;  // position of "["
                Len Expr;  // possibly an Ellipsis node for [...]T array types
                Elt Expr;  // element type
        };
 
        // A SliceType node represents a slice type.
        SliceType struct {
-               Lbrack Position;  // position of "["
+               token.Position;  // position of "["
                Elt Expr;  // element type
        };
 
        // A StructType node represents a struct type.
        StructType struct {
-               Struct, Lbrace Position;  // positions of "struct" keyword, "{"
+               token.Position;  // position of "struct" keyword
+               Lbrace token.Position;  // position of "{"
                Fields []*Field;  // list of field declarations; nil if forward declaration
-               Rbrace Position;  // position of "}"
+               Rbrace token.Position;  // position of "}"
        };
 
        // Pointer types are represented via StarExpr nodes.
 
        // A FunctionType node represents a function type.
        FunctionType struct {
-               Func Position;  // position of "func" keyword
+               token.Position;  // position of "func" keyword
                Params []*Field;  // (incoming) parameters
                Results []*Field;  // (outgoing) results
        };
 
        // An InterfaceType node represents an interface type.
        InterfaceType struct {
-               Interface, Lbrace Position;  // positions of "interface" keyword, "{"
+               token.Position;  // position of "interface" keyword
+               Lbrace token.Position;  // position of "{"
                Methods []*Field; // list of methods; nil if forward declaration
-               Rbrace Position;  // position of "}"
+               Rbrace token.Position;  // position of "}"
        };
 
        // A MapType node represents a map type.
        MapType struct {
-               Map Position;  // position of "map" keyword
+               token.Position;  // position of "map" keyword
                Key Expr;
                Value Expr;
        };
 
        // A ChannelType node represents a channel type.
        ChannelType struct {
-               Pos_ Position;  // position of "chan" keyword or "<-" (whichever comes first)
+               token.Position;  // position of "chan" keyword or "<-" (whichever comes first)
                Dir ChanDir;  // channel direction
                Value Expr;  // value type
        };
 )
 
 
-// Pos() implementations for all expression/type nodes.
+// Pos() implementations for expression/type where the position
+// corresponds to the position of a sub-node.
 //
-func (x *BadExpr) Pos() Position  { return x.Pos_; }
-func (x *Ident) Pos() Position  { return x.Pos_; }
-func (x *IntLit) Pos() Position  { return x.Pos_; }
-func (x *FloatLit) Pos() Position  { return x.Pos_; }
-func (x *CharLit) Pos() Position  { return x.Pos_; }
-func (x *StringLit) Pos() Position  { return x.Pos_; }
-func (x *StringList) Pos() Position  { return x.Strings[0].Pos(); }
-func (x *FunctionLit) Pos() Position  { return x.Type.Func; }
-func (x *CompositeLit) Pos() Position  { return x.Type.Pos(); }
-func (x *ParenExpr) Pos() Position  { return x.Lparen; }
-func (x *SelectorExpr) Pos() Position  { return x.X.Pos(); }
-func (x *IndexExpr) Pos() Position  { return x.X.Pos(); }
-func (x *SliceExpr) Pos() Position  { return x.X.Pos(); }
-func (x *TypeAssertExpr) Pos() Position  { return x.X.Pos(); }
-func (x *CallExpr) Pos() Position  { return x.Fun.Pos(); }
-func (x *StarExpr) Pos() Position  { return x.Star; }
-func (x *UnaryExpr) Pos() Position  { return x.Pos_; }
-func (x *BinaryExpr) Pos() Position  { return x.X.Pos(); }
-
-func (x *Ellipsis) Pos() Position { return x.Pos_; }
-func (x *ArrayType) Pos() Position { return x.Lbrack; }
-func (x *SliceType) Pos() Position { return x.Lbrack; }
-func (x *StructType) Pos() Position { return x.Struct; }
-func (x *FunctionType) Pos() Position { return x.Func; }
-func (x *InterfaceType) Pos() Position { return x.Interface; }
-func (x *MapType) Pos() Position { return x.Map; }
-func (x *ChannelType) Pos() Position { return x.Pos_; }
+func (x *StringList) Pos() token.Position  { return x.Strings[0].Pos(); }
+func (x *FunctionLit) Pos() token.Position  { return x.Type.Pos(); }
+func (x *CompositeLit) Pos() token.Position  { return x.Type.Pos(); }
+func (x *SelectorExpr) Pos() token.Position  { return x.X.Pos(); }
+func (x *IndexExpr) Pos() token.Position  { return x.X.Pos(); }
+func (x *SliceExpr) Pos() token.Position  { return x.X.Pos(); }
+func (x *TypeAssertExpr) Pos() token.Position  { return x.X.Pos(); }
+func (x *CallExpr) Pos() token.Position  { return x.Fun.Pos(); }
+func (x *BinaryExpr) Pos() token.Position  { return x.X.Pos(); }
 
 
 // All expression/type nodes implement a Visit method which takes
@@ -440,7 +425,7 @@ type (
        // created.
        //
        BadStmt struct {
-               Pos_ Position;  // beginning position of bad statement
+               token.Position;  // beginning position of bad statement
        };
 
        // A DeclStmt node represents a declaration in a statement list.
@@ -453,7 +438,7 @@ type (
        // of the immediately preceeding semicolon.
        //
        EmptyStmt struct {
-               Semicolon Position;  // position of preceeding ";"
+               token.Position;  // position of preceeding ";"
        };
 
        // A LabeledStmt node represents a labeled statement.
@@ -479,26 +464,26 @@ type (
        // a short variable declaration.
        AssignStmt struct {
                Lhs []Expr;
-               Pos_ Position;  // token position
+               TokPos token.Position;  // position of Tok
                Tok token.Token;  // assignment token, DEFINE
                Rhs []Expr;
        };
 
        // A GoStmt node represents a go statement.
        GoStmt struct {
-               Go Position;  // position of "go" keyword
+               token.Position;  // position of "go" keyword
                Call *CallExpr;
        };
 
        // A DeferStmt node represents a defer statement.
        DeferStmt struct {
-               Defer Position;  // position of "defer" keyword
+               token.Position;  // position of "defer" keyword
                Call *CallExpr;
        };
 
        // A ReturnStmt node represents a return statement.
        ReturnStmt struct {
-               Return Position;  // position of "return" keyword
+               token.Position;  // position of "return" keyword
                Results []Expr;
        };
 
@@ -506,21 +491,21 @@ type (
        // or fallthrough statement.
        //
        BranchStmt struct {
-               Pos_ Position;  // position of keyword
+               token.Position;  // position of Tok
                Tok token.Token;  // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
                Label *Ident;
        };
 
        // A BlockStmt node represents a braced statement list.
        BlockStmt struct {
-               Lbrace Position;
+               token.Position;  // position of "{"
                List []Stmt;
-               Rbrace Position;
+               Rbrace token.Position;  // position of "}"
        };
 
        // An IfStmt node represents an if statement.
        IfStmt struct {
-               If Position;  // position of "if" keyword
+               token.Position;  // position of "if" keyword
                Init Stmt;
                Cond Expr;
                Body *BlockStmt;
@@ -529,15 +514,15 @@ type (
 
        // A CaseClause represents a case of an expression switch statement.
        CaseClause struct {
-               Case Position;  // position of "case" or "default" keyword
+               token.Position;  // position of "case" or "default" keyword
                Values []Expr;  // nil means default case
-               Colon Position;  // position of ":"
+               Colon token.Position;  // position of ":"
                Body []Stmt;  // statement list; or nil
        };
 
        // A SwitchStmt node represents an expression switch statement.
        SwitchStmt struct {
-               Switch Position;  // position of "switch" keyword
+               token.Position;  // position of "switch" keyword
                Init Stmt;
                Tag Expr;
                Body *BlockStmt;  // CaseClauses only
@@ -545,15 +530,15 @@ type (
 
        // A TypeCaseClause represents a case of a type switch statement.
        TypeCaseClause struct {
-               Case Position;  // position of "case" or "default" keyword
+               token.Position;  // position of "case" or "default" keyword
                Type Expr;  // nil means default case
-               Colon Position;  // position of ":"
+               Colon token.Position;  // position of ":"
                Body []Stmt;  // statement list; or nil
        };
 
        // An TypeSwitchStmt node represents a type switch statement.
        TypeSwitchStmt struct {
-               Switch Position;  // position of "switch" keyword
+               token.Position;  // position of "switch" keyword
                Init Stmt;
                Assign Stmt;  // x := y.(type)
                Body *BlockStmt;  // TypeCaseClauses only
@@ -561,22 +546,22 @@ type (
 
        // A CommClause node represents a case of a select statement.
        CommClause struct {
-               Case Position;  // position of "case" or "default" keyword
+               token.Position;  // 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 Position;  // position of ":"
+               Colon token.Position;  // position of ":"
                Body []Stmt;  // statement list; or nil
        };
 
        // An SelectStmt node represents a select statement.
        SelectStmt struct {
-               Select Position;  // position of "select" keyword
+               token.Position;  // position of "select" keyword
                Body *BlockStmt;  // CommClauses only
        };
 
        // A ForStmt represents a for statement.
        ForStmt struct {
-               For Position;  // position of "for" keyword
+               token.Position;  // position of "for" keyword
                Init Stmt;
                Cond Expr;
                Post Stmt;
@@ -585,39 +570,24 @@ type (
 
        // A RangeStmt represents a for statement with a range clause.
        RangeStmt struct {
-               For Position;  // position of "for" keyword
+               token.Position;  // position of "for" keyword
                Key, Value Expr;  // Value may be nil
-               Pos_ Position;  // token position
-               Tok token.Token;  // ASSIGN or DEFINE
+               TokPos token.Position;  // position of Tok
+               Tok token.Token;  // ASSIGN, DEFINE
                X Expr;  // value to range over
                Body *BlockStmt;
        };
 )
 
 
-// Pos() implementations for all statement nodes.
+// Pos() implementations for statement nodes where the position
+// corresponds to the position of a sub-node.
 //
-func (s *BadStmt) Pos() Position { return s.Pos_; }
-func (s *DeclStmt) Pos() Position { return s.Decl.Pos(); }
-func (s *EmptyStmt) Pos() Position { return s.Semicolon; }
-func (s *LabeledStmt) Pos() Position { return s.Label.Pos(); }
-func (s *ExprStmt) Pos() Position { return s.X.Pos(); }
-func (s *IncDecStmt) Pos() Position { return s.X.Pos(); }
-func (s *AssignStmt) Pos() Position { return s.Lhs[0].Pos(); }
-func (s *GoStmt) Pos() Position { return s.Go; }
-func (s *DeferStmt) Pos() Position { return s.Defer; }
-func (s *ReturnStmt) Pos() Position { return s.Return; }
-func (s *BranchStmt) Pos() Position { return s.Pos_; }
-func (s *BlockStmt) Pos() Position { return s.Lbrace; }
-func (s *IfStmt) Pos() Position { return s.If; }
-func (s *CaseClause) Pos() Position { return s.Case; }
-func (s *SwitchStmt) Pos() Position { return s.Switch; }
-func (s *TypeCaseClause) Pos() Position { return s.Case; }
-func (s *TypeSwitchStmt) Pos() Position { return s.Switch; }
-func (s *CommClause) Pos() Position { return s.Case; }
-func (s *SelectStmt) Pos() Position { return s.Select; }
-func (s *ForStmt) Pos() Position { return s.For; }
-func (s *RangeStmt) Pos() Position { return s.For; }
+func (s *DeclStmt) Pos() token.Position { return s.Decl.Pos(); }
+func (s *LabeledStmt) Pos() token.Position { return s.Label.Pos(); }
+func (s *ExprStmt) Pos() token.Position { return s.X.Pos(); }
+func (s *IncDecStmt) Pos() token.Position { return s.X.Pos(); }
+func (s *AssignStmt) Pos() token.Position { return s.Lhs[0].Pos(); }
 
 
 // All statement nodes implement a Visit method which takes
@@ -686,19 +656,19 @@ type (
        // created.
        //
        BadDecl struct {
-               Pos_ Position;  // beginning position of bad declaration
+               token.Position;  // beginning position of bad declaration
        };
 
        ImportDecl struct {
                Doc Comments;  // associated documentation; or nil
-               Import Position;  // position of "import" keyword
+               token.Position;  // position of "import" keyword
                Name *Ident;  // local package name or nil
                Path []*StringLit;  // package path
        };
 
        ConstDecl struct {
                Doc Comments;  // associated documentation; or nil
-               Const Position;  // position of "const" keyword
+               token.Position;  // position of "const" keyword
                Names []*Ident;
                Type Expr;  // constant type or nil
                Values []Expr;
@@ -706,14 +676,14 @@ type (
 
        TypeDecl struct {
                Doc Comments;  // associated documentation; or nil
-               Pos_ Position;  // position of "type" keyword
+               token.Position;  // position of "type" keyword
                Name *Ident;
                Type Expr;
        };
 
        VarDecl struct {
                Doc Comments;  // associated documentation; or nil
-               Var Position;  // position of "var" keyword
+               token.Position;  // position of "var" keyword
                Names []*Ident;
                Type Expr;  // variable type or nil
                Values []Expr;
@@ -729,24 +699,17 @@ type (
 
        DeclList struct {
                Doc Comments;  // associated documentation; or nil
-               Pos_ Position;  // position of token
+               token.Position;  // position of Tok
                Tok token.Token;  // IMPORT, CONST, VAR, TYPE
-               Lparen Position;  // position of '('
+               Lparen token.Position;  // position of '('
                List []Decl;  // the list of parenthesized declarations
-               Rparen Position;  // position of ')'
+               Rparen token.Position;  // position of ')'
        };
 )
 
 
-// Pos() implementations for all declaration nodes.
-//
-func (d *BadDecl) Pos() Position { return d.Pos_; }
-func (d *ImportDecl) Pos() Position { return d.Import; }
-func (d *ConstDecl) Pos() Position { return d.Const; }
-func (d *TypeDecl) Pos() Position { return d.Pos_; }
-func (d *VarDecl) Pos() Position { return d.Var; }
-func (d *FuncDecl) Pos() Position { return d.Type.Func; }
-func (d *DeclList) Pos() Position { return d.Lparen; }
+// The position of a FuncDecl node is the position of its function type.
+func (d *FuncDecl) Pos() token.Position  { return d.Type.Pos(); }
 
 
 // All declaration nodes implement a Visit method which takes
@@ -782,7 +745,7 @@ func (d *DeclList) Visit(v DeclVisitor) { v.DoDeclList(d); }
 // A Package node represents the root node of an AST.
 type Package struct {
        Doc Comments;  // associated documentation; or nil
-       Package Position;  // position of "package" keyword
+       token.Position;  // position of "package" keyword
        Name *Ident;  // package name
        Decls []Decl;  // top-level declarations
        Comments []*Comment;  // list of unassociated comments