]> Cypherpunks repositories - gostls13.git/commitdiff
- expanded parsing heuristics to deal with new(T, ...)
authorRobert Griesemer <gri@golang.org>
Fri, 24 Oct 2008 00:56:54 +0000 (17:56 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 24 Oct 2008 00:56:54 +0000 (17:56 -0700)
- fixed an issue with select
- added all bugs and fixedbugs tests that are syntactically correct to the test suite
- minor cosmetic changes

R=r
OCL=17759
CL=17759

usr/gri/pretty/ast.go
usr/gri/pretty/parser.go
usr/gri/pretty/printer.go
usr/gri/pretty/scanner.go
usr/gri/pretty/test.sh

index 5673088e3b3592bad4ec951d90b12adce21ed214..3179a4811c1d1b209213b56c13377d0172c28128 100644 (file)
@@ -8,7 +8,7 @@ import Scanner "scanner"
 
 
 type (
-       Node interface {};
+       Any interface {};
        Type struct;
        Expr struct;
        Stat struct;
@@ -23,7 +23,7 @@ type (
 // Thus, empty lists can be represented by nil.
 
 export type List struct {
-       a *[] Node;
+       a *[] Any;
 }
 
 
@@ -33,22 +33,22 @@ func (p *List) len() int {
 }
 
 
-func (p *List) at(i int) Node {
+func (p *List) at(i int) Any {
        return p.a[i];
 }
 
 
-func (p *List) set(i int, x Node) {
+func (p *List) set(i int, x Any) {
        p.a[i] = x;
 }
 
 
-func (p *List) Add (x Node) {
+func (p *List) Add (x Any) {
        a := p.a;
        n := len(a);
 
        if n == cap(a) {
-               b := new([] Node, 2*n);
+               b := new([] Any, 2*n);
                for i := 0; i < n; i++ {
                        b[i] = a[i];
                }
@@ -63,16 +63,24 @@ func (p *List) Add (x Node) {
 
 export func NewList() *List {
        p := new(List);
-       p.a = new([] Node, 10) [0 : 0];
+       p.a = new([] Any, 10) [0 : 0];
        return p;
 }
 
 
+// ----------------------------------------------------------------------------
+// All nodes have a source position and and token.
+
+export type Node struct {
+       pos, tok int;
+}
+
+
 // ----------------------------------------------------------------------------
 // Expressions
 
 export type Expr struct {
-       pos, tok int;
+       Node;
        x, y *Expr;  // binary (x, y) and unary (y) expressions
        // TODO find a more space efficient way to hold these
        s string;  // identifiers and literals
@@ -124,7 +132,7 @@ export const /* channel mode */ (
 
 
 export type Type struct {
-       pos, tok int;
+       Node;
        expr *Expr;  // type name, array length
        mode int;  // channel mode
        key *Type;  // receiver type, map key
@@ -171,7 +179,7 @@ export var BadType = NewType(0, Scanner.ILLEGAL);
 // Statements
 
 export type Stat struct {
-       pos, tok int;
+       Node;
        init, post *Stat;
        expr *Expr;
        block *List;
@@ -193,7 +201,7 @@ export var BadStat = NewStat(0, Scanner.ILLEGAL);
 // Declarations
 
 export type Decl struct {
-       pos, tok int;
+       Node;
        exported bool;
        ident *Expr;  // nil for ()-style declarations
        typ *Type;
index e74416663aeef1d504f317ce10f4282b46146b77..b5648d42066ee64c8150139117c88f4ba3e5c374 100644 (file)
@@ -93,7 +93,7 @@ func (P *Parser) Open(verbose, sixg bool, scanner *Scanner.Scanner, tokchan *<-c
        P.comments = AST.NewList();
        
        P.Next();
-       P.expr_lev = 1;
+       P.expr_lev = 0;
        P.scope_lev = 0;
 }
 
@@ -631,15 +631,39 @@ func (P *Parser) ParseFunctionLit() *AST.Expr {
        x := AST.NewLit(P.pos, Scanner.FUNC, "");
        P.Expect(Scanner.FUNC);
        x.t = P.ParseFunctionType();
+       P.expr_lev++;
        P.scope_lev++;
        x.block = P.ParseBlock();
        P.scope_lev--;
+       P.expr_lev--;
        
        P.Ecart();
        return x;
 }
 
 
+/*
+func (P *Parser) ParseNewCall() *AST.Expr {
+       P.Trace("NewCall");
+       
+       x := AST.NewExpr(P.pos, Scanner.NEW, nil, nil);
+       P.Next();
+       P.Expect(Scanner.LPAREN);
+       P.expr_lev++;
+       x.t = P.ParseType();
+       if P.tok == Scanner.COMMA {
+               P.Next();
+               x.y = P.ParseExpressionList();
+       }
+       P.expr_lev--;
+       P.Expect(Scanner.RPAREN);
+       
+       P.Ecart();
+       return x;
+}
+*/
+
+
 func (P *Parser) ParseOperand() *AST.Expr {
        P.Trace("Operand");
 
@@ -668,7 +692,12 @@ func (P *Parser) ParseOperand() *AST.Expr {
 
        case Scanner.FUNC:
                x = P.ParseFunctionLit();
-               
+
+       /*
+       case Scanner.NEW:
+               x = P.ParseNewCall();
+       */
+
        default:
                t := P.TryType();
                if t != nil {
@@ -709,7 +738,9 @@ func (P *Parser) ParseIndex(x *AST.Expr) *AST.Expr {
        
        pos := P.pos;
        P.Expect(Scanner.LBRACK);
+       P.expr_lev++;
        i := P.ParseExpression(0);
+       P.expr_lev--;
        P.Expect(Scanner.RBRACK);
        
        P.Ecart();
@@ -719,25 +750,35 @@ func (P *Parser) ParseIndex(x *AST.Expr) *AST.Expr {
 
 func (P *Parser) ParseBinaryExpr(prec1 int) *AST.Expr
 
-func (P *Parser) ParseCall(x *AST.Expr) *AST.Expr {
+func (P *Parser) ParseCall(x0 *AST.Expr) *AST.Expr {
        P.Trace("Call");
 
-       x = P.NewExpr(P.pos, Scanner.LPAREN, x, nil);
+       x := P.NewExpr(P.pos, Scanner.LPAREN, x0, nil);
        P.Expect(Scanner.LPAREN);
        if P.tok != Scanner.RPAREN {
-               // the very first argument may be a type if the function called is new()
-               // call ParseBinaryExpr() which allows type expressions (instead of ParseExpression)
-               y := P.ParseBinaryExpr(1);
-               if P.tok == Scanner.COMMA {
-                       pos := P.pos;
-                       P.Next();
-                       z := P.ParseExpressionList();
-                       // create list manually because NewExpr checks for type expressions
-                       z = P.NewExpr(pos, Scanner.COMMA, nil, z);
-                       z.x = y;
-                       y = z;
+               P.expr_lev++;
+               var t *AST.Type;
+               if x0.tok == Scanner.IDENT && x0.s == "new" {
+                       // heuristic: assume it's a new(T, ...) call, try to parse a type
+                       t = P.TryType();
+               }
+               if t != nil {
+                       // we found a type
+                       x.y = AST.NewTypeExpr(t);
+                       if P.tok == Scanner.COMMA {
+                               pos := P.pos;
+                               P.Next();
+                               y := P.ParseExpressionList();
+                               // create list manually because NewExpr checks for type expressions
+                               z := AST.NewExpr(pos, Scanner.COMMA, nil, y);
+                               z.x = x.y;
+                               x.y = z;
+                       }
+               } else {
+                       // normal argument list
+                       x.y = P.ParseExpressionList();
                }
-               x.y = y;
+               P.expr_lev--;
        }
        P.Expect(Scanner.RPAREN);
        
@@ -817,10 +858,10 @@ func (P *Parser) ParsePrimaryExpr() *AST.Expr {
                case Scanner.LPAREN: x = P.ParseCall(x);
                case Scanner.LBRACE:
                        // assume a composite literal only if x could be a type
-                       // and if we are not inside control clause (expr_lev > 0)
+                       // and if we are not inside control clause (expr_lev >= 0)
                        // (composites inside control clauses must be parenthesized)
                        var t *AST.Type;
-                       if P.expr_lev > 0 {
+                       if P.expr_lev >= 0 {
                                t = ExprType(x);
                        }
                        if t != nil {
@@ -1002,7 +1043,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
        P.Expect(keyword);
        if P.tok != Scanner.LBRACE {
                prev_lev := P.expr_lev;
-               P.expr_lev = 0;
+               P.expr_lev = -1;
                if P.tok != Scanner.SEMICOLON {
                        s.init = P.ParseSimpleStat();
                }
@@ -1129,12 +1170,15 @@ func (P *Parser) ParseCommCase() *AST.Stat {
        s := AST.NewStat(P.pos, Scanner.CASE);
        if P.tok == Scanner.CASE {
                P.Next();
-               P.ParseExpression(1);
+               x := P.ParseExpression(1);
                if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
+                       pos, tok := P.pos, P.tok;
                        P.Next();
                        P.Expect(Scanner.ARROW);
-                       P.ParseExpression(1);
+                       y := P.ParseExpression(1);
+                       x = AST.NewExpr(pos, tok, x, y);
                }
+               s.expr = x;
        } else {
                P.Expect(Scanner.DEFAULT);
        }
index 60f1c63bbcf624025da85a4b381fb2d36189e8d2..0776790f3eeeb64118aeb3091f48a31943d03f4a 100644 (file)
@@ -238,9 +238,9 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
        case Scanner.COMMA:
                // list
                // (don't use binary expression printing because of different spacing)
-               P.Expr1(x.x, Scanner.LowestPrec);
+               P.Expr(x.x);
                P.String(x.pos, ", ");
-               P.Expr1(x.y, Scanner.LowestPrec);
+               P.Expr(x.y);
 
        case Scanner.PERIOD:
                // selector or type guard
@@ -265,14 +265,14 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
                // call
                P.Expr1(x.x, Scanner.HighestPrec);
                P.String(x.pos, "(");
-               P.Expr1(x.y, Scanner.LowestPrec);
+               P.Expr(x.y);
                P.String(0, ")");
 
        case Scanner.LBRACE:
                // composite
                P.Type(x.t);
                P.String(x.pos, "{");
-               P.Expr1(x.y, Scanner.LowestPrec);
+               P.Expr(x.y);
                P.String(0, "}");
                
        default:
index 634094e0b4e6ca33c48618f3e76fe2dab44ebc0c..4b331b5620d08fead96c5965d4b0711871179b0e 100644 (file)
@@ -285,6 +285,7 @@ export type Scanner struct {
        pos int;  // current reading position
        ch int;  // one char look-ahead
        chpos int;  // position of ch
+       linepos int;  // position of beginning of line
 
        // testmode
        testmode bool;
@@ -298,8 +299,8 @@ func (S *Scanner) Next() {
        if S.pos < len(S.src) {
                // assume ascii
                r, w := int(S.src[S.pos]), 1;
-               if r > 0x80 {
-                       // wasn't ascii
+               if r >= 0x80 {
+                       // not ascii
                        r, w = sys.stringtorune(S.src, S.pos);
                }
                S.ch = r;
@@ -430,17 +431,16 @@ func (S *Scanner) LineCol(pos int) (line, col int) {
 
 
 func (S *Scanner) ErrorMsg(pos int, msg string) {
-       print(S.filename);
+       print(S.filename, ":");
        if pos >= 0 {
                // print position
                line, col := S.LineCol(pos);
+               print(line, ":");
                if S.columns {
-                       print(":", line, ":", col);
-               } else {
-                       print(":", line);
+                       print(col, ":");
                }
        }
-       print(": ", msg, "\n");
+       print(" ", msg, "\n");
        
        S.nerrors++;
        S.errpos = pos;
@@ -486,14 +486,15 @@ func (S *Scanner) Open(filename, src string, columns, testmode bool) {
        S.filename = filename;
        S.nerrors = 0;
        S.errpos = 0;
+       S.columns = columns;
        
        S.src = src;
        S.pos = 0;
-       S.columns = columns;
+       S.linepos = 0;
+
        S.testmode = testmode;
-       
-       S.ExpectNoErrors();  // after setting S.src
-       S.Next();  // after S.ExpectNoErrrors()
+       S.ExpectNoErrors();  // S.src must be set
+       S.Next();  // S.ExpectNoErrrors() must be called before
 }
 
 
@@ -535,10 +536,10 @@ func (S *Scanner) ScanComment() string {
        
        if S.ch == '/' {
                // comment
+               S.Next();
                for S.ch >= 0 {
                        S.Next();
                        if S.ch == '\n' {
-                               S.Next();
                                goto exit;
                        }
                }
@@ -550,7 +551,6 @@ func (S *Scanner) ScanComment() string {
                        ch := S.ch;
                        S.Next();
                        if ch == '*' && S.ch == '/' {
-                               S.Next();
                                goto exit;
                        }
                }
@@ -559,7 +559,9 @@ func (S *Scanner) ScanComment() string {
        S.Error(pos, "comment not terminated");
 
 exit:
+       S.Next();
        comment := S.src[pos : S.chpos];
+
        if S.testmode {
                // interpret ERROR and SYNC comments
                oldpos := -1;
index c17f59660d9690d7ef33dcfea03f4867bf13c98d..ad5998a2e25861adaad30777cf8eb5c17dcbfd79 100755 (executable)
@@ -21,8 +21,8 @@ count() {
 apply1() {
        #echo $1 $2
        case `basename $F` in
-       selftest.go | func3.go ) ;;  # skip - these are test cases for syntax errors
-       newfn.go ) ;;  # skip these - cannot parse w/o type information
+       selftest.go | func3.go | bug014.go | bug029.go | bug032.go | bug050.go | \
+       bug068.go | bug088.go | bug083.go | bug106.go ) ;;  # skip - files contain syntax errors
        * ) $1 $2; count ;;
        esac
 }
@@ -42,6 +42,8 @@ apply() {
        for F in \
                $GOROOT/usr/gri/pretty/*.go \
                $GOROOT/test/*.go \
+               $GOROOT/test/bugs/*.go \
+               $GOROOT/test/fixedbugs/*.go \
                $GOROOT/src/pkg/*.go \
                $GOROOT/src/lib/*.go \
                $GOROOT/src/lib/*/*.go \