Block struct;
Expr interface;
- Stat struct;
+ StatImpl struct;
Decl struct;
)
// Expressions
type (
- Visitor interface;
+ ExprVisitor interface;
Expr interface {
Pos() int;
- Visit(v Visitor);
+ Visit(v ExprVisitor);
};
BadExpr struct {
)
-type Visitor interface {
+type ExprVisitor interface {
DoBadExpr(x *BadExpr);
DoIdent(x *Ident);
DoBinaryExpr(x *BinaryExpr);
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); }
// ----------------------------------------------------------------------------
// 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);
// ----------------------------------------------------------------------------
package Parser
import (
+ "flag";
"fmt";
"array";
Scanner "scanner";
}
+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();
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;
// ----------------------------------------------------------------------------
// 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);
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 {
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);
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 {
}
-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();
}
-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();
}
-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();
}
-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();
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 {
if keyword == Scanner.FOR {
P.Expect(Scanner.SEMICOLON);
if P.tok != Scanner.LBRACE {
- s.Post = P.ParseSimpleStat(false);
+ s.Post = P.OldParseSimpleStat(false);
}
}
} else {
}
-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);
}
-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();
}
-func (P *Parser) ParseSwitchCase() *AST.Stat {
+func (P *Parser) ParseSwitchCase() *AST.StatImpl {
if P.verbose {
P.Trace("SwitchCase");
defer P.Ecart();
}
-func (P *Parser) ParseCaseClause() *AST.Stat {
+func (P *Parser) ParseCaseClause() *AST.StatImpl {
if P.verbose {
P.Trace("CaseClause");
defer P.Ecart();
}
-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 {
}
-func (P *Parser) ParseCommCase() *AST.Stat {
+func (P *Parser) ParseCommCase() *AST.StatImpl {
if P.verbose {
P.Trace("CommCase");
defer P.Ecart();
}
-func (P *Parser) ParseCommClause() *AST.Stat {
+func (P *Parser) ParseCommClause() *AST.StatImpl {
if P.verbose {
P.Trace("CommClause");
defer P.Ecart();
}
-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);
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);
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;
}
if P.verbose {
P.Trace("Declaration");
defer P.Ecart();
+ defer P.VerifyIndent(P.indent);
}
indent := P.indent;
P.Next(); // make progress
}
- if indent != P.indent {
- panic("imbalanced tracing code (Declaration)");
- }
return d;
}
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();
}
// ----------------------------------------------------------------------------
// 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;
}
}
-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;
// 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, ";");
P.String(0, ";");
P.separator = blank;
if has_post {
- P.Stat(s.Post);
+ P.StatImpl(s.Post);
}
}
}
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
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:
}
+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