]> Cypherpunks repositories - gostls13.git/commitdiff
- fixed several parser issues
authorRobert Griesemer <gri@golang.org>
Fri, 25 Jul 2008 00:00:58 +0000 (17:00 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 25 Jul 2008 00:00:58 +0000 (17:00 -0700)
R=r
OCL=13441
CL=13441

usr/gri/gosrc/globals.go
usr/gri/gosrc/object.go
usr/gri/gosrc/parser.go

index 2a936647ee8c796ee5220ba0977594e049b5b2cf..9665cbdaf51edd8edc44f031f1ec4340bfe6df17 100644 (file)
@@ -53,10 +53,10 @@ type Package struct {
 
 type Elem struct {
        next *Elem;
+       val int;
        str string;
        obj *Object;
        typ *Type;
-       pkg *Package;
 }
 
 
@@ -190,6 +190,11 @@ func (L *List) TypAt(i int) *Type {
 }
 
 
+func (L *List) AddInt(val int) {
+       L.Add().val = val;
+}
+
+
 func (L *List) AddStr(str string) {
        L.Add().str = str;
 }
index fba2b3cf2266e1fb9d08f1a8f347627db8689219..bef5fbcee53d6c6220da12746f68581a7a5041bb 100755 (executable)
@@ -7,10 +7,10 @@ package Object
 import Globals "globals"
 
 
-export BAD, CONST, TYPE, VAR, FUNC, PACKAGE, PTYPE
+export BAD, CONST, TYPE, VAR, FUNC, PACKAGE, LABEL, PTYPE
 const /* kind */ (
        BAD = iota;  // error handling
-       CONST; TYPE; VAR; FUNC; PACKAGE;
+       CONST; TYPE; VAR; FUNC; PACKAGE; LABEL;
        PTYPE;  // primary type (import/export only)
 )
 
index 302db224201f61f377527b07c13e874edcdf7bd3..05fc74239e7fc43e51f8a6adf37aa134298f48e8 100644 (file)
@@ -208,12 +208,15 @@ func (P *Parser) ParseIdentList() {
 }
 
 
-func (P *Parser) ParseQualifiedIdent() *Globals.Object {
+func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
        P.Trace("QualifiedIdent");
 
+       if pos < 0 {
+               pos = P.pos;
+               ident = P.ParseIdent();
+       }
+       
        if EnableSemanticTests {
-               pos := P.pos;
-               ident := P.ParseIdent();
                obj := P.Lookup(ident);
                if obj == nil {
                        P.Error(pos, `"` + ident + `" is not declared`);
@@ -229,7 +232,6 @@ func (P *Parser) ParseQualifiedIdent() *Globals.Object {
                return obj;
                
        } else {
-               P.ParseIdent();
                if P.tok == Scanner.PERIOD {
                        P.Next();
                        P.ParseIdent();
@@ -261,7 +263,7 @@ func (P *Parser) ParseTypeName() *Globals.Type {
        P.Trace("TypeName");
        
        if EnableSemanticTests {
-               obj := P.ParseQualifiedIdent();
+               obj := P.ParseQualifiedIdent(-1, "");
                typ := obj.typ;
                if obj.kind != Object.TYPE {
                        P.Error(obj.pos, `"` + obj.ident + `" is not a type`);
@@ -270,7 +272,7 @@ func (P *Parser) ParseTypeName() *Globals.Type {
                P.Ecart();
                return typ;
        } else {
-               P.ParseQualifiedIdent();
+               P.ParseQualifiedIdent(-1, "");
                P.Ecart();
                return Universe.bad_t;
        }
@@ -510,11 +512,11 @@ func (P *Parser) ParseInterfaceType() *Globals.Type {
        P.OpenScope();
        typ := Globals.NewType(Type.INTERFACE);
        typ.scope = P.top_scope;
-       for P.tok != Scanner.RBRACE {
+       for P.tok == Scanner.IDENT {
                P.ParseMethodDecl();
        }
        P.CloseScope();
-       P.Next();
+       P.Expect(Scanner.RBRACE);
        
        P.Ecart();
        return typ;
@@ -708,6 +710,15 @@ func (P *Parser) ParseExpressionPairList() {
 }
 
 
+func (P *Parser) ParseBuiltinCall() {
+       P.Trace("BuiltinCall");
+       
+       P.ParseExpressionList();  // TODO should be optional
+       
+       P.Ecart();
+}
+
+
 func (P *Parser) ParseCompositeLit(typ *Globals.Type) {
        P.Trace("CompositeLit");
        
@@ -749,18 +760,36 @@ func (P *Parser) ParseCompositeLit(typ *Globals.Type) {
 }
 
 
-func (P *Parser) ParseOperand() {
+func (P *Parser) ParseOperand(pos int, ident string) {
        P.Trace("Operand");
+
+       if pos < 0 && P.tok == Scanner.IDENT {
+               // no look-ahead yet
+               pos = P.pos;
+               ident = P.val;
+               P.Next();
+       }
        
-       switch P.tok {
-       case Scanner.IDENT:
-               P.ParseQualifiedIdent();
+       if pos >= 0 {
+               // TODO set these up properly in the Universe
+               if ident == "panic" || ident == "print" {
+                       P.ParseBuiltinCall();
+                       goto exit;
+               }
+       
+               P.ParseQualifiedIdent(pos, ident);
                // TODO enable code below
                /*
                if obj.kind == Object.TYPE {
                        P.ParseCompositeLit(obj.typ);
                }
                */
+               goto exit;
+       }
+       
+       switch P.tok {
+       case Scanner.IDENT:
+               panic "UNREACHABLE";
        case Scanner.LPAREN:
                P.Next();
                P.ParseExpression();
@@ -786,6 +815,7 @@ func (P *Parser) ParseOperand() {
                }
        }
        
+exit:
        P.Ecart();
 }
 
@@ -821,8 +851,8 @@ func (P *Parser) ParseIndexOrSlice() {
 }
 
 
-func (P *Parser) ParseInvocation() {
-       P.Trace("Invocation");
+func (P *Parser) ParseCall() {
+       P.Trace("Call");
        
        P.Expect(Scanner.LPAREN);
        if P.tok != Scanner.RPAREN {
@@ -834,10 +864,10 @@ func (P *Parser) ParseInvocation() {
 }
 
 
-func (P *Parser) ParsePrimaryExpr() {
+func (P *Parser) ParsePrimaryExpr(pos int, ident string) AST.Expr {
        P.Trace("PrimaryExpr");
        
-       P.ParseOperand();
+       P.ParseOperand(pos, ident);
        for {
                switch P.tok {
                case Scanner.PERIOD:
@@ -845,24 +875,25 @@ func (P *Parser) ParsePrimaryExpr() {
                case Scanner.LBRACK:
                        P.ParseIndexOrSlice();
                case Scanner.LPAREN:
-                       P.ParseInvocation();
+                       P.ParseCall();
                default:
                        P.Ecart();
-                       return;
+                       return nil;
                }
        }
        
        P.Ecart();
+       return nil;
 }
 
 
 func (P *Parser) ParsePrimaryExprList() {
        P.Trace("PrimaryExprList");
        
-       P.ParsePrimaryExpr();
+       P.ParsePrimaryExpr(-1, "");
        for P.tok == Scanner.COMMA {
                P.Next();
-               P.ParsePrimaryExpr();
+               P.ParsePrimaryExpr(-1, "");
        }
        
        P.Ecart();
@@ -885,7 +916,7 @@ func (P *Parser) ParseUnaryExpr() AST.Expr {
                P.Ecart();
                return nil;  // TODO fix this
        }
-       P.ParsePrimaryExpr();
+       P.ParsePrimaryExpr(-1, "");
        
        P.Ecart();
        return nil;  // TODO fix this
@@ -912,10 +943,15 @@ func Precedence(tok int) int {
 }
 
 
-func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
+func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) AST.Expr {
        P.Trace("BinaryExpr");
        
-       x := P.ParseUnaryExpr();
+       var x AST.Expr;
+       if pos >= 0 {
+               x = P.ParsePrimaryExpr(pos, ident);
+       } else {
+               x = P.ParseUnaryExpr();
+       }
        for prec := Precedence(P.tok); prec >= prec1; prec-- {
                for Precedence(P.tok) == prec {
                        e := new(AST.BinaryExpr);
@@ -923,7 +959,7 @@ func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
                        e.op = P.tok;  // TODO should we use tokens or separate operator constants?
                        e.x = x;
                        P.Next();
-                       e.y = P.ParseBinaryExpr(prec + 1);
+                       e.y = P.ParseBinaryExpr(-1, "", prec + 1);
                        x = e;
                }
        }
@@ -932,11 +968,13 @@ func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
 }
 
 
-func (P *Parser) ParseExpression() {
-       P.Trace("Expression");
+// Expressions where the first token may be an
+// identifier that has already been consumed.
+func (P *Parser) ParseIdentExpression(pos int, ident string) {
+       P.Trace("IdentExpression");
        indent := P.indent;
        
-       P.ParseBinaryExpr(1);
+       P.ParseBinaryExpr(pos, ident, 1);
        
        if indent != P.indent {
                panic "imbalanced tracing code (Expression)";
@@ -945,32 +983,102 @@ func (P *Parser) ParseExpression() {
 }
 
 
+func (P *Parser) ParseExpression() {
+       P.Trace("Expression");  
+       P.ParseIdentExpression(-1, "");
+       P.Ecart();
+}
+
+
 // ----------------------------------------------------------------------------
 // Statements
 
-func (P *Parser) ParseBuiltinStat() {
-       P.Trace("BuiltinStat");
-       P.Expect(Scanner.IDENT);
-       P.ParseExpressionList();  // TODO should be optional
+func (P *Parser) ParseIdentOrExpr(nidents int) int {
+       P.Trace("IdentOrExpr");
+       if nidents >= 0 && P.tok == Scanner.IDENT {
+               pos := P.pos;
+               ident := P.val;
+               P.Next();
+               switch P.tok {
+               case Scanner.COMMA,
+                       Scanner.COLON,
+                       Scanner.DEFINE,
+                       Scanner.ASSIGN,
+                       Scanner.ADD_ASSIGN,
+                       Scanner.SUB_ASSIGN,
+                       Scanner.MUL_ASSIGN,
+                       Scanner.QUO_ASSIGN,
+                       Scanner.REM_ASSIGN,
+                       Scanner.AND_ASSIGN,
+                       Scanner.OR_ASSIGN,
+                       Scanner.XOR_ASSIGN,
+                       Scanner.SHL_ASSIGN,
+                       Scanner.SHR_ASSIGN:
+                       // identifier is not part of a more complicated expression
+                       nidents++;
+                       
+               default:
+                       // assume identifier is part of a more complicated expression
+                       P.ParseIdentExpression(pos, ident);
+                       nidents = -nidents - 1;
+               }
+       } else {
+               P.ParseExpression();
+               if nidents > 0 {
+                       nidents = -nidents;
+               }
+               nidents--;
+       }
        P.Ecart();
+       return nidents;
+}
+
+
+// temporary - will go away eventually
+func abs(x int) int {
+       if x < 0 {
+               x = -x;
+       }
+       return x;
 }
 
 
 func (P *Parser) ParseSimpleStat() {
        P.Trace("SimpleStat");
-       P.ParseExpression();
-       if P.tok == Scanner.COLON {
-               P.Next();
-               P.Ecart();
-               return;
-       }
-       if P.tok == Scanner.COMMA {
+       
+       // If we see an identifier, we don't know if it's part of a
+       // label declaration, (multiple) variable declaration, assignment,
+       // or simply an expression, without looking ahead.
+       // Strategy: We parse an expression list, but simultaneously, as
+       // long as possible, maintain a list of identifiers which is converted
+       // into an expression list only if neccessary.
+       // TODO: maintain the lists
+
+       nidents := P.ParseIdentOrExpr(0);
+       for P.tok == Scanner.COMMA {
                P.Next();
-               P.ParsePrimaryExprList();
+               nidents = P.ParseIdentOrExpr(nidents);
        }
+       
        switch P.tok {
+       case Scanner.COLON:
+               // label declaration
+               P.Next();
+               if nidents != 1 {
+                       // TODO provide exact error position
+                       P.Error(P.pos, "illegal label declaration");
+               }
+               
+       case Scanner.DEFINE:
+               // variable declaration
+               P.Next();
+               P.ParseExpressionList();
+               if nidents < 0 {
+                       // TODO provide exact error position
+                       P.Error(P.pos, "illegal identifier list for declaration");
+               }
+               
        case Scanner.ASSIGN: fallthrough;
-       case Scanner.DEFINE: fallthrough;
        case Scanner.ADD_ASSIGN: fallthrough;
        case Scanner.SUB_ASSIGN: fallthrough;
        case Scanner.MUL_ASSIGN: fallthrough;
@@ -983,11 +1091,19 @@ func (P *Parser) ParseSimpleStat() {
        case Scanner.SHR_ASSIGN:
                P.Next();
                P.ParseExpressionList();
-       case Scanner.INC:
-               P.Next();
-       case Scanner.DEC:
+       case Scanner.INC, Scanner.DEC:
                P.Next();
+               if abs(nidents) != 1 {
+                       // TODO provide exact error position
+                       P.Error(P.pos, "too many expressions for '++' or '--'");
+               }
+       default:
+               if abs(nidents) != 1 {
+                       // TODO provide exact error position
+                       P.Error(P.pos, "too many expressions for expression statement");
+               }
        }
+       
        P.Ecart();
 }
 
@@ -1144,7 +1260,7 @@ func (P *Parser) ParseSwitchStat() {
                }
        }
        P.Expect(Scanner.LBRACE);
-       for P.tok != Scanner.RBRACE {
+       for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT {
                P.ParseCaseClause();
        }
        P.Expect(Scanner.RBRACE);
@@ -1214,7 +1330,7 @@ func (P *Parser) ParseSelectStat() bool {
        
        P.Expect(Scanner.SELECT);
        P.Expect(Scanner.LBRACE);
-       for P.tok != Scanner.RBRACE {
+       for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
                P.ParseCommClause();
        }
        P.Next();
@@ -1236,16 +1352,8 @@ func (P *Parser) TryStatement() bool {
        case Scanner.FUNC:
                // for now we do not allow local function declarations
                fallthrough;
-       case Scanner.SEND: fallthrough;
-       case Scanner.RECV:
-               P.ParseSimpleStat();  // send or receive
-       case Scanner.IDENT:
-               switch P.val {
-               case "print", "panic":
-                       P.ParseBuiltinStat();
-               default:
-                       P.ParseSimpleStat();
-               }
+       case Scanner.MUL, Scanner.SEND, Scanner.RECV, Scanner.IDENT:
+               P.ParseSimpleStat();
        case Scanner.GO:
                P.ParseGoStat();
        case Scanner.RETURN:
@@ -1300,7 +1408,7 @@ func (P *Parser) ParseImportDecl() {
        P.Expect(Scanner.IMPORT);
        if P.tok == Scanner.LPAREN {
                P.Next();
-               for P.tok != Scanner.RPAREN {
+               for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
                        P.ParseImportSpec();
                        P.Optional(Scanner.SEMICOLON);  // TODO this seems wrong
                }
@@ -1338,7 +1446,7 @@ func (P *Parser) ParseConstDecl() {
        P.Expect(Scanner.CONST);
        if P.tok == Scanner.LPAREN {
                P.Next();
-               for P.tok != Scanner.RPAREN {
+               for P.tok == Scanner.IDENT {
                        P.ParseConstSpec();
                        if P.tok != Scanner.RPAREN {
                                P.Expect(Scanner.SEMICOLON);
@@ -1390,7 +1498,7 @@ func (P *Parser) ParseTypeDecl() {
        P.Expect(Scanner.TYPE);
        if P.tok == Scanner.LPAREN {
                P.Next();
-               for P.tok != Scanner.RPAREN {
+               for P.tok == Scanner.IDENT {
                        P.ParseTypeSpec();
                        if P.tok != Scanner.RPAREN {
                                P.Expect(Scanner.SEMICOLON);
@@ -1433,7 +1541,7 @@ func (P *Parser) ParseVarDecl() {
        P.Expect(Scanner.VAR);
        if P.tok == Scanner.LPAREN {
                P.Next();
-               for P.tok != Scanner.RPAREN {
+               for P.tok == Scanner.IDENT {
                        P.ParseVarSpec();
                        if P.tok != Scanner.RPAREN {
                                P.Expect(Scanner.SEMICOLON);
@@ -1467,20 +1575,20 @@ func (P *Parser) ParseFuncDecl() {
 func (P *Parser) ParseExportDecl() {
        P.Trace("ExportDecl");
        
+       // TODO this needs to be clarified - the current syntax is
+       // "everything goes" - sigh...
        P.Expect(Scanner.EXPORT);
+       has_paren := false;
        if P.tok == Scanner.LPAREN {
                P.Next();
-               for P.tok != Scanner.RPAREN {
-                       P.exports.AddStr(P.ParseIdent());
-                       P.Optional(Scanner.COMMA);  // TODO this seems wrong
-               }
-               P.Next();
-       } else {
+               has_paren = true;
+       }
+       for P.tok == Scanner.IDENT {
                P.exports.AddStr(P.ParseIdent());
-               for P.tok == Scanner.COMMA {
-                       P.Next();
-                       P.exports.AddStr(P.ParseIdent());
-               }
+               P.Optional(Scanner.COMMA);  // TODO this seems wrong
+       }
+       if has_paren {
+               P.Expect(Scanner.RPAREN)
        }
        
        P.Ecart();