]> Cypherpunks repositories - gostls13.git/commitdiff
today's snapshot: steps towards using interfaces for statements in ast
authorRobert Griesemer <gri@golang.org>
Thu, 5 Feb 2009 02:28:41 +0000 (18:28 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 5 Feb 2009 02:28:41 +0000 (18:28 -0800)
R=r
OCL=24380
CL=24380

usr/gri/pretty/ast.go
usr/gri/pretty/parser.go
usr/gri/pretty/printer.go

index cfd345d5a97116ffc3c542eb92570feffd3a03aa..c0b3c86278c5a1e2414f35683316a2b0a1b63a14 100644 (file)
@@ -18,7 +18,7 @@ type (
 
        Block struct;
        Expr interface;
-       Stat struct;
+       StatImpl struct;
        Decl struct;
 )
 
@@ -350,11 +350,11 @@ func NewBlock(pos, tok int) *Block {
 // Expressions
 
 type (
-       Visitor interface;
+       ExprVisitor interface;
 
        Expr interface {
                Pos() int;
-               Visit(v Visitor);
+               Visit(v ExprVisitor);
        };
 
        BadExpr struct {
@@ -421,7 +421,7 @@ type (
 )
 
 
-type Visitor interface {
+type ExprVisitor interface {
        DoBadExpr(x *BadExpr);
        DoIdent(x *Ident);
        DoBinaryExpr(x *BinaryExpr);
@@ -451,18 +451,18 @@ func (x *Index) Pos() int { return x.Pos_; }
 func (x *Call) Pos() int { return x.Pos_; }
 
 
-func (x *BadExpr) Visit(v Visitor) { v.DoBadExpr(x); }
-func (x *Ident) Visit(v Visitor) { v.DoIdent(x); }
-func (x *BinaryExpr) Visit(v Visitor) { v.DoBinaryExpr(x); }
-func (x *UnaryExpr) Visit(v Visitor) { v.DoUnaryExpr(x); }
-func (x *BasicLit) Visit(v Visitor) { v.DoBasicLit(x); }
-func (x *FunctionLit) Visit(v Visitor) { v.DoFunctionLit(x); }
-func (x *CompositeLit) Visit(v Visitor) { v.DoCompositeLit(x); }
-func (x *TypeLit) Visit(v Visitor) { v.DoTypeLit(x); }
-func (x *Selector) Visit(v Visitor) { v.DoSelector(x); }
-func (x *TypeGuard) Visit(v Visitor) { v.DoTypeGuard(x); }
-func (x *Index) Visit(v Visitor) { v.DoIndex(x); }
-func (x *Call) Visit(v Visitor) { v.DoCall(x); }
+func (x *BadExpr) Visit(v ExprVisitor) { v.DoBadExpr(x); }
+func (x *Ident) Visit(v ExprVisitor) { v.DoIdent(x); }
+func (x *BinaryExpr) Visit(v ExprVisitor) { v.DoBinaryExpr(x); }
+func (x *UnaryExpr) Visit(v ExprVisitor) { v.DoUnaryExpr(x); }
+func (x *BasicLit) Visit(v ExprVisitor) { v.DoBasicLit(x); }
+func (x *FunctionLit) Visit(v ExprVisitor) { v.DoFunctionLit(x); }
+func (x *CompositeLit) Visit(v ExprVisitor) { v.DoCompositeLit(x); }
+func (x *TypeLit) Visit(v ExprVisitor) { v.DoTypeLit(x); }
+func (x *Selector) Visit(v ExprVisitor) { v.DoSelector(x); }
+func (x *TypeGuard) Visit(v ExprVisitor) { v.DoTypeGuard(x); }
+func (x *Index) Visit(v ExprVisitor) { v.DoIndex(x); }
+func (x *Call) Visit(v ExprVisitor) { v.DoCall(x); }
 
 
 
@@ -518,23 +518,112 @@ func (t *Type) Nfields() int {
 // ----------------------------------------------------------------------------
 // Statements
 
-type Stat struct {
+type (
+       StatVisitor interface;
+
+       Stat interface {
+               Visit(v StatVisitor);
+       };
+       
+       BadStat struct {
+               Pos int;
+       };
+
+       LabelDecl struct {
+               Pos int;  // position of ":"
+               Label *Ident;
+       };
+
+       DeclarationStat struct {
+               Decl *Decl;
+       };
+
+       ExpressionStat struct {
+               Pos int;  // position of Tok
+               Tok int;  // INC, DEC, RETURN, GO, DEFER
+               Expr Expr;
+       };
+       
+       IfStat struct {
+               Pos int;  // position of "if"
+               Init Stat;
+               Cond Expr;
+               Body *Block;
+               Else Stat;
+       };
+       
+       ForStat struct {
+               Pos int;  // position of "for"
+               Init Stat;
+               Cond Expr;
+               Post Stat;
+               Body *Block;
+       };
+       
+       SwitchStat struct {
+               Pos int;  // position of "switch"
+               Init Stat;
+               Tag Expr;
+               Body *Block;
+       };
+       
+       SelectStat struct {
+               Pos int;  // position of "select"
+               Body *Block;
+       };
+       
+       ControlFlowStat struct {
+               Pos int;  // position of Tok
+               Tok int;  // BREAK, CONTINUE, GOTO, FALLTHROUGH
+               Label *Ident;  // if any, or nil
+       };
+)
+
+
+type StatVisitor interface {
+       DoBadStat(s *BadStat);
+       DoLabelDecl(s *LabelDecl);
+       DoDeclarationStat(s *DeclarationStat);
+       DoExpressionStat(s *ExpressionStat);
+       DoIfStat(s *IfStat);
+       DoForStat(s *ForStat);
+       DoSwitchStat(s *SwitchStat);
+       DoSelectStat(s *SelectStat);
+       DoControlFlowStat(s *ControlFlowStat);
+}
+
+
+func (s *BadStat) Visit(v StatVisitor) { v.DoBadStat(s); }
+func (s *LabelDecl) Visit(v StatVisitor) { v.DoLabelDecl(s); }
+func (s *DeclarationStat) Visit(v StatVisitor) { v.DoDeclarationStat(s); }
+func (s *ExpressionStat) Visit(v StatVisitor) { v.DoExpressionStat(s); }
+func (s *IfStat) Visit(v StatVisitor) { v.DoIfStat(s); }
+func (s *ForStat) Visit(v StatVisitor) { v.DoForStat(s); }
+func (s *SwitchStat) Visit(v StatVisitor) { v.DoSwitchStat(s); }
+func (s *SelectStat) Visit(v StatVisitor) { v.DoSelectStat(s); }
+func (s *ControlFlowStat) Visit(v StatVisitor) { v.DoControlFlowStat(s); }
+
+
+// ----------------------------------------------------------------------------
+// Old style statements
+
+type StatImpl struct {
        Node;
-       Init, Post *Stat;
+       Init, Post *StatImpl;
        Expr Expr;
        Body *Block;  // composite statement body
        Decl *Decl;  // declaration statement
 }
 
 
-func NewStat(pos, tok int) *Stat {
-       s := new(Stat);
+func NewStat(pos, tok int) *StatImpl {
+       s := new(StatImpl);
        s.Pos, s.Tok = pos, tok;
        return s;
 }
 
 
-var BadStat = NewStat(0, Scanner.ILLEGAL);
+var OldBadStat = NewStat(0, Scanner.ILLEGAL);
 
 
 // ----------------------------------------------------------------------------
index ae904a6511125c96546b885f92b040d2d125617a..f7e4ccd62c3de3c08353e7baaf4369719d703eee 100644 (file)
@@ -5,6 +5,7 @@
 package Parser
 
 import (
+       "flag";
        "fmt";
        "array";
        Scanner "scanner";
@@ -83,6 +84,13 @@ func (P *Parser) Ecart() {
 }
 
 
+func (P *Parser) VerifyIndent(indent uint) {
+       if indent != P.indent {
+               panic("imbalanced tracing code");
+       }
+}
+
+
 func (P *Parser) Next0() {
        if P.tokchan == nil {
                P.pos, P.tok, P.val = P.scanner.Scan();
@@ -247,7 +255,8 @@ func (P *Parser) NewBinary(pos, tok int, x, y AST.Expr) *AST.BinaryExpr {
 
 func (P *Parser) TryType() *AST.Type;
 func (P *Parser) ParseExpression(prec int) AST.Expr;
-func (P *Parser) ParseStatement() *AST.Stat;
+func (P *Parser) ParseStatement() AST.Stat;
+func (P *Parser) OldParseStatement() *AST.StatImpl;
 func (P *Parser) ParseDeclaration() *AST.Decl;
 
 
@@ -746,14 +755,24 @@ func (P *Parser) TryType() *AST.Type {
 // ----------------------------------------------------------------------------
 // Blocks
 
+
+var newstat = flag.Bool("newstat", false, "use new statement parsing - work in progress");
+
+
 func (P *Parser) ParseStatementList(list *array.Array) {
        if P.verbose {
                P.Trace("StatementList");
                defer P.Ecart();
+               defer P.VerifyIndent(P.indent);
        }
 
        for P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
-               s := P.ParseStatement();
+               var s interface{};
+               if *newstat {
+                       s = P.ParseStatement();
+               } else {
+                       s = P.OldParseStatement();
+               }
                if s != nil {
                        // not the empty statement
                        list.Push(s);
@@ -1133,31 +1152,93 @@ func (P *Parser) ParseExpression(prec int) AST.Expr {
        if P.verbose {
                P.Trace("Expression");
                defer P.Ecart();
+               defer P.VerifyIndent(P.indent);
        }
 
-       indent := P.indent;
        if prec < 0 {
                panic("precedence must be >= 0");
        }
-       x := P.NoType(P.ParseBinaryExpr(prec));
-       if indent != P.indent {
-               panic("imbalanced tracing code (Expression)");
-       }
 
-       return x;
+       return P.NoType(P.ParseBinaryExpr(prec));
 }
 
 
 // ----------------------------------------------------------------------------
 // Statements
 
-func (P *Parser) ParseSimpleStat(range_ok bool) *AST.Stat {
+func (P *Parser) ParseSimpleStat(range_ok bool) AST.Stat {
+       if P.verbose {
+               P.Trace("SimpleStat");
+               defer P.Ecart();
+       }
+
+       x := P.ParseExpressionList();
+
+       switch P.tok {
+       case Scanner.COLON:
+               // label declaration
+               pos := P.pos;
+               P.Next();  // consume ":"
+               if AST.ExprLen(x) == 1 {
+                       if label, is_ident := x.(*AST.Ident); is_ident {
+                               return &AST.LabelDecl{pos, label};
+                       }
+               }
+               P.Error(x.Pos(), "illegal label declaration");
+               return nil;
+               
+       case
+               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:
+               // declaration/assignment
+               pos, tok := P.pos, P.tok;
+               P.Next();
+               var y AST.Expr;
+               if range_ok && P.tok == Scanner.RANGE {
+                       range_pos := P.pos;
+                       P.Next();
+                       y = &AST.UnaryExpr{range_pos, Scanner.RANGE, P.ParseExpression(1)};
+                       if tok != Scanner.DEFINE && tok != Scanner.ASSIGN {
+                               P.Error(pos, "expected '=' or ':=', found '" + Scanner.TokenString(tok) + "'");
+                       }
+               } else {
+                       y = P.ParseExpressionList();
+                       if xl, yl := AST.ExprLen(x), AST.ExprLen(y); xl > 1 && yl > 1 && xl != yl {
+                               P.Error(x.Pos(), "arity of lhs doesn't match rhs");
+                       }
+               }
+               // TODO changed ILLEGAL -> NONE
+               return &AST.ExpressionStat{x.Pos(), Scanner.ILLEGAL, P.NewBinary(pos, tok, x, y)};
+               
+       default:
+               if AST.ExprLen(x) != 1 {
+                       P.Error(x.Pos(), "only one expression allowed");
+               }
+               
+               if P.tok == Scanner.INC || P.tok == Scanner.DEC {
+                       s := &AST.ExpressionStat{P.pos, P.tok, x};
+                       P.Next();  // consume "++" or "--"
+                       return s;
+               }
+               
+               // TODO changed ILLEGAL -> NONE
+               return &AST.ExpressionStat{x.Pos(), Scanner.ILLEGAL, x};
+       }
+
+       unreachable();
+       return nil;
+}
+
+
+func (P *Parser) OldParseSimpleStat(range_ok bool) *AST.StatImpl {
        if P.verbose {
                P.Trace("SimpleStat");
                defer P.Ecart();
        }
 
-       s := AST.BadStat;
+       s := AST.OldBadStat;
        x := P.ParseExpressionList();
 
        switch P.tok {
@@ -1180,7 +1261,7 @@ func (P *Parser) ParseSimpleStat(range_ok bool) *AST.Stat {
                pos, tok := P.pos, P.tok;
                P.Next();
                var y AST.Expr = &AST.BadExpr{pos};
-               if P.tok == Scanner.RANGE {
+               if range_ok && P.tok == Scanner.RANGE {
                        range_pos := P.pos;
                        P.Next();
                        y = P.ParseExpression(1);
@@ -1197,14 +1278,6 @@ func (P *Parser) ParseSimpleStat(range_ok bool) *AST.Stat {
                s = AST.NewStat(x.Pos(), Scanner.EXPRSTAT);
                s.Expr = P.NewBinary(pos, tok, x, y);
                
-       case Scanner.RANGE:
-               pos := P.pos;
-               P.Next();
-               y := P.ParseExpression(1);
-               y = &AST.UnaryExpr{pos, Scanner.RANGE, y};
-               s = AST.NewStat(x.Pos(), Scanner.EXPRSTAT);
-               s.Expr = P.NewBinary(pos, Scanner.DEFINE, x, y);
-
        default:
                var pos, tok int;
                if P.tok == Scanner.INC || P.tok == Scanner.DEC {
@@ -1225,7 +1298,19 @@ func (P *Parser) ParseSimpleStat(range_ok bool) *AST.Stat {
 }
 
 
-func (P *Parser) ParseInvocationStat(keyword int) *AST.Stat {
+func (P *Parser) ParseInvocationStat(keyword int) *AST.ExpressionStat {
+       if P.verbose {
+               P.Trace("InvocationStat");
+               defer P.Ecart();
+       }
+
+       pos := P.pos;
+       P.Expect(keyword);
+       return &AST.ExpressionStat{pos, keyword, P.ParseExpression(1)};
+}
+
+
+func (P *Parser) OldParseInvocationStat(keyword int) *AST.StatImpl {
        if P.verbose {
                P.Trace("InvocationStat");
                defer P.Ecart();
@@ -1239,7 +1324,24 @@ func (P *Parser) ParseInvocationStat(keyword int) *AST.Stat {
 }
 
 
-func (P *Parser) ParseReturnStat() *AST.Stat {
+func (P *Parser) ParseReturnStat() *AST.ExpressionStat {
+       if P.verbose {
+               P.Trace("ReturnStat");
+               defer P.Ecart();
+       }
+
+       pos := P.pos;
+       P.Expect(Scanner.RETURN);
+       var x AST.Expr;
+       if P.tok != Scanner.SEMICOLON && P.tok != Scanner.RBRACE {
+               x = P.ParseExpressionList();
+       }
+
+       return &AST.ExpressionStat{pos, Scanner.RETURN, x};
+}
+
+
+func (P *Parser) OldParseReturnStat() *AST.StatImpl {
        if P.verbose {
                P.Trace("ReturnStat");
                defer P.Ecart();
@@ -1255,7 +1357,7 @@ func (P *Parser) ParseReturnStat() *AST.Stat {
 }
 
 
-func (P *Parser) ParseControlFlowStat(tok int) *AST.Stat {
+func (P *Parser) ParseControlFlowStat(tok int) *AST.StatImpl {
        if P.verbose {
                P.Trace("ControlFlowStat");
                defer P.Ecart();
@@ -1271,7 +1373,47 @@ func (P *Parser) ParseControlFlowStat(tok int) *AST.Stat {
 }
 
 
-func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
+func (P *Parser) ParseControlClause(isForStat bool) (init AST.Stat, expr AST.Expr, post AST.Stat) {
+       if P.verbose {
+               P.Trace("ControlClause");
+               defer P.Ecart();
+       }
+
+       if P.tok != Scanner.LBRACE {
+               prev_lev := P.expr_lev;
+               P.expr_lev = -1;
+               if P.tok != Scanner.SEMICOLON {
+                       init = P.ParseSimpleStat(isForStat);
+                       // TODO check for range clause and exit if found
+               }
+               if P.tok == Scanner.SEMICOLON {
+                       P.Next();
+                       if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
+                               expr = P.ParseExpression(1);
+                       }
+                       if isForStat {
+                               P.Expect(Scanner.SEMICOLON);
+                               if P.tok != Scanner.LBRACE {
+                                       post = P.ParseSimpleStat(false);
+                               }
+                       }
+               } else {
+                       if init != nil {  // guard in case of errors
+                               if s, is_expr_stat := init.(*AST.ExpressionStat); is_expr_stat {
+                                       expr, init = s.Expr, nil;
+                               } else {
+                                       P.Error(0, "illegal control clause");
+                               }
+                       }
+               }
+               P.expr_lev = prev_lev;
+       }
+
+       return init, expr, post;
+}
+
+
+func (P *Parser) OldParseControlClause(keyword int) *AST.StatImpl {
        if P.verbose {
                P.Trace("ControlClause");
                defer P.Ecart();
@@ -1283,7 +1425,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
                prev_lev := P.expr_lev;
                P.expr_lev = -1;
                if P.tok != Scanner.SEMICOLON {
-                       s.Init = P.ParseSimpleStat(keyword == Scanner.FOR);
+                       s.Init = P.OldParseSimpleStat(keyword == Scanner.FOR);
                        // TODO check for range clause and exit if found
                }
                if P.tok == Scanner.SEMICOLON {
@@ -1294,7 +1436,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
                        if keyword == Scanner.FOR {
                                P.Expect(Scanner.SEMICOLON);
                                if P.tok != Scanner.LBRACE {
-                                       s.Post = P.ParseSimpleStat(false);
+                                       s.Post = P.OldParseSimpleStat(false);
                                }
                        }
                } else {
@@ -1309,22 +1451,61 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
 }
 
 
-func (P *Parser) ParseIfStat() *AST.Stat {
+func (P *Parser) ParseIfStat() *AST.IfStat {
+       if P.verbose {
+               P.Trace("IfStat");
+               defer P.Ecart();
+       }
+
+       P.OpenScope();
+       pos := P.pos;
+       P.Expect(Scanner.IF);
+       init, cond, dummy := P.ParseControlClause(false);
+       body := P.ParseBlock(nil, Scanner.LBRACE);
+       var else_ AST.Stat;
+       if P.tok == Scanner.ELSE {
+               P.Next();
+               if P.tok == Scanner.IF || P.tok == Scanner.LBRACE {
+                       else_ = P.ParseStatement();
+               } else if P.sixg {
+                       else_ = P.ParseStatement();
+                       if else_ != nil {
+                               // not the empty statement
+                               // wrap in a block since we don't have one
+                               panic();
+                               /*
+                               b := AST.NewStat(s1.Pos, Scanner.LBRACE);
+                               b.Body = AST.NewBlock(s1.Pos, Scanner.LBRACE);
+                               b.Body.List.Push(s1);
+                               s1 = b;
+                               */
+                       }
+               } else {
+                       P.Error(P.pos, "'if' or '{' expected - illegal 'else' branch");
+               }
+       }
+       P.CloseScope();
+
+       return &AST.IfStat{pos, init, cond, body, else_ };
+}
+
+
+func (P *Parser) OldParseIfStat() *AST.StatImpl {
        if P.verbose {
                P.Trace("IfStat");
                defer P.Ecart();
        }
 
        P.OpenScope();
-       s := P.ParseControlClause(Scanner.IF);
+       s := P.OldParseControlClause(Scanner.IF);
        s.Body = P.ParseBlock(nil, Scanner.LBRACE);
        if P.tok == Scanner.ELSE {
                P.Next();
-               s1 := AST.BadStat;
+               s1 := AST.OldBadStat;
                if P.tok == Scanner.IF || P.tok == Scanner.LBRACE {
-                       s1 = P.ParseStatement();
+                       s1 = P.OldParseStatement();
                } else if P.sixg {
-                       s1 = P.ParseStatement();
+                       s1 = P.OldParseStatement();
                        if s1 != nil {
                                // not the empty statement
                                assert(s1.Tok != Scanner.LBRACE);
@@ -1345,14 +1526,31 @@ func (P *Parser) ParseIfStat() *AST.Stat {
 }
 
 
-func (P *Parser) ParseForStat() *AST.Stat {
+func (P *Parser) ParseForStat() *AST.ForStat {
        if P.verbose {
                P.Trace("ForStat");
                defer P.Ecart();
        }
 
        P.OpenScope();
-       s := P.ParseControlClause(Scanner.FOR);
+       pos := P.pos;
+       P.Expect(Scanner.FOR);
+       init, cond, post := P.ParseControlClause(true);
+       body := P.ParseBlock(nil, Scanner.LBRACE);
+       P.CloseScope();
+
+       return &AST.ForStat{pos, init, cond, post, body};
+}
+
+
+func (P *Parser) OldParseForStat() *AST.StatImpl {
+       if P.verbose {
+               P.Trace("ForStat");
+               defer P.Ecart();
+       }
+
+       P.OpenScope();
+       s := P.OldParseControlClause(Scanner.FOR);
        s.Body = P.ParseBlock(nil, Scanner.LBRACE);
        P.CloseScope();
 
@@ -1360,7 +1558,7 @@ func (P *Parser) ParseForStat() *AST.Stat {
 }
 
 
-func (P *Parser) ParseSwitchCase() *AST.Stat {
+func (P *Parser) ParseSwitchCase() *AST.StatImpl {
        if P.verbose {
                P.Trace("SwitchCase");
                defer P.Ecart();
@@ -1378,7 +1576,7 @@ func (P *Parser) ParseSwitchCase() *AST.Stat {
 }
 
 
-func (P *Parser) ParseCaseClause() *AST.Stat {
+func (P *Parser) ParseCaseClause() *AST.StatImpl {
        if P.verbose {
                P.Trace("CaseClause");
                defer P.Ecart();
@@ -1391,14 +1589,38 @@ func (P *Parser) ParseCaseClause() *AST.Stat {
 }
 
 
-func (P *Parser) ParseSwitchStat() *AST.Stat {
+func (P *Parser) ParseSwitchStat() *AST.SwitchStat {
+       if P.verbose {
+               P.Trace("SwitchStat");
+               defer P.Ecart();
+       }
+
+       P.OpenScope();
+       pos := P.pos;
+       P.Expect(Scanner.SWITCH);
+       init, tag, post := P.ParseControlClause(false);
+       body := AST.NewBlock(P.pos, Scanner.LBRACE);
+       P.Expect(Scanner.LBRACE);
+       for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
+               body.List.Push(P.ParseCaseClause());
+       }
+       body.End = P.pos;
+       P.Expect(Scanner.RBRACE);
+       P.opt_semi = true;
+       P.CloseScope();
+
+       return &AST.SwitchStat{pos, init, tag, body};
+}
+
+
+func (P *Parser) OldParseSwitchStat() *AST.StatImpl {
        if P.verbose {
                P.Trace("SwitchStat");
                defer P.Ecart();
        }
 
        P.OpenScope();
-       s := P.ParseControlClause(Scanner.SWITCH);
+       s := P.OldParseControlClause(Scanner.SWITCH);
        b := AST.NewBlock(P.pos, Scanner.LBRACE);
        P.Expect(Scanner.LBRACE);
        for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
@@ -1414,7 +1636,7 @@ func (P *Parser) ParseSwitchStat() *AST.Stat {
 }
 
 
-func (P *Parser) ParseCommCase() *AST.Stat {
+func (P *Parser) ParseCommCase() *AST.StatImpl {
        if P.verbose {
                P.Trace("CommCase");
                defer P.Ecart();
@@ -1443,7 +1665,7 @@ func (P *Parser) ParseCommCase() *AST.Stat {
 }
 
 
-func (P *Parser) ParseCommClause() *AST.Stat {
+func (P *Parser) ParseCommClause() *AST.StatImpl {
        if P.verbose {
                P.Trace("CommClause");
                defer P.Ecart();
@@ -1456,12 +1678,36 @@ func (P *Parser) ParseCommClause() *AST.Stat {
 }
 
 
-func (P *Parser) ParseSelectStat() *AST.Stat {
+func (P *Parser) ParseSelectStat() *AST.SelectStat {
        if P.verbose {
                P.Trace("SelectStat");
                defer P.Ecart();
        }
 
+       P.OpenScope();
+       pos := P.pos;
+       P.Expect(Scanner.SELECT);
+       body := AST.NewBlock(P.pos, Scanner.LBRACE);
+       P.Expect(Scanner.LBRACE);
+       for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
+               body.List.Push(P.ParseCommClause());
+       }
+       body.End = P.pos;
+       P.Expect(Scanner.RBRACE);
+       P.opt_semi = true;
+       P.CloseScope();
+
+       return &AST.SelectStat{pos, body};
+}
+
+
+func (P *Parser) OldParseSelectStat() *AST.StatImpl {
+       if P.verbose {
+               P.Trace("SelectStat");
+               defer P.Ecart();
+       }
+
+       P.OpenScope();
        s := AST.NewStat(P.pos, Scanner.SELECT);
        P.Expect(Scanner.SELECT);
        b := AST.NewBlock(P.pos, Scanner.LBRACE);
@@ -1472,20 +1718,66 @@ func (P *Parser) ParseSelectStat() *AST.Stat {
        b.End = P.pos;
        P.Expect(Scanner.RBRACE);
        P.opt_semi = true;
+       P.CloseScope();
        s.Body = b;
 
        return s;
 }
 
 
-func (P *Parser) ParseStatement() *AST.Stat {
+func (P *Parser) ParseStatement() AST.Stat {
        if P.verbose {
                P.Trace("Statement");
                defer P.Ecart();
+               defer P.VerifyIndent(P.indent);
+       }
+
+       s := AST.OldBadStat;
+       switch P.tok {
+       case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
+               return &AST.DeclarationStat{P.ParseDeclaration()};
+       case Scanner.FUNC:
+               // for now we do not allow local function declarations,
+               // instead we assume this starts a function literal
+               fallthrough;
+       case
+               // only the tokens that are legal top-level expression starts
+               Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING, Scanner.LPAREN,  // operand
+               Scanner.LBRACK, Scanner.STRUCT,  // composite type
+               Scanner.MUL, Scanner.AND, Scanner.ARROW:  // unary
+               return P.ParseSimpleStat(false);
+       case Scanner.GO, Scanner.DEFER:
+               return P.ParseInvocationStat(P.tok);
+       case Scanner.RETURN:
+               return P.ParseReturnStat();
+       case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO, Scanner.FALLTHROUGH:
+               s = P.ParseControlFlowStat(P.tok);
+       case Scanner.LBRACE:
+               s = AST.NewStat(P.pos, Scanner.LBRACE);
+               s.Body = P.ParseBlock(nil, Scanner.LBRACE);
+       case Scanner.IF:
+               return P.ParseIfStat();
+       case Scanner.FOR:
+               return P.ParseForStat();
+       case Scanner.SWITCH:
+               return P.ParseSwitchStat();
+       case Scanner.SELECT:
+               return P.ParseSelectStat();
+       }
+
+       // empty statement
+       return nil;
+}
+
+
+func (P *Parser) OldParseStatement() *AST.StatImpl {
+       if P.verbose {
+               P.Trace("Statement");
+               defer P.Ecart();
+               defer P.VerifyIndent(P.indent);
        }
-       indent := P.indent;
 
-       s := AST.BadStat;
+       s := AST.OldBadStat;
        switch P.tok {
        case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
                s = AST.NewStat(P.pos, P.tok);
@@ -1499,32 +1791,29 @@ func (P *Parser) ParseStatement() *AST.Stat {
                Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING, Scanner.LPAREN,  // operand
                Scanner.LBRACK, Scanner.STRUCT,  // composite type
                Scanner.MUL, Scanner.AND, Scanner.ARROW:  // unary
-               s = P.ParseSimpleStat(false);
+               s = P.OldParseSimpleStat(false);
        case Scanner.GO, Scanner.DEFER:
-               s = P.ParseInvocationStat(P.tok);
+               s = P.OldParseInvocationStat(P.tok);
        case Scanner.RETURN:
-               s = P.ParseReturnStat();
+               s = P.OldParseReturnStat();
        case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO, Scanner.FALLTHROUGH:
                s = P.ParseControlFlowStat(P.tok);
        case Scanner.LBRACE:
                s = AST.NewStat(P.pos, Scanner.LBRACE);
                s.Body = P.ParseBlock(nil, Scanner.LBRACE);
        case Scanner.IF:
-               s = P.ParseIfStat();
+               s = P.OldParseIfStat();
        case Scanner.FOR:
-               s = P.ParseForStat();
+               s = P.OldParseForStat();
        case Scanner.SWITCH:
-               s = P.ParseSwitchStat();
+               s = P.OldParseSwitchStat();
        case Scanner.SELECT:
-               s = P.ParseSelectStat();
+               s = P.OldParseSelectStat();
        default:
                // empty statement
                s = nil;
        }
 
-       if indent != P.indent {
-               panic("imbalanced tracing code (Statement)");
-       }
        return s;
 }
 
@@ -1719,6 +2008,7 @@ func (P *Parser) ParseDeclaration() *AST.Decl {
        if P.verbose {
                P.Trace("Declaration");
                defer P.Ecart();
+               defer P.VerifyIndent(P.indent);
        }
        indent := P.indent;
 
@@ -1734,9 +2024,6 @@ func (P *Parser) ParseDeclaration() *AST.Decl {
                P.Next();  // make progress
        }
 
-       if indent != P.indent {
-               panic("imbalanced tracing code (Declaration)");
-       }
        return d;
 }
 
index 5e3f8a4b7468cb6f3590a2a44fc233fc18c868c0..143886fce7c68aaa16ca913edc34fb24e6aed74f 100644 (file)
@@ -371,9 +371,8 @@ func (P *Printer) Token(pos int, tok int) {
 
 
 func (P *Printer) Error(pos int, tok int, msg string) {
-       P.String(0, "<");
-       P.Token(pos, tok);
-       P.String(0, " " + msg + ">");
+       fmt.Printf("\ninternal printing error: pos = %d, tok = %s, %s\n", pos, Scanner.TokenString(tok), msg);
+       panic();
 }
 
 
@@ -723,12 +722,25 @@ func (P *Printer) Expr(x AST.Expr) {
 // ----------------------------------------------------------------------------
 // Statements
 
-func (P *Printer) Stat(s *AST.Stat)
+func (P *Printer) Stat(s AST.Stat) {
+       s.Visit(P);
+}
+
+
+func (P *Printer) StatImpl(s *AST.StatImpl)
 
 func (P *Printer) StatementList(list *array.Array) {
        for i, n := 0, list.Len(); i < n; i++ {
                P.newlines = 1;  // for first entry
-               P.Stat(list.At(i).(*AST.Stat));
+               
+               if s, is_StatImpl := list.At(i).(*AST.StatImpl); is_StatImpl {
+                       P.StatImpl(s);
+               } else if s, is_Stat := list.At(i).(AST.Stat); is_Stat {
+                       s.Visit(P);
+               } else {
+                       panic();
+               }
+
                P.newlines = 1;
                P.state = inside_list;
        }
@@ -757,7 +769,7 @@ func (P *Printer) Block(b *AST.Block, indent bool) {
 }
 
 
-func (P *Printer) ControlClause(s *AST.Stat) {
+func (P *Printer) OldControlClause(s *AST.StatImpl) {
        has_post := s.Tok == Scanner.FOR && s.Post != nil;  // post also used by "if"
 
        P.separator = blank;
@@ -770,7 +782,7 @@ func (P *Printer) ControlClause(s *AST.Stat) {
                // all semicolons required
                // (they are not separators, print them explicitly)
                if s.Init != nil {
-                       P.Stat(s.Init);
+                       P.StatImpl(s.Init);
                        P.separator = none;
                }
                P.String(0, ";");
@@ -783,7 +795,7 @@ func (P *Printer) ControlClause(s *AST.Stat) {
                        P.String(0, ";");
                        P.separator = blank;
                        if has_post {
-                               P.Stat(s.Post);
+                               P.StatImpl(s.Post);
                        }
                }
        }
@@ -793,7 +805,7 @@ func (P *Printer) ControlClause(s *AST.Stat) {
 
 func (P *Printer) Declaration(d *AST.Decl, parenthesized bool);
 
-func (P *Printer) Stat(s *AST.Stat) {
+func (P *Printer) StatImpl(s *AST.StatImpl) {
        switch s.Tok {
        case Scanner.EXPRSTAT:
                // expression statement
@@ -823,23 +835,23 @@ func (P *Printer) Stat(s *AST.Stat) {
 
        case Scanner.IF:
                P.String(s.Pos, "if");
-               P.ControlClause(s);
+               P.OldControlClause(s);
                P.Block(s.Body, true);
                if s.Post != nil {
                        P.separator = blank;
                        P.String(0, "else");
                        P.separator = blank;
-                       P.Stat(s.Post);
+                       P.StatImpl(s.Post);
                }
 
        case Scanner.FOR:
                P.String(s.Pos, "for");
-               P.ControlClause(s);
+               P.OldControlClause(s);
                P.Block(s.Body, true);
 
        case Scanner.SWITCH, Scanner.SELECT:
                P.Token(s.Pos, s.Tok);
-               P.ControlClause(s);
+               P.OldControlClause(s);
                P.Block(s.Body, false);
 
        case Scanner.CASE, Scanner.DEFAULT:
@@ -872,6 +884,116 @@ func (P *Printer) Stat(s *AST.Stat) {
 }
 
 
+func (P *Printer) DoBadStat(s *AST.BadStat) {
+       panic();
+}
+
+
+func (P *Printer) DoLabelDecl(s *AST.LabelDecl) {
+       panic();
+}
+
+
+func (P *Printer) DoDeclarationStat(s *AST.DeclarationStat) {
+       P.Declaration(s.Decl, false);
+}
+
+
+func (P *Printer) DoExpressionStat(s *AST.ExpressionStat) {
+       switch s.Tok {
+       case Scanner.ILLEGAL:
+               P.Expr(s.Expr);
+       case Scanner.INC, Scanner.DEC:
+               P.Expr(s.Expr);
+               P.Token(s.Pos, s.Tok);
+       case Scanner.RETURN, Scanner.GO, Scanner.DEFER:
+               P.Token(s.Pos, s.Tok);
+               if s.Expr != nil {
+                       P.separator = blank;
+                       P.Expr(s.Expr);
+               }
+       default:
+               P.Error(s.Pos, s.Tok, "DoExpressionStat");
+               unreachable();
+       }
+       P.separator = semicolon;
+}
+
+
+func (P *Printer) ControlClause(isForStat bool, init AST.Stat, expr AST.Expr, post AST.Stat) {
+       P.separator = blank;
+       if init == nil && post == nil {
+               // no semicolons required
+               if expr != nil {
+                       P.Expr(expr);
+               }
+       } else {
+               // all semicolons required
+               // (they are not separators, print them explicitly)
+               if init != nil {
+                       P.Stat(init);
+                       P.separator = none;
+               }
+               P.String(0, ";");
+               P.separator = blank;
+               if expr != nil {
+                       P.Expr(expr);
+                       P.separator = none;
+               }
+               if isForStat {
+                       P.String(0, ";");
+                       P.separator = blank;
+                       if post != nil {
+                               P.Stat(post);
+                       }
+               }
+       }
+       P.separator = blank;
+}
+
+
+func (P *Printer) DoIfStat(s *AST.IfStat) {
+       P.String(s.Pos, "if");
+       P.ControlClause(false, s.Init, s.Cond, nil);
+       P.Block(s.Body, true);
+       if s.Else != nil {
+               P.separator = blank;
+               P.String(0, "else");
+               P.separator = blank;
+               P.Stat(s.Else);
+       }
+}
+
+
+func (P *Printer) DoForStat(s *AST.ForStat) {
+       P.String(s.Pos, "for");
+       P.ControlClause(true, s.Init, s.Cond, s.Post);
+       P.Block(s.Body, true);
+}
+
+
+func (P *Printer) DoSwitchStat(s *AST.SwitchStat) {
+       P.String(s.Pos, "switch");
+       P.ControlClause(false, s.Init, s.Tag, nil);
+       P.Block(s.Body, false);
+}
+
+
+func (P *Printer) DoSelectStat(s *AST.SelectStat) {
+       panic();
+}
+
+
+func (P *Printer) DoControlFlowStat(s *AST.ControlFlowStat) {
+       P.Token(s.Pos, s.Tok);
+       if s.Label != nil {
+               P.separator = blank;
+               P.Expr(s.Label);
+       }
+       P.separator = semicolon;
+}
+
+
 // ----------------------------------------------------------------------------
 // Declarations