]> Cypherpunks repositories - gostls13.git/commitdiff
- snapshot of pretty printer work
authorRobert Griesemer <gri@golang.org>
Wed, 15 Oct 2008 01:14:01 +0000 (18:14 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 15 Oct 2008 01:14:01 +0000 (18:14 -0700)
- accepts all Go code (use -s flag)
- complete rewrite of AST, AST building, and printing
  (as a result much more compact)
- printing severely screwed up at the moment, but should be
  fully working in 1 more day

R=r
DELTA=2118  (514 added, 980 deleted, 624 changed)
OCL=17161
CL=17161

usr/gri/pretty/Makefile
usr/gri/pretty/ast.go [deleted file]
usr/gri/pretty/node.go [new file with mode: 0644]
usr/gri/pretty/parser.go
usr/gri/pretty/pretty.go
usr/gri/pretty/printer.go

index 0ef3e402514ee8f005941be037d71e98f13e37d5..d1d2c277b21c844d7521b054123a420cfdc5e91a 100644 (file)
@@ -54,7 +54,11 @@ clean:
 
 pretty.6:      parser.6 printer.6 platform.6 scanner.6
 
-parser.6:      ast.6 scanner.6 utils.6 printer.6
+printer.6:     node.6 scanner.6
+
+parser.6:      scanner.6 utils.6 printer.6 node.6
+
+node.6:        scanner.6
 
 scanner.6:     utils.6 platform.6
 
diff --git a/usr/gri/pretty/ast.go b/usr/gri/pretty/ast.go
deleted file mode 100644 (file)
index cd31f3f..0000000
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package AST
-
-
-// ----------------------------------------------------------------------------
-// Visitor
-
-type (
-       Nil struct;
-       Ident struct;
-       ArrayType struct;
-       StructType struct;
-       MapType struct;
-       ChannelType struct;
-       PointerType struct;
-       InterfaceType struct;
-       FunctionType struct;
-       VarDeclList struct;
-       ImportDecl struct;
-       ConstDecl struct;
-       TypeDecl struct;
-       VarDecl struct;
-       Declaration struct;
-       FuncDecl struct;
-       MethodDecl struct;
-       Selector struct;
-       Index struct;
-       Call struct;
-       Pair struct;
-       Binary struct;
-       Unary struct;
-       Literal struct;
-       CompositeLit struct;
-       FunctionLit struct;
-       Label struct;
-       Block struct;
-       ExprStat struct;
-       Assignment struct;
-       ControlClause struct;
-       IfStat struct;
-       ForStat struct;
-       CaseClause struct;
-       SwitchStat struct;
-       ReturnStat struct;
-       IncDecStat struct;
-       ControlFlowStat struct;
-       GoStat struct;
-       Program struct;
-)
-
-export type Visitor interface {
-       // Basics
-       DoNil(x *Nil);
-       DoIdent(x *Ident);
-
-       // Types
-       DoFunctionType(x *FunctionType);
-       DoArrayType(x *ArrayType);
-       DoStructType(x *StructType);
-       DoMapType(x *MapType);
-       DoChannelType(x *ChannelType);
-       DoInterfaceType(x *InterfaceType);
-       DoPointerType(x *PointerType);
-
-       // Declarations
-       DoImportDecl(x *ImportDecl);
-       DoConstDecl(x *ConstDecl);
-       DoTypeDecl(x *TypeDecl);
-       DoVarDecl(x *VarDecl);
-       DoVarDeclList(x *VarDeclList);
-       DoFuncDecl(x *FuncDecl);
-       DoMethodDecl(x *MethodDecl);
-       DoDeclaration(x *Declaration);
-
-       // Expressions
-       DoBinary(x *Binary);
-       DoUnary(x *Unary);
-       DoLiteral(x *Literal);
-       DoPair(x *Pair);
-       DoIndex(x *Index);
-       DoCall(x *Call);
-       DoSelector(x *Selector);
-       DoCompositeLit(x *CompositeLit);
-       DoFunctionLit(x *FunctionLit);
-
-       // Statements
-       DoLabel(x *Label);
-       DoBlock(x *Block);
-       DoExprStat(x *ExprStat);
-       DoAssignment(x *Assignment);
-       DoIfStat(x *IfStat);
-       DoForStat(x *ForStat);
-       DoCaseClause(x *CaseClause);
-       DoSwitchStat(x *SwitchStat);
-       DoReturnStat(x *ReturnStat);
-       DoIncDecStat(x *IncDecStat);
-       DoControlFlowStat(x *ControlFlowStat);
-       DoGoStat(x *GoStat);
-
-       // Program
-       DoProgram(x *Program);
-}
-
-
-// ----------------------------------------------------------------------------
-// An AST Node
-
-export type Node interface {
-       Visit(x Visitor);
-}
-
-
-// ----------------------------------------------------------------------------
-// Lists
-//
-// If p is a list and p == nil, then p.len() == 0.
-// Thus, empty lists can be represented by nil.
-
-export type List struct {
-       a *[] Node;
-}
-
-
-func (p *List) len() int {
-       if p == nil { return 0; }
-       return len(p.a);
-}
-
-
-func (p *List) at(i int) Node {
-       return p.a[i];
-}
-
-
-func (p *List) Add (x Node) {
-       a := p.a;
-       n := len(a);
-
-       if n == cap(a) {
-               b := new([] Node, 2*n);
-               for i := 0; i < n; i++ {
-                       b[i] = a[i];
-               }
-               a = b;
-       }
-
-       a = a[0 : n + 1];
-       a[n] = x;
-       p.a = a;
-}
-
-
-export func NewList() *List {
-       p := new(List);
-       p.a = new([] Node, 10) [0 : 0];
-       return p;
-}
-
-
-// ----------------------------------------------------------------------------
-// Basics
-
-export type Nil struct {
-       // The Node "nil" value
-}
-
-export var NIL *Nil = new(Nil);
-
-
-export type Ident struct {
-       pos int;
-       val string;
-}
-
-
-func (x *Nil)   Visit(v Visitor)  { v.DoNil(x); }
-func (x *Ident) Visit(v Visitor)  { v.DoIdent(x); }
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-export type Type interface {
-       Visit(x Visitor);
-}
-
-
-export type Expr interface {
-       Visit(x Visitor);
-}
-
-
-export type ArrayType struct {
-       pos int;  // position of "["
-       len_ Expr;
-       elt Type;
-}
-
-
-export type StructType struct {
-       pos int;  // position of "struct"
-       fields *List;  // list of *VarDeclList
-}
-
-
-export type MapType struct {
-       pos int;  // position of "map"
-       key, val Type;
-}
-
-
-export const /* chan mode */ (
-       FULL = iota;
-       RECV;
-       SEND;
-)
-
-export type ChannelType struct {
-       pos int;  // position of "chan" or "<-" (if before "chan")
-       elt Type;
-       mode int;
-}
-
-
-export type PointerType struct {
-       pos int;  // position of "*"
-       base Type;
-}
-
-
-export type InterfaceType struct {
-       pos int;  // position of "interface"
-       methods *List;  // list of *MethodDecl
-}
-
-
-export type FunctionType struct {
-       pos int;  // position of "("
-       recv *VarDeclList;
-       params *List;  // list of *VarDeclList
-       result *List;  // list of *VarDeclList
-}
-
-
-func (x *FunctionType)   Visit(v Visitor)  { v.DoFunctionType(x); }
-func (x *ArrayType)      Visit(v Visitor)  { v.DoArrayType(x); }
-func (x *StructType)     Visit(v Visitor)  { v.DoStructType(x); }
-func (x *MapType)        Visit(v Visitor)  { v.DoMapType(x); }
-func (x *ChannelType)    Visit(v Visitor)  { v.DoChannelType(x); }
-func (x *PointerType)    Visit(v Visitor)  { v.DoPointerType(x); }
-func (x *InterfaceType)  Visit(v Visitor)  { v.DoInterfaceType(x); }
-
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-export type Decl interface {
-       Visit(x Visitor);
-}
-
-
-export type VarDeclList struct {
-       idents *List;  // possibly nil
-       typ Type;
-}
-
-
-export type ImportDecl struct {
-       ident *Ident;
-       file string;
-}
-
-
-export type ConstDecl struct {
-       ident *Ident;
-       typ Type;
-       val Expr;
-}
-
-
-export type TypeDecl struct {
-       ident *Ident;
-       typ Type;
-}
-
-
-export type VarDecl struct {
-       idents *List;
-       typ Type;
-       vals *List;
-}
-
-
-export type Declaration struct {
-       pos int;  // position of token
-       tok int;
-       decls *List;
-}
-
-
-export type FuncDecl struct {
-       pos int;  // position of "func"
-       ident *Ident;
-       typ *FunctionType;
-       body *Block;
-}
-
-
-export type MethodDecl struct {
-       ident *Ident;
-       typ *FunctionType;
-}
-
-
-func (x *VarDeclList)  Visit(v Visitor)  { v.DoVarDeclList(x); }
-func (x *ImportDecl)   Visit(v Visitor)  { v.DoImportDecl(x); }
-func (x *ConstDecl)    Visit(v Visitor)  { v.DoConstDecl(x); }
-func (x *TypeDecl)     Visit(v Visitor)  { v.DoTypeDecl(x); }
-func (x *VarDecl)      Visit(v Visitor)  { v.DoVarDecl(x); }
-func (x *FuncDecl)     Visit(v Visitor)  { v.DoFuncDecl(x); }
-func (x *MethodDecl)   Visit(v Visitor)  { v.DoMethodDecl(x); }
-func (x *Declaration)  Visit(v Visitor)  { v.DoDeclaration(x); }
-
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-export type Selector struct {
-       pos int;  // position of "."
-       x Expr;
-       field string;
-}
-
-
-export type Index struct {
-       pos int;  // position of "["
-       x Expr;
-       index Expr;
-}
-
-
-export type Call struct {
-       pos int;  // position of "("
-       fun Expr;
-       args *List;
-}
-
-
-export type Pair struct {
-       pos int;  // position of ":"
-       x, y Expr;
-}
-
-
-export type Binary struct {
-       pos int;  // position of operator tok
-       tok int;
-       x, y Expr;
-}
-
-
-export type Unary struct {
-       pos int;  // position of operator tok
-       tok int;
-       x Expr;
-}
-
-
-export type Literal struct {
-       pos int;  // position of literal
-       tok int;
-       val string;
-}
-
-
-export type CompositeLit struct {
-       pos int;  // position of "{"
-       typ Type;
-       vals *List  // list of Expr
-}
-
-
-export type FunctionLit struct {
-       pos int;  // position of "func"
-       typ *FunctionType;
-       body *Block;
-}
-
-
-func (x *Binary)       Visit(v Visitor)  { v.DoBinary(x); }
-func (x *Unary)        Visit(v Visitor)  { v.DoUnary(x); }
-func (x *Literal)      Visit(v Visitor)  { v.DoLiteral(x); }
-func (x *Pair)         Visit(v Visitor)  { v.DoPair(x); }
-func (x *Index)        Visit(v Visitor)  { v.DoIndex(x); }
-func (x *Call)         Visit(v Visitor)  { v.DoCall(x); }
-func (x *Selector)     Visit(v Visitor)  { v.DoSelector(x); }
-func (x *CompositeLit) Visit(v Visitor)  { v.DoCompositeLit(x); }
-func (x *FunctionLit)  Visit(v Visitor)  { v.DoFunctionLit(x); }
-
-
-// ----------------------------------------------------------------------------
-// Statements
-
-export type Stat interface {
-       Visit(x Visitor);
-}
-
-
-export type Label struct {
-       pos int;  // position of ":"
-       ident Expr;  // should be ident
-}
-
-
-export type Block struct {
-       pos int;  // position of "{"
-       stats *List;
-}
-
-
-export type ExprStat struct {
-       expr Expr;
-}
-
-
-export type Assignment struct {
-       pos int;  // position of assignment token
-       tok int;
-       lhs, rhs *List;
-}
-
-
-export type ControlClause struct {
-       init Stat;
-       expr Expr;
-       post Stat;
-       has_init, has_expr, has_post bool;
-}
-
-
-export type IfStat struct {
-       pos int;  // position of "if"
-       ctrl *ControlClause;
-       then *Block;
-       else_ Stat;
-       has_else bool;
-}
-
-
-export type ForStat struct {
-       pos int;  // position of "for"
-       ctrl *ControlClause;
-       body *Block;
-}
-
-
-export type CaseClause struct {
-       pos int;  // position of "case" or "default"
-       exprs *List;  // nil if default case
-       stats *List;  // list of Stat
-       falls bool;
-}
-
-
-export type SwitchStat struct {
-       pos int;  // position of "switch"
-       ctrl *ControlClause;
-       cases *List;  // list of *CaseClause
-}
-
-
-export type ReturnStat struct {
-       pos int;  // position of "return"
-       res *List;  // list of Expr
-}
-
-
-export type IncDecStat struct {
-       pos int;  // position of token
-       tok int;
-       expr Expr;
-}
-
-
-export type ControlFlowStat struct {
-       pos int;  // position of token
-       tok int;
-       label *Ident;  // nil, if no label
-}
-
-
-export type GoStat struct {
-       pos int;  // position of "go"
-       expr Expr;
-}
-
-
-func (x *Block)            Visit(v Visitor)  { v.DoBlock(x); }
-func (x *Label)            Visit(v Visitor)  { v.DoLabel(x); }
-func (x *ExprStat)         Visit(v Visitor)  { v.DoExprStat(x); }
-func (x *Assignment)       Visit(v Visitor)  { v.DoAssignment(x); }
-func (x *IfStat)           Visit(v Visitor)  { v.DoIfStat(x); }
-func (x *ForStat)          Visit(v Visitor)  { v.DoForStat(x); }
-func (x *CaseClause)       Visit(v Visitor)  { v.DoCaseClause(x); }
-func (x *SwitchStat)       Visit(v Visitor)  { v.DoSwitchStat(x); }
-func (x *ReturnStat)       Visit(v Visitor)  { v.DoReturnStat(x); }
-func (x *IncDecStat)       Visit(v Visitor)  { v.DoIncDecStat(x); }
-func (x *ControlFlowStat)  Visit(v Visitor)  { v.DoControlFlowStat(x); }
-func (x *GoStat)           Visit(v Visitor)  { v.DoGoStat(x); }
-
-
-// ----------------------------------------------------------------------------
-// Program
-
-export type Program struct {
-       pos int;
-       ident *Ident;
-       decls *List;
-}
-
-
-func (x *Program) Visit(v Visitor)  { v.DoProgram(x); }
diff --git a/usr/gri/pretty/node.go b/usr/gri/pretty/node.go
new file mode 100644 (file)
index 0000000..93f646b
--- /dev/null
@@ -0,0 +1,248 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package Node
+
+import Scanner "scanner"
+
+type Node interface {}
+
+type (
+       Type struct;
+       Expr struct;
+       Stat struct;
+       Decl struct;
+)
+
+
+// ----------------------------------------------------------------------------
+// Lists
+//
+// If p is a list and p == nil, then p.len() == 0.
+// Thus, empty lists can be represented by nil.
+
+export type List struct {
+       a *[] Node;
+}
+
+
+func (p *List) len() int {
+       if p == nil { return 0; }
+       return len(p.a);
+}
+
+
+func (p *List) at(i int) Node {
+       return p.a[i];
+}
+
+
+func (p *List) Add (x Node) {
+       a := p.a;
+       n := len(a);
+
+       if n == cap(a) {
+               b := new([] Node, 2*n);
+               for i := 0; i < n; i++ {
+                       b[i] = a[i];
+               }
+               a = b;
+       }
+
+       a = a[0 : n + 1];
+       a[n] = x;
+       p.a = a;
+}
+
+
+/*
+func (p *List) Print() {
+       print("(");
+       for i, n := 0, p.len(); i < n; i++ {
+               if i > 0 {
+                       print(", ");
+               }
+               p.at(i).Print();
+       }
+       print(")");
+}
+*/
+
+
+export func NewList() *List {
+       p := new(List);
+       p.a = new([] Node, 10) [0 : 0];
+       return p;
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+export const /* channel mode */ (
+       FULL = iota;
+       SEND;
+       RECV;
+)
+
+
+export type Type struct {
+       pos, tok int;
+       expr *Expr;  // type name, array length
+       mode int;  // channel mode
+       key *Type;  // map key
+       elt *Type;  // array element, map or channel value, or pointer base type
+       list *List;  // struct fields, interface methods, function parameters
+}
+
+
+export func NewType(pos, tok int) *Type {
+       t := new(Type);
+       t.pos, t.tok = pos, tok;
+       return t;
+}
+
+
+// ----------------------------------------------------------------------------
+// Expressions
+//
+// Expression pairs are represented as binary expressions with operator ":"
+// Expression lists are represented as binary expressions with operator ","
+
+export type Val struct {
+       i int;
+       f float;
+       s string;
+       t *Type;
+}
+
+
+export type Expr struct {
+       pos, tok int;
+       x, y *Expr;  // binary (x, y) and unary (y) expressions
+       ident string;  // identifiers
+       val *Val;  // literals
+}
+
+
+func (x *Expr) len() int {
+       if x == nil {
+               return 0;
+       }
+       n := 1;
+       for ; x.tok == Scanner.COMMA; x = x.y {
+               n++;
+       }
+       return n;
+}
+
+
+/*
+func (x *Expr) Print() {
+       switch {
+       case x == nil:
+               print("nil");
+       case x.val != nil:
+               print(x.val.s);
+       default:
+               if x.x == nil {
+                       print(Scanner.TokenName(x.tok));
+               } else {
+                       x.x.Print();
+                       print(" ");
+                       print(Scanner.TokenName(x.tok));
+                       print(" ");
+               }
+               x.y.Print();
+       }
+}
+*/
+
+
+export func NewExpr(pos, tok int, x, y *Expr) *Expr {
+       e := new(Expr);
+       e.pos, e.tok, e.x, e.y = pos, tok, x, y;
+       return e;
+}
+
+
+export func NewIdent(pos int, ident string) *Expr {
+       e := new(Expr);
+       e.pos, e.tok, e.ident = pos, Scanner.IDENT, ident;
+       return e;
+}
+
+
+export func NewVal(pos, tok int, val *Val) *Expr {
+       e := new(Expr);
+       e.pos, e.tok, e.val = pos, tok, val;
+       return e;
+}
+
+
+// ----------------------------------------------------------------------------
+// Statements
+
+export type Stat struct {
+       pos, tok int;
+       init *Stat;
+       expr *Expr;
+       post *Stat;
+       block *List;
+       decl *Decl;
+}
+
+
+export func NewStat(pos, tok int) *Stat {
+       s := new(Stat);
+       s.pos, s.tok = pos, tok;
+       return s;
+}
+
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+export type VarDeclList struct {
+}
+
+
+func (d *VarDeclList) Print() {
+}
+
+
+export type Decl struct {
+       pos, tok int;
+       exported bool;
+       ident *Expr;  // nil for ()-style declarations
+       typ *Type;
+       val *Expr;
+       // list of *Decl for ()-style declarations
+       // list of *Stat for func declarations (or nil for forward decl)
+       list *List;
+}
+
+
+export func NewDecl(pos, tok int, exported bool) *Decl {
+       d := new(Decl);
+       d.pos, d.tok, d.exported = pos, tok, exported;
+       return d;
+}
+
+
+// ----------------------------------------------------------------------------
+// Program
+
+export type Program struct {
+       pos int;  // tok is Scanner.PACKAGE
+       ident *Expr;
+       decls *List;
+}
+
+
+export func NewProgram(pos int) *Program {
+       p := new(Program);
+       p.pos = pos;
+       return p;
+}
index ba033ce4010d8c177f0f479a45a15245f38055c7..4dcacdc16f66c7b6f6f1ad629d2a426d40d77e07 100644 (file)
@@ -5,7 +5,7 @@
 package Parser
 
 import Scanner "scanner"
-import AST "ast"
+import Node "node"
 
 
 export type Parser struct {
@@ -43,12 +43,12 @@ func (P *Parser) Trace(msg string) {
                P.PrintIndent();
                print(msg, " {\n");
        }
-       P.indent++;  // always, so proper identation is always checked
+       P.indent++;  // always check proper identation
 }
 
 
 func (P *Parser) Ecart() {
-       P.indent--;  // always, so proper identation is always checked
+       P.indent--;  // always check proper identation
        if P.verbose {
                P.PrintIndent();
                print("}\n");
@@ -105,22 +105,21 @@ func (P *Parser) OptSemicolon() {
 // ----------------------------------------------------------------------------
 // Common productions
 
-func (P *Parser) TryType() (typ AST.Type, ok bool);
-func (P *Parser) ParseExpression() AST.Expr;
-func (P *Parser) ParseStatement() AST.Stat;
-func (P *Parser) ParseDeclaration() AST.Node;
+func (P *Parser) TryType() *Node.Type;
+func (P *Parser) ParseExpression() *Node.Expr;
+func (P *Parser) ParseStatement() *Node.Stat;
+func (P *Parser) ParseDeclaration() *Node.Decl;
 
 
-func (P *Parser) ParseIdent() *AST.Ident {
+func (P *Parser) ParseIdent() *Node.Expr {
        P.Trace("Ident");
 
-       ident := new(AST.Ident);
-       ident.pos, ident.val = P.pos, "";
+       var x *Node.Expr;
        if P.tok == Scanner.IDENT {
-               ident.val = P.val;
+               x = Node.NewIdent(P.pos, P.val);
                if P.verbose {
                        P.PrintIndent();
-                       print("Ident = \"", ident.val, "\"\n");
+                       print("Ident = \"", x.val, "\"\n");
                }
                P.Next();
        } else {
@@ -128,14 +127,14 @@ func (P *Parser) ParseIdent() *AST.Ident {
        }
        
        P.Ecart();
-       return ident;
+       return x;
 }
 
 
-func (P *Parser) ParseIdentList() *AST.List {
+func (P *Parser) ParseIdentList() *Node.List {
        P.Trace("IdentList");
 
-       list := AST.NewList();
+       list := Node.NewList();
        list.Add(P.ParseIdent());
        for P.tok == Scanner.COMMA {
                P.Next();
@@ -147,35 +146,14 @@ func (P *Parser) ParseIdentList() *AST.List {
 }
 
 
-func (P *Parser) ParseQualifiedIdent() AST.Expr {
-       P.Trace("QualifiedIdent");
-
-       ident := P.ParseIdent();
-       var qident AST.Expr = ident;
-
-       for P.tok == Scanner.PERIOD {
-               pos := P.pos;
-               P.Next();
-               y := P.ParseIdent();
-
-               z := new(AST.Selector);
-               z.pos, z.x, z.field = pos, qident, y.val;
-               qident = z;
-       }
-       
-       P.Ecart();
-       return qident;
-}
-
-
 // ----------------------------------------------------------------------------
 // Types
 
-func (P *Parser) ParseType() AST.Type {
+func (P *Parser) ParseType() *Node.Type {
        P.Trace("Type");
        
-       typ, ok := P.TryType();
-       if !ok {
+       typ := P.TryType();
+       if typ == nil {
                P.Error(P.pos, "type expected");
        }
        
@@ -184,7 +162,7 @@ func (P *Parser) ParseType() AST.Type {
 }
 
 
-func (P *Parser) ParseVarType() AST.Type {
+func (P *Parser) ParseVarType() *Node.Type {
        P.Trace("VarType");
        
        typ := P.ParseType();
@@ -194,91 +172,97 @@ func (P *Parser) ParseVarType() AST.Type {
 }
 
 
-func (P *Parser) ParseTypeName() AST.Type {
+func (P *Parser) ParseQualifiedIdent() *Node.Expr {
+       P.Trace("QualifiedIdent");
+
+       x := P.ParseIdent();
+       for P.tok == Scanner.PERIOD {
+               pos := P.pos;
+               P.Next();
+               y := P.ParseIdent();
+               x = Node.NewExpr(pos, Scanner.PERIOD, x, y);
+       }
+       
+       P.Ecart();
+       return x;
+}
+
+
+func (P *Parser) ParseTypeName() *Node.Type {
        P.Trace("TypeName");
        
-       typ := P.ParseQualifiedIdent();
+       t := Node.NewType(P.pos, P.tok);
+       t.expr = P.ParseQualifiedIdent();
 
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseArrayType() *AST.ArrayType {
+func (P *Parser) ParseArrayType() *Node.Type {
        P.Trace("ArrayType");
        
-       typ := new(AST.ArrayType);
-       typ.pos = P.pos;
-       typ.len_ = AST.NIL;
-       
+       t := Node.NewType(P.pos, Scanner.LBRACK);
        P.Expect(Scanner.LBRACK);
        if P.tok != Scanner.RBRACK {
-               // TODO set typ.len
-               typ.len_ = P.ParseExpression();
+               t.expr = P.ParseExpression();
        }
        P.Expect(Scanner.RBRACK);
-       typ.elt = P.ParseType();
+       t.elt = P.ParseType();
 
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseChannelType() *AST.ChannelType {
+func (P *Parser) ParseChannelType() *Node.Type {
        P.Trace("ChannelType");
        
-       typ := new(AST.ChannelType);
-       typ.pos = P.pos;
-       typ.mode = AST.FULL;
-       
+       t := Node.NewType(P.pos, Scanner.CHAN);
+       t.mode = Node.FULL;
        if P.tok == Scanner.CHAN {
                P.Next();
                if P.tok == Scanner.ARROW {
                        P.Next();
-                       typ.mode = AST.SEND;
+                       t.mode = Node.SEND;
                }
        } else {
                P.Expect(Scanner.ARROW);
                P.Expect(Scanner.CHAN);
-               typ.mode = AST.RECV;
+               t.mode = Node.RECV;
        }
-       typ.elt = P.ParseVarType();
+       t.elt = P.ParseVarType();
 
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseVarDeclList() *AST.VarDeclList {
+func (P *Parser) ParseVarDeclList() *Node.VarDeclList {
        P.Trace("VarDeclList");
 
-       vars := new(AST.VarDeclList);
-       vars.idents = AST.NewList();
-       vars.typ = AST.NIL;
-       
-       vars.idents.Add(P.ParseType());
+       list := new(Node.VarDeclList);
+       P.ParseType();
        for P.tok == Scanner.COMMA {
                P.Next();
-               vars.idents.Add(P.ParseType());
+               P.ParseType();
        }
        
-       var ok bool;
-       vars.typ, ok = P.TryType();
+       typ := P.TryType();
 
-       if !ok {
+       if typ == nil {
                // we must have a list of types
        }
        
        P.Ecart();
-       return vars;
+       return list;
 }
 
 
-// Returns a list of *AST.VarDeclList or Type
-func (P *Parser) ParseParameterList() *AST.List {
+func (P *Parser) ParseParameterList() *Node.List {
        P.Trace("ParameterList");
        
-       list := AST.NewList();
+       list := Node.NewList();
        list.Add(P.ParseVarDeclList());
        for P.tok == Scanner.COMMA {
                P.Next();
@@ -290,11 +274,10 @@ func (P *Parser) ParseParameterList() *AST.List {
 }
 
 
-// Returns a list of AST.VarDeclList
-func (P *Parser) ParseParameters() *AST.List {
+func (P *Parser) ParseParameters() *Node.List {
        P.Trace("Parameters");
        
-       var list *AST.List;
+       var list *Node.List;
        P.Expect(Scanner.LPAREN);
        if P.tok != Scanner.RPAREN {
                list = P.ParseParameterList();
@@ -322,25 +305,18 @@ func (P *Parser) ParseResultList() {
 }
 
 
-func (P *Parser) ParseResult() *AST.List {
+func (P *Parser) ParseResult() *Node.List {
        P.Trace("Result");
        
-       var result *AST.List;
+       var list *Node.List;
        if P.tok == Scanner.LPAREN {
-               result = P.ParseParameters();
+               list = P.ParseParameters();
        } else {
-               typ, ok := P.TryType();
-               if ok {
-                       vars := new(AST.VarDeclList);
-                       vars.typ = typ;
-                       list := AST.NewList();
-                       list.Add(vars);
-                       result = list;
-               }
+               typ := P.TryType();
        }
 
        P.Ecart();
-       return result;
+       return list;
 }
 
 
@@ -350,44 +326,38 @@ func (P *Parser) ParseResult() *AST.List {
 // (params) type
 // (params) (results)
 
-func (P *Parser) ParseFunctionType() *AST.FunctionType {
+func (P *Parser) ParseFunctionType() *Node.Type {
        P.Trace("FunctionType");
        
-       typ := new(AST.FunctionType);
-       typ.pos = P.pos;
-       typ.params = P.ParseParameters();
-       typ.result = P.ParseResult();
+       t := Node.NewType(P.pos, Scanner.LPAREN);
+       t.list = P.ParseParameters();
+       P.ParseResult();
        
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseMethodDecl() *AST.MethodDecl {
+func (P *Parser) ParseMethodDecl() *Node.Decl {
        P.Trace("MethodDecl");
        
-       decl := new(AST.MethodDecl);
-       decl.ident = P.ParseIdent();
-       decl.typ = P.ParseFunctionType();
+       P.ParseIdent();
+       P.ParseFunctionType();
        
        P.Ecart();
-       return decl;
+       return nil;
 }
 
 
-func (P *Parser) ParseInterfaceType() *AST.InterfaceType {
+func (P *Parser) ParseInterfaceType() *Node.Type {
        P.Trace("InterfaceType");
        
-       typ := new(AST.InterfaceType);
-       typ.pos = P.pos;
-       typ.methods = AST.NewList();
-       
+       t := Node.NewType(P.pos, Scanner.INTERFACE);
        P.Expect(Scanner.INTERFACE);
-       
        if P.tok == Scanner.LBRACE {
                P.Next();
                for P.tok == Scanner.IDENT {
-                       typ.methods.Add(P.ParseMethodDecl());
+                       P.ParseMethodDecl();
                        if P.tok != Scanner.RBRACE {
                                P.Expect(Scanner.SEMICOLON);
                        }
@@ -396,40 +366,35 @@ func (P *Parser) ParseInterfaceType() *AST.InterfaceType {
        }
 
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseMapType() *AST.MapType {
+func (P *Parser) ParseMapType() *Node.Type {
        P.Trace("MapType");
        
-       typ := new(AST.MapType);
-       typ.pos = P.pos;
-       
+       t := Node.NewType(P.pos, Scanner.MAP);
        P.Expect(Scanner.MAP);
        P.Expect(Scanner.LBRACK);
-       typ.key = P.ParseVarType();
+       t.key = P.ParseVarType();
        P.Expect(Scanner.RBRACK);
-       typ.val = P.ParseVarType();
+       t.elt = P.ParseVarType();
        
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParseStructType() *AST.StructType {
+func (P *Parser) ParseStructType() *Node.Type {
        P.Trace("StructType");
 
-       typ := new(AST.StructType);
-       typ.pos = P.pos;
-       typ.fields = AST.NewList();
-       
+       t := Node.NewType(P.pos, Scanner.STRUCT);
        P.Expect(Scanner.STRUCT);
-       
        if P.tok == Scanner.LBRACE {
                P.Next();
+               t.list = Node.NewList();
                for P.tok == Scanner.IDENT {
-                       typ.fields.Add(P.ParseVarDeclList());
+                       t.list.Add(P.ParseVarDeclList());
                        if P.tok != Scanner.RBRACE {
                                P.Expect(Scanner.SEMICOLON);
                        }
@@ -439,56 +404,52 @@ func (P *Parser) ParseStructType() *AST.StructType {
        }
 
        P.Ecart();
-       return typ;
+       return t;
 }
 
 
-func (P *Parser) ParsePointerType() *AST.PointerType {
+func (P *Parser) ParsePointerType() *Node.Type {
        P.Trace("PointerType");
        
-       typ := new(AST.PointerType);
-       typ.pos = P.pos;
-       
+       typ := Node.NewType(P.pos, Scanner.MUL);
        P.Expect(Scanner.MUL);
-       typ.base = P.ParseType();
+       typ.elt = P.ParseType();
        
        P.Ecart();
        return typ;
 }
 
 
-// Returns false if no type was found.
-func (P *Parser) TryType() (typ_ AST.Type, ok_ bool) {
+// Returns nil if no type was found.
+func (P *Parser) TryType() *Node.Type {
        P.Trace("Type (try)");
        
-       var typ AST.Type = AST.NIL;
-       found := true;
+       var t *Node.Type;
        switch P.tok {
-       case Scanner.IDENT: typ = P.ParseTypeName();
-       case Scanner.LBRACK: typ = P.ParseArrayType();
-       case Scanner.CHAN, Scanner.ARROW: typ = P.ParseChannelType();
-       case Scanner.INTERFACE: typ = P.ParseInterfaceType();
-       case Scanner.LPAREN: typ = P.ParseFunctionType();
-       case Scanner.MAP: typ = P.ParseMapType();
-       case Scanner.STRUCT: typ = P.ParseStructType();
-       case Scanner.MUL: typ = P.ParsePointerType();
-       default: found = false;
+       case Scanner.IDENT: t = P.ParseTypeName();
+       case Scanner.LBRACK: t = P.ParseArrayType();
+       case Scanner.CHAN, Scanner.ARROW: t = P.ParseChannelType();
+       case Scanner.INTERFACE: t = P.ParseInterfaceType();
+       case Scanner.LPAREN: t = P.ParseFunctionType();
+       case Scanner.MAP: t = P.ParseMapType();
+       case Scanner.STRUCT: t = P.ParseStructType();
+       case Scanner.MUL: t = P.ParsePointerType();
        }
 
        P.Ecart();
-       return typ, found;
+       return t;
 }
 
 
 // ----------------------------------------------------------------------------
 // Blocks
 
-func (P *Parser) ParseStatementList() *AST.List {
+func (P *Parser) ParseStatementList() *Node.List {
        P.Trace("StatementList");
        
-       stats := AST.NewList();
+       list := Node.NewList();
        for P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
-               stats.Add(P.ParseStatement());
+               list.Add(P.ParseStatement());
                if P.tok == Scanner.SEMICOLON {
                        P.Next();
                } else if P.opt_semi {
@@ -499,134 +460,95 @@ func (P *Parser) ParseStatementList() *AST.List {
        }
        
        P.Ecart();
-       return stats;
+       return list;
 }
 
 
-func (P *Parser) ParseBlock() *AST.Block {
+func (P *Parser) ParseBlock() *Node.List {
        P.Trace("Block");
        
-       block := new(AST.Block);
-       block.pos = P.pos;
-       
+       var s *Node.List;
        P.Expect(Scanner.LBRACE);
        if P.tok != Scanner.RBRACE {
-               block.stats = P.ParseStatementList();
+               s = P.ParseStatementList();
        }
-       P.OptSemicolon();
        P.Expect(Scanner.RBRACE);
        P.opt_semi = true;
        
        P.Ecart();
-       return block;
+       return s;
 }
 
 
 // ----------------------------------------------------------------------------
 // Expressions
 
-func (P *Parser) ParseExpressionList(list *AST.List) {
+// TODO: Make this non-recursive.
+func (P *Parser) ParseExpressionList() *Node.Expr {
        P.Trace("ExpressionList");
 
-       list.Add(P.ParseExpression());
-       for P.tok == Scanner.COMMA {
+       x := P.ParseExpression();
+       if P.tok == Scanner.COMMA {
+               pos := P.pos;
                P.Next();
-               list.Add(P.ParseExpression());
+               y := P.ParseExpressionList();
+               x = Node.NewExpr(pos, Scanner.COMMA, x, y);
        }
        
        P.Ecart();
+       return x;
 }
 
 
-func (P *Parser) ParseNewExpressionList() *AST.List {
-       list := AST.NewList();
-       P.ParseExpressionList(list);
-       return list;
-}
-
-
-func (P *Parser) ParseFunctionLit() *AST.FunctionLit {
+func (P *Parser) ParseFunctionLit() *Node.Expr {
        P.Trace("FunctionLit");
        
-       fun := new(AST.FunctionLit);
-       fun.pos = P.pos;
-       
        P.Expect(Scanner.FUNC);
-       fun.typ = P.ParseFunctionType();
+       P.ParseFunctionType();
        P.scope_lev++;
-       fun.body = P.ParseBlock();
+       P.ParseBlock();
        P.scope_lev--;
        
        P.Ecart();
-       return fun;
-}
-
-
-func (P *Parser) ParseExpressionPair() AST.Expr {
-       P.Trace("ExpressionPair");
-
-       p := new(AST.Pair);
-       p.x = P.ParseExpression();
-       p.pos = P.pos;
-       P.Expect(Scanner.COLON);
-       p.y = P.ParseExpression();
-       
-       P.Ecart();
-       return p;
-}
-
-
-func (P *Parser) ParseExpressionPairList(list *AST.List) {
-       P.Trace("ExpressionPairList");
-
-       list.Add(P.ParseExpressionPair());
-       for P.tok == Scanner.COMMA {
-               P.Next();
-               list.Add(P.ParseExpressionPair());
-       }
-       
-       P.Ecart();
+       return nil;
 }
 
 
-func (P *Parser) ParseOperand() AST.Expr {
+func (P *Parser) ParseOperand() *Node.Expr {
        P.Trace("Operand");
 
-       var op AST.Expr;
-
+       var x *Node.Expr;
        switch P.tok {
        case Scanner.IDENT:
-               op = P.ParseIdent();
+               x = P.ParseIdent();
                
        case Scanner.LPAREN:
                P.Next();
                P.expr_lev++;
-               op = P.ParseExpression();
+               x = P.ParseExpression();
                P.expr_lev--;
                P.Expect(Scanner.RPAREN);
 
        case Scanner.INT, Scanner.FLOAT:
-               lit := new(AST.Literal);
-               lit.pos, lit.tok, lit.val = P.pos, P.tok, P.val;
-               op = lit;
+               val := new(Node.Val);
+               val.s = P.val;
+               x = Node.NewVal(P.pos, P.tok, val);
                P.Next();
 
        case Scanner.STRING:
-               lit := new(AST.Literal);
-               lit.pos, lit.tok = P.pos, P.tok;
-               for P.tok == Scanner.STRING {
-                       lit.val += P.val;
-                       P.Next();
+               val := new(Node.Val);
+               val.s = P.val;
+               x = Node.NewVal(P.pos, Scanner.STRING, val);
+               for P.Next(); P.tok == Scanner.STRING; P.Next() {
+                       val.s += P.val;
                }
-               op = lit;
 
        case Scanner.FUNC:
-               op = P.ParseFunctionLit();
+               P.ParseFunctionLit();
                
        default:
-               typ, ok := P.TryType();
-               if ok {
-                       op = typ;
+               typ := P.TryType();
+               if typ != nil {
                        break;
                }
 
@@ -635,22 +557,19 @@ func (P *Parser) ParseOperand() AST.Expr {
        }
 
        P.Ecart();
-       return op;
+       return x;
 }
 
 
-func (P *Parser) ParseSelectorOrTypeGuard(x AST.Expr) AST.Expr {
+func (P *Parser) ParseSelectorOrTypeGuard(x *Node.Expr) *Node.Expr {
        P.Trace("SelectorOrTypeGuard");
 
        pos := P.pos;
        P.Expect(Scanner.PERIOD);
        
        if P.tok == Scanner.IDENT {
-               ident := P.ParseIdent();
-               
-               z := new(AST.Selector);
-               z.pos, z.x, z.field = pos, x, ident.val;
-               x = z;
+               y := P.ParseIdent();
+               x = Node.NewExpr(pos, Scanner.PERIOD, x, y);
                
        } else {
                P.Expect(Scanner.LPAREN);
@@ -663,99 +582,92 @@ func (P *Parser) ParseSelectorOrTypeGuard(x AST.Expr) AST.Expr {
 }
 
 
-func (P *Parser) ParseIndexOrSlice(x AST.Expr) AST.Expr {
+// mode = 0: single or pair accepted
+// mode = 1: single only accepted
+// mode = 2: pair only accepted
+func (P *Parser) ParseExpressionPair(mode int) *Node.Expr {
+       P.Trace("ExpressionPair");
+
+       x := P.ParseExpression();
+       if mode == 0 && P.tok == Scanner.COLON || mode == 2 {
+               pos := P.pos;
+               P.Expect(Scanner.COLON);
+               y := P.ParseExpression();
+               x = Node.NewExpr(pos, Scanner.COLON, x, y);
+       }
+
+       P.Ecart();
+       return x;
+}
+
+
+func (P *Parser) ParseIndex(x *Node.Expr) *Node.Expr {
        P.Trace("IndexOrSlice");
        
        pos := P.pos;
        P.Expect(Scanner.LBRACK);
-       i := P.ParseExpression();
-       if P.tok == Scanner.COLON {
-               P.Next();
-               j := P.ParseExpression();
-               // TODO: handle this case
-       }
+       i := P.ParseExpressionPair(0);
        P.Expect(Scanner.RBRACK);
-
-       z := new(AST.Index);
-       z.pos, z.x, z.index = pos, x, i;
        
        P.Ecart();
-       return z;
+       return Node.NewExpr(pos, Scanner.LBRACK, x, i);
 }
 
 
-func (P *Parser) ParseCall(x AST.Expr) *AST.Call {
+func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
        P.Trace("Call");
 
-       call := new(AST.Call);
-       call.pos = P.pos;
-       call.fun = x;
-       call.args = nil;
-       
+       x = Node.NewExpr(P.pos, Scanner.LPAREN, x, nil);
        P.Expect(Scanner.LPAREN);
        if P.tok != Scanner.RPAREN {
-               call.args = P.ParseNewExpressionList();
+               x.y = P.ParseExpressionList();
        }
        P.Expect(Scanner.RPAREN);
        
        P.Ecart();
-       return call;
+       return x;
 }
 
 
-func (P *Parser) ParseCompositeLit(typ AST.Type) AST.Expr {
+func (P *Parser) ParseCompositeLit() {
        P.Trace("CompositeLit");
-       
-       lit := new(AST.CompositeLit);
-       lit.pos = P.pos;
-       lit.typ = typ;
-       lit.vals = AST.NewList();
-       
+
+       mode := 0;
        P.Expect(Scanner.LBRACE);
-       if P.tok != Scanner.RBRACE {
-               x := P.ParseExpression();
-               if P.tok == Scanner.COMMA {
-                       P.Next();
-                       lit.vals.Add(x);
-                       if P.tok != Scanner.RBRACE {
-                               P.ParseExpressionList(lit.vals);
+       for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
+               x := P.ParseExpressionPair(mode);
+               if mode == 0 {
+                       // first expression determines mode
+                       if x.tok == Scanner.COLON {
+                               mode = 2;
+                       } else {
+                               mode = 1;
                        }
-               } else if P.tok == Scanner.COLON {
-                       p := new(AST.Pair);
-                       p.pos = P.pos;
-                       p.x = x;
+               }
+               if P.tok == Scanner.COMMA {
                        P.Next();
-                       p.y = P.ParseExpression();
-                       lit.vals.Add(p);
-                       if P.tok == Scanner.COMMA {
-                               P.Next();
-                               if P.tok != Scanner.RBRACE {
-                                       P.ParseExpressionPairList(lit.vals);
-                               }
-                       }
                } else {
-                       lit.vals.Add(x);
+                       break;
                }
        }
        P.Expect(Scanner.RBRACE);
-
+       
        P.Ecart();
-       return lit;
 }
 
 
-func (P *Parser) ParsePrimaryExpr() AST.Expr {
+func (P *Parser) ParsePrimaryExpr() *Node.Expr {
        P.Trace("PrimaryExpr");
        
        x := P.ParseOperand();
        for {
                switch P.tok {
                case Scanner.PERIOD: x = P.ParseSelectorOrTypeGuard(x);
-               case Scanner.LBRACK: x = P.ParseIndexOrSlice(x);
+               case Scanner.LBRACK: x = P.ParseIndex(x);
                case Scanner.LPAREN: x = P.ParseCall(x);
                case Scanner.LBRACE:
                        if P.expr_lev > 0 {
-                               x = P.ParseCompositeLit(x);
+                               P.ParseCompositeLit();
                        } else {
                                goto exit;
                        }
@@ -769,10 +681,10 @@ exit:
 }
 
 
-func (P *Parser) ParseUnaryExpr() AST.Expr {
+func (P *Parser) ParseUnaryExpr() *Node.Expr {
        P.Trace("UnaryExpr");
        
-       var x AST.Expr = AST.NIL;
+       var x *Node.Expr;
        switch P.tok {
        case
                Scanner.ADD, Scanner.SUB,
@@ -782,10 +694,7 @@ func (P *Parser) ParseUnaryExpr() AST.Expr {
                        pos, tok := P.pos, P.tok;
                        P.Next();
                        y := P.ParseUnaryExpr();
-
-                       z := new(AST.Unary);
-                       z.pos, z.tok, z.x = pos, tok, y;
-                       x = z;
+                       x = Node.NewExpr(pos, tok, nil, y);
                        
                default:
                        x = P.ParsePrimaryExpr();
@@ -796,7 +705,7 @@ func (P *Parser) ParseUnaryExpr() AST.Expr {
 }
 
 
-func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
+func (P *Parser) ParseBinaryExpr(prec1 int) *Node.Expr {
        P.Trace("BinaryExpr");
        
        x := P.ParseUnaryExpr();
@@ -805,10 +714,7 @@ func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
                        pos, tok := P.pos, P.tok;
                        P.Next();
                        y := P.ParseBinaryExpr(prec + 1);
-                       
-                       z := new(AST.Binary);
-                       z.pos, z.tok, z.x, z.y = pos, tok, x, y;
-                       x = z;
+                       x = Node.NewExpr(pos, tok, x, y);
                }
        }
        
@@ -817,7 +723,7 @@ func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
 }
 
 
-func (P *Parser) ParseExpression() AST.Expr {
+func (P *Parser) ParseExpression() *Node.Expr {
        P.Trace("Expression");
        indent := P.indent;
        
@@ -826,7 +732,6 @@ func (P *Parser) ParseExpression() AST.Expr {
        if indent != P.indent {
                panic("imbalanced tracing code (Expression)");
        }
-
        P.Ecart();
        return x;
 }
@@ -835,294 +740,268 @@ func (P *Parser) ParseExpression() AST.Expr {
 // ----------------------------------------------------------------------------
 // Statements
 
-func (P *Parser) ParseSimpleStat() AST.Stat {
+func (P *Parser) ParseSimpleStat() *Node.Stat {
        P.Trace("SimpleStat");
        
-       var stat AST.Stat = AST.NIL;
-       x := P.ParseNewExpressionList();
+       var s *Node.Stat;
+       list := P.ParseExpressionList();
        
        switch P.tok {
        case Scanner.COLON:
                // label declaration
-               l := new(AST.Label);
-               l.pos = P.pos;
-               if x.len() == 1 {
-                       l.ident = x.at(0);
+               if list.len() == 1 {
                } else {
                        P.Error(P.pos, "illegal label declaration");
-                       l.ident = AST.NIL;
                }
                P.Next();  // consume ":"
                P.opt_semi = true;
-               stat = l;
                
        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:
-               pos, tok := P.pos, P.tok;
+               s = Node.NewStat(P.pos, P.tok);
                P.Next();
-               y := P.ParseNewExpressionList();
-               a := new(AST.Assignment);
-               a.pos, a.tok, a.lhs, a.rhs = pos, tok, x, y;
-               stat = a;
-               
+               s.expr = P.ParseExpressionList();
+
        default:
                if P.tok == Scanner.INC || P.tok == Scanner.DEC {
-                       s := new(AST.IncDecStat);
-                       s.pos, s.tok = P.pos, P.tok;
-                       if x.len() == 1 {
-                               s.expr = x.at(0);
+                       s = Node.NewStat(P.pos, P.tok);
+                       if list.len() == 1 {
+                               s.expr = list;
                        } else {
                                P.Error(P.pos, "more then one operand");
                        }
                        P.Next();
-                       stat = s;
                } else {
-                       s := new(AST.ExprStat);
-                       if x != nil && x.len() > 0 {
-                               s.expr = x.at(0);
+                       s = Node.NewStat(P.pos, 0);  // TODO give this a token value
+                       if list.len() == 1 {
+                               s.expr = list;
                        } else {
-                               // this is a syntax error
-                               s.expr = AST.NIL;
+                               P.Error(P.pos, "syntax error");
                        }
-                       stat = s;
                }
        }
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseGoStat() *AST.GoStat {
+func (P *Parser) ParseGoStat() *Node.Stat {
        P.Trace("GoStat");
        
-       stat := new(AST.GoStat);
-       stat.pos = P.pos;
-       
+       s := Node.NewStat(P.pos, Scanner.GO);
        P.Expect(Scanner.GO);
-       stat.expr = P.ParseExpression();
+       s.expr = P.ParseExpression();
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseReturnStat() *AST.ReturnStat {
+func (P *Parser) ParseReturnStat() *Node.Stat {
        P.Trace("ReturnStat");
        
-       stat := new(AST.ReturnStat);
-       stat.pos = P.pos;
-       
+       s := Node.NewStat(P.pos, Scanner.RETURN);
        P.Expect(Scanner.RETURN);
        if P.tok != Scanner.SEMICOLON && P.tok != Scanner.RBRACE {
-               stat.res = P.ParseNewExpressionList();
+               s.expr = P.ParseExpressionList();
        }
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseControlFlowStat(tok int) *AST.ControlFlowStat {
+func (P *Parser) ParseControlFlowStat(tok int) *Node.Stat {
        P.Trace("ControlFlowStat");
        
-       stat := new(AST.ControlFlowStat);
-       stat.pos, stat.tok = P.pos, P.tok;
-       
+       s := Node.NewStat(P.pos, tok);
        P.Expect(tok);
        if P.tok == Scanner.IDENT {
-               stat.label = P.ParseIdent();
+               s.expr = P.ParseIdent();
        }
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseControlClause(keyword int) *AST.ControlClause {
+func (P *Parser) ParseControlClause(keyword int) *Node.Stat {
        P.Trace("StatHeader");
        
-       ctrl := new(AST.ControlClause);
-       ctrl.init, ctrl.expr, ctrl.post = AST.NIL, AST.NIL, AST.NIL;
-
+       s := Node.NewStat(P.pos, keyword);
        P.Expect(keyword);
        if P.tok != Scanner.LBRACE {
                prev_lev := P.expr_lev;
                P.expr_lev = 0;
                if P.tok != Scanner.SEMICOLON {
-                       ctrl.init = P.ParseSimpleStat();
-                       ctrl.has_init = true;
+                       s.init = P.ParseSimpleStat();
                }
                if P.tok == Scanner.SEMICOLON {
                        P.Next();
                        if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
-                               ctrl.expr = P.ParseExpression();
-                               ctrl.has_expr = true;
+                               s.expr = P.ParseExpression();
                        }
                        if keyword == Scanner.FOR {
                                P.Expect(Scanner.SEMICOLON);
                                if P.tok != Scanner.LBRACE {
-                                       ctrl.post = P.ParseSimpleStat();
-                                       ctrl.has_post = true;
+                                       s.post = P.ParseSimpleStat();
                                }
                        }
                } else {
-                       ctrl.expr, ctrl.has_expr = ctrl.init, ctrl.has_init;
-                       ctrl.init, ctrl.has_init = AST.NIL, false;
+                       if s.init != nil {  // guard in case of errors
+                               s.expr, s.init = s.init.expr, nil;
+                       }
                }
                P.expr_lev = prev_lev;
        }
 
        P.Ecart();
-       return ctrl;
+       return s;
 }
 
 
-func (P *Parser) ParseIfStat() *AST.IfStat {
+func (P *Parser) ParseIfStat() *Node.Stat {
        P.Trace("IfStat");
 
-       stat := new(AST.IfStat);
-       stat.pos = P.pos;
-       stat.ctrl = P.ParseControlClause(Scanner.IF);
-       stat.then = P.ParseBlock();
+       s := P.ParseControlClause(Scanner.IF);
+       s.block = P.ParseBlock();
        if P.tok == Scanner.ELSE {
                P.Next();
                if P.tok == Scanner.IF {
-                       stat.else_ = P.ParseIfStat();
+                       P.ParseIfStat();
                } else {
-                       // TODO: Should be P.ParseBlock().
-                       stat.else_ = P.ParseStatement();
+                       P.ParseStatement();
                }
-               stat.has_else = true;
        }
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseForStat() *AST.ForStat {
+func (P *Parser) ParseForStat() *Node.Stat {
        P.Trace("ForStat");
        
-       stat := new(AST.ForStat);
-       stat.pos = P.pos;
-       
-       stat.ctrl = P.ParseControlClause(Scanner.FOR);
-       stat.body = P.ParseBlock();
+       s := P.ParseControlClause(Scanner.FOR);
+       s.block = P.ParseBlock();
        
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseCase() *AST.CaseClause {
+func (P *Parser) ParseCase() *Node.Stat {
        P.Trace("Case");
        
-       clause := new(AST.CaseClause);
-       clause.pos = P.pos;
-       
+       s := Node.NewStat(P.pos, P.tok);
        if P.tok == Scanner.CASE {
                P.Next();
-               clause.exprs = P.ParseNewExpressionList();
+               s.expr = P.ParseExpressionList();
        } else {
                P.Expect(Scanner.DEFAULT);
        }
        P.Expect(Scanner.COLON);
        
        P.Ecart();
-       return clause;
+       return s;
 }
 
 
-func (P *Parser) ParseCaseClause() *AST.CaseClause {
+func (P *Parser) ParseCaseClause() *Node.Stat {
        P.Trace("CaseClause");
 
-       clause := P.ParseCase();
+       s := P.ParseCase();
        if P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE {
-               clause.stats = P.ParseStatementList();
+               s.block = P.ParseStatementList();
        }
        
        P.Ecart();
-       return clause;
+       return s;
 }
 
 
-func (P *Parser) ParseSwitchStat() *AST.SwitchStat {
+func (P *Parser) ParseSwitchStat() *Node.Stat {
        P.Trace("SwitchStat");
        
-       stat := new(AST.SwitchStat);
-       stat.pos = P.pos;
-       stat.ctrl = P.ParseControlClause(Scanner.SWITCH);
-       stat.cases = AST.NewList();
-       
+       s := P.ParseControlClause(Scanner.SWITCH);
+       s.block = Node.NewList();
        P.Expect(Scanner.LBRACE);
        for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
-               stat.cases.Add(P.ParseCaseClause());
+               s.block.Add(P.ParseCaseClause());
        }
        P.Expect(Scanner.RBRACE);
        P.opt_semi = true;
 
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
-func (P *Parser) ParseCommCase() {
-  P.Trace("CommCase");
-  
-  if P.tok == Scanner.CASE {
-       P.Next();
-       P.ParseExpression();
-       if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
+func (P *Parser) ParseCommCase() *Node.Stat {
+       P.Trace("CommCase");
+
+       s := Node.NewStat(P.pos, Scanner.CASE);
+       if P.tok == Scanner.CASE {
                P.Next();
-               P.Expect(Scanner.ARROW);
                P.ParseExpression();
+               if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
+                       P.Next();
+                       P.Expect(Scanner.ARROW);
+                       P.ParseExpression();
+               }
+       } else {
+               P.Expect(Scanner.DEFAULT);
        }
-  } else {
-       P.Expect(Scanner.DEFAULT);
-  }
-  P.Expect(Scanner.COLON);
-  
-  P.Ecart();
+       P.Expect(Scanner.COLON);
+
+       P.Ecart();
+       return s;
 }
 
 
-func (P *Parser) ParseCommClause() {
+func (P *Parser) ParseCommClause() *Node.Stat {
        P.Trace("CommClause");
        
-       P.ParseCommCase();
+       s := P.ParseCommCase();
        if P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE {
-               P.ParseStatementList();
+               s.block = P.ParseStatementList();
        }
        
        P.Ecart();
+       return s;
 }
 
 
-func (P *Parser) ParseSelectStat() {
+func (P *Parser) ParseSelectStat() *Node.Stat {
        P.Trace("SelectStat");
        
+       s := Node.NewStat(P.pos, Scanner.SELECT);
+       s.block = Node.NewList();
        P.Expect(Scanner.SELECT);
        P.Expect(Scanner.LBRACE);
        for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
-               P.ParseCommClause();
+               s.block.Add(P.ParseCommClause());
        }
        P.Expect(Scanner.RBRACE);
        P.opt_semi = true;
        
        P.Ecart();
+       return s;
 }
 
 
-func (P *Parser) ParseFallthroughStat() {
+func (P *Parser) ParseFallthroughStat() *Node.Stat {
        P.Trace("FallthroughStat");
        
+       s := Node.NewStat(P.pos, Scanner.FALLTHROUGH);
        P.Expect(Scanner.FALLTHROUGH);
 
        P.Ecart();
+       return s;
 }
 
 
@@ -1132,27 +1011,30 @@ func (P *Parser) ParseEmptyStat() {
 }
 
 
-func (P *Parser) ParseRangeStat() {
+func (P *Parser) ParseRangeStat() *Node.Stat {
        P.Trace("RangeStat");
        
+       s := Node.NewStat(P.pos, Scanner.RANGE);
        P.Expect(Scanner.RANGE);
        P.ParseIdentList();
        P.Expect(Scanner.DEFINE);
-       P.ParseExpression();
-       P.ParseBlock();
+       s.expr = P.ParseExpression();
+       s.block = P.ParseBlock();
        
-       P.Ecart();;
+       P.Ecart();
+       return s;
 }
 
 
-func (P *Parser) ParseStatement() AST.Stat {
+func (P *Parser) ParseStatement() *Node.Stat {
        P.Trace("Statement");
        indent := P.indent;
 
-       var stat AST.Stat = AST.NIL;
+       var s *Node.Stat;
        switch P.tok {
        case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
-               stat = P.ParseDeclaration();
+               s = Node.NewStat(P.pos, P.tok);
+               s.decl = P.ParseDeclaration();
        case Scanner.FUNC:
                // for now we do not allow local function declarations
                fallthrough;
@@ -1161,27 +1043,28 @@ 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
-               stat = P.ParseSimpleStat();
+               s = P.ParseSimpleStat();
        case Scanner.GO:
-               stat = P.ParseGoStat();
+               s = P.ParseGoStat();
        case Scanner.RETURN:
-               stat = P.ParseReturnStat();
+               s = P.ParseReturnStat();
        case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
-               stat = P.ParseControlFlowStat(P.tok);
+               s = P.ParseControlFlowStat(P.tok);
        case Scanner.LBRACE:
-               stat = P.ParseBlock();
+               s = Node.NewStat(P.pos, Scanner.LBRACE);
+               s.block = P.ParseBlock();
        case Scanner.IF:
-               stat = P.ParseIfStat();
+               s = P.ParseIfStat();
        case Scanner.FOR:
-               stat = P.ParseForStat();
+               s = P.ParseForStat();
        case Scanner.SWITCH:
-               stat = P.ParseSwitchStat();
+               s = P.ParseSwitchStat();
        case Scanner.RANGE:
-               P.ParseRangeStat();
+               s = P.ParseRangeStat();
        case Scanner.SELECT:
-               P.ParseSelectStat();
+               s = P.ParseSelectStat();
        case Scanner.FALLTHROUGH:
-               P.ParseFallthroughStat();
+               s = P.ParseFallthroughStat();
        default:
                P.ParseEmptyStat();  // for complete tracing output only
        }
@@ -1190,94 +1073,88 @@ func (P *Parser) ParseStatement() AST.Stat {
                panic("imbalanced tracing code (Statement)");
        }
        P.Ecart();
-       return stat;
+       return s;
 }
 
 
 // ----------------------------------------------------------------------------
 // Declarations
 
-func (P *Parser) ParseImportSpec() *AST.ImportDecl {
+func (P *Parser) ParseImportSpec() *Node.Decl {
        P.Trace("ImportSpec");
        
-       decl := new(AST.ImportDecl);
-
+       d := Node.NewDecl(P.pos, Scanner.IMPORT, false);
        if P.tok == Scanner.PERIOD {
                P.Error(P.pos, `"import ." not yet handled properly`);
                P.Next();
        } else if P.tok == Scanner.IDENT {
-               decl.ident = P.ParseIdent();
+               d.ident = P.ParseIdent();
        }
        
        if P.tok == Scanner.STRING {
                // TODO eventually the scanner should strip the quotes
-               decl.file = P.val;
                P.Next();
        } else {
                P.Expect(Scanner.STRING);  // use Expect() error handling
        }
        
        P.Ecart();
-       return decl;
+       return d;
 }
 
 
-func (P *Parser) ParseConstSpec(exported bool) *AST.ConstDecl {
+func (P *Parser) ParseConstSpec(exported bool) *Node.Decl {
        P.Trace("ConstSpec");
        
-       decl := new(AST.ConstDecl);
-       decl.ident = P.ParseIdent();
-       var ok bool;
-       decl.typ, ok = P.TryType();
-       decl.val = AST.NIL;
-       
+       d := Node.NewDecl(P.pos, Scanner.CONST, exported);
+       d.ident = P.ParseIdent();
+       d.typ = P.TryType();
        if P.tok == Scanner.ASSIGN {
                P.Next();
-               decl.val = P.ParseExpression();
+               d.val = P.ParseExpression();
        }
        
        P.Ecart();
-       return decl;
+       return d;
 }
 
 
-func (P *Parser) ParseTypeSpec(exported bool) *AST.TypeDecl {
+func (P *Parser) ParseTypeSpec(exported bool) *Node.Decl {
        P.Trace("TypeSpec");
 
-       decl := new(AST.TypeDecl);
-       decl.ident = P.ParseIdent();
-       decl.typ = P.ParseType();
+       d := Node.NewDecl(P.pos, Scanner.TYPE, exported);
+       d.ident = P.ParseIdent();
+       d.typ = P.ParseType();
        P.opt_semi = true;
        
        P.Ecart();
-       return decl;
+       return d;
 }
 
 
-func (P *Parser) ParseVarSpec(exported bool) *AST.VarDecl {
+func (P *Parser) ParseVarSpec(exported bool) *Node.Decl {
        P.Trace("VarSpec");
        
-       decl := new(AST.VarDecl);
-       decl.idents = P.ParseIdentList();
+       d := Node.NewDecl(P.pos, Scanner.VAR, exported);
+       P.ParseIdentList();
        if P.tok == Scanner.ASSIGN {
                P.Next();
-               decl.typ = AST.NIL;
-               decl.vals = P.ParseNewExpressionList();
+               P.ParseExpressionList();
        } else {
-               decl.typ = P.ParseVarType();
+               P.ParseVarType();
                if P.tok == Scanner.ASSIGN {
                        P.Next();
-                       decl.vals = P.ParseNewExpressionList();
+                       P.ParseExpressionList();
                }
        }
        
        P.Ecart();
-       return decl;
+       return d;
 }
 
 
 // TODO Replace this by using function pointers derived from methods.
-func (P *Parser) ParseSpec(exported bool, keyword int) AST.Decl {
+func (P *Parser) ParseSpec(exported bool, keyword int) *Node.Decl {
        switch keyword {
        case Scanner.IMPORT: return P.ParseImportSpec();
        case Scanner.CONST: return P.ParseConstSpec(exported);
@@ -1285,22 +1162,21 @@ func (P *Parser) ParseSpec(exported bool, keyword int) AST.Decl {
        case Scanner.VAR: return P.ParseVarSpec(exported);
        }
        panic("UNREACHABLE");
-       return AST.NIL;
+       return nil;
 }
 
 
-func (P *Parser) ParseDecl(exported bool, keyword int) *AST.Declaration {
+func (P *Parser) ParseDecl(exported bool, keyword int) *Node.Decl {
        P.Trace("Decl");
        
-       decl := new(AST.Declaration);
-       decl.decls = AST.NewList();
-       decl.pos, decl.tok = P.pos, P.tok;
-       
+       var d *Node.Decl;
        P.Expect(keyword);
        if P.tok == Scanner.LPAREN {
                P.Next();
+               d = Node.NewDecl(P.pos, keyword, exported);
+               d.list = Node.NewList();
                for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
-                       decl.decls.Add(P.ParseSpec(exported, keyword));
+                       d.list.Add(P.ParseSpec(exported, keyword));
                        if P.tok == Scanner.SEMICOLON {
                                P.Next();
                        } else {
@@ -1311,11 +1187,11 @@ func (P *Parser) ParseDecl(exported bool, keyword int) *AST.Declaration {
                P.opt_semi = true;
                
        } else {
-               decl.decls.Add(P.ParseSpec(exported, keyword));
+               d = P.ParseSpec(exported, keyword);
        }
        
        P.Ecart();
-       return decl;
+       return d;
 }
 
 
@@ -1328,39 +1204,37 @@ func (P *Parser) ParseDecl(exported bool, keyword int) *AST.Declaration {
 // func (recv) ident (params) type
 // func (recv) ident (params) (results)
 
-func (P *Parser) ParseFunctionDecl(exported bool) *AST.FuncDecl {
+func (P *Parser) ParseFunctionDecl(exported bool) *Node.Decl {
        P.Trace("FunctionDecl");
        
-       fun := new(AST.FuncDecl);
-       fun.pos = P.pos;
-
+       d := Node.NewDecl(P.pos, Scanner.FUNC, exported);
        P.Expect(Scanner.FUNC);
-
-       var recv *AST.VarDeclList;
        if P.tok == Scanner.LPAREN {
                pos := P.pos;
-               tmp := P.ParseParameters();
+               P.ParseParameters();
+               /*
                if tmp.len() > 0 {
-                       recv = tmp.at(0);
+                       //recv = tmp.at(0);
                }
+               */
+               /*
                if recv.idents.len() != 1 {
-                       P.Error(pos, "must have exactly one receiver");
+                       //P.Error(pos, "must have exactly one receiver");
                }
+               */
        }
        
-       fun.ident = P.ParseIdent();
-       fun.typ = P.ParseFunctionType();
-       fun.typ.recv = recv;
+       d.ident = P.ParseIdent();
+       d.typ = P.ParseFunctionType();
        
        if P.tok == Scanner.LBRACE {
                P.scope_lev++;
-               fun.body = P.ParseBlock();
+               d.list = P.ParseBlock();
                P.scope_lev--;
        }
        
        P.Ecart();
-       
-       return fun;
+       return d;
 }
 
 
@@ -1377,7 +1251,7 @@ func (P *Parser) ParseExportDecl() {
                has_paren = true;
        }
        for P.tok == Scanner.IDENT {
-               ident := P.ParseIdent();
+               P.ParseIdent();
                if P.tok == Scanner.COMMA {
                        P.Next();  // TODO this seems wrong
                }
@@ -1390,11 +1264,11 @@ func (P *Parser) ParseExportDecl() {
 }
 
 
-func (P *Parser) ParseDeclaration() AST.Node {
+func (P *Parser) ParseDeclaration() *Node.Decl {
        P.Trace("Declaration");
        indent := P.indent;
        
-       var node AST.Node;
+       var d *Node.Decl;
 
        exported := false;
        if P.tok == Scanner.EXPORT {
@@ -1408,9 +1282,9 @@ func (P *Parser) ParseDeclaration() AST.Node {
        
        switch P.tok {
        case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
-               node = P.ParseDecl(exported, P.tok);
+               d = P.ParseDecl(exported, P.tok);
        case Scanner.FUNC:
-               node = P.ParseFunctionDecl(exported);
+               d = P.ParseFunctionDecl(exported);
        case Scanner.EXPORT:
                if exported {
                        P.Error(P.pos, "cannot mark export declaration for export");
@@ -1430,34 +1304,31 @@ func (P *Parser) ParseDeclaration() AST.Node {
                panic("imbalanced tracing code (Declaration)");
        }
        P.Ecart();
-       return node;
+       return d;
 }
 
 
 // ----------------------------------------------------------------------------
 // Program
 
-func (P *Parser) ParseProgram() *AST.Program {
+func (P *Parser) ParseProgram() *Node.Program {
        P.Trace("Program");
        
-       pos := P.pos;
+       p := Node.NewProgram(P.pos);
        P.Expect(Scanner.PACKAGE);
-       ident := P.ParseIdent();
+       p.ident = P.ParseIdent();
        
-       decls := AST.NewList();
+       p.decls = Node.NewList();
        for P.tok == Scanner.IMPORT {
-               decls.Add(P.ParseDecl(false, Scanner.IMPORT));
+               p.decls.Add(P.ParseDecl(false, Scanner.IMPORT));
                P.OptSemicolon();
        }
                
        for P.tok != Scanner.EOF {
-               decls.Add(P.ParseDeclaration());
+               p.decls.Add(P.ParseDeclaration());
                P.OptSemicolon();
        }
        
        P.Ecart();
-       
-       x := new(AST.Program);
-       x.pos, x.ident, x.decls = pos, ident, decls;
-       return x;
+       return p;
 }
index ab52cfe56976718a917bc4992aa5cc820229b3b6..1dde21307914b14e3b379af0b6228cc5fc792274 100644 (file)
@@ -7,7 +7,6 @@ package main
 import Flag "flag"
 import Platform "platform"
 import Scanner "scanner"
-import AST "ast"  // should not be needed
 import Parser "parser"
 import Printer "printer"
 
@@ -66,7 +65,8 @@ func main() {
                }
                
                if !silent.BVal() {
-                       Printer.Print(prog);
+                       var P Printer.Printer;
+                       (&P).Program(prog);
                }
        }
 }
index e6db7ed39dc7d612f6f247623e77e48d6685d41d..1bd44fd168cee7fadff61f784e372daf597238a0 100644 (file)
@@ -5,11 +5,10 @@
 package Printer
 
 import Scanner "scanner"
-import AST "ast"
+import Node "node"
 
 
-// Printer implements AST.Visitor
-type Printer struct {
+export type Printer struct {
        level int;  // true scope level
        indent int;  // indentation level
        semi bool;  // pending ";"
@@ -57,302 +56,154 @@ func (P *Printer) CloseScope(paren string) {
 }
 
 
-func (P *Printer) Print(x AST.Node) {
-       outer := P.prec;
-       P.prec = 0;
-       x.Visit(P);
-       P.prec = outer;
-}
-
-
-func (P *Printer) PrintList(p *AST.List) {
-       for i := 0; i < p.len(); i++ {
-               if i > 0 {
-                       P.String(", ");
-               }
-               P.Print(p.at(i));
-       }
-}
-
-
-// ----------------------------------------------------------------------------
-// Basics
-
-func (P *Printer) DoNil(x *AST.Nil) {
-       P.String("<NIL>");
-}
-
-
-func (P *Printer) DoIdent(x *AST.Ident) {
-       P.String(x.val);
-}
-
-
 // ----------------------------------------------------------------------------
 // Types
 
-func (P *Printer) DoFunctionType(x *AST.FunctionType) {
-       P.String("(");
-       P.PrintList(x.params);
-       P.String(")");
-       if x.result != nil {
-               P.String(" (");
-               P.PrintList(x.result);
-               P.String(")");
-       }
-}
-
-
-func (P *Printer) DoArrayType(x *AST.ArrayType) {
-       P.String("[");
-       P.Print(x.len_);
-       P.String("] ");
-       P.Print(x.elt);
-}
-
-
-func (P *Printer) DoStructType(x *AST.StructType) {
-       P.String("struct ");
-       P.OpenScope("{");
-       for i := 0; i < x.fields.len(); i++ {
-               P.Print(x.fields.at(i));
-               P.newl, P.semi = true, true;
-       }
-       P.CloseScope("}");
-}
+func (P *Printer) Expr(x *Node.Expr)
 
+func (P *Printer) Type(t *Node.Type) {
+       switch t.tok {
+       case Scanner.IDENT:
+               P.Expr(t.expr);
 
-func (P *Printer) DoMapType(x *AST.MapType) {
-       P.String("[");
-       P.Print(x.key);
-       P.String("] ");
-       P.Print(x.val);
-}
+       case Scanner.LBRACK:
+               P.String("[");
+               if t.expr != nil {
+                       P.Expr(t.expr);
+               }
+               P.String("] ");
+               P.Type(t.elt);
+
+       case Scanner.STRUCT:
+               P.String("struct");
+               if t.list != nil {
+                       P.OpenScope(" {");
+                       /*
+                       for i := 0; i < x.fields.len(); i++ {
+                               P.Print(x.fields.at(i));
+                               P.newl, P.semi = true, true;
+                       }
+                       */
+                       P.CloseScope("}");
+               }
 
+       case Scanner.MAP:
+               P.String("[");
+               P.Type(t.key);
+               P.String("] ");
+               P.Type(t.elt);
+
+       case Scanner.CHAN:
+               switch t.mode {
+               case Node.FULL: P.String("chan ");
+               case Node.RECV: P.String("<-chan ");
+               case Node.SEND: P.String("chan <- ");
+               }
+               P.Type(t.elt);
+
+       case Scanner.INTERFACE:
+               P.String("interface");
+               if t.list != nil {
+                       P.OpenScope(" {");
+                       /*
+                       for i := 0; i < x.methods.len(); i++ {
+                               P.Print(x.methods.at(i));
+                               P.newl, P.semi = true, true;
+                       }
+                       */
+                       P.CloseScope("}");
+               }
 
-func (P *Printer) DoChannelType(x *AST.ChannelType) {
-       switch x.mode {
-       case AST.FULL: P.String("chan ");
-       case AST.RECV: P.String("<-chan ");
-       case AST.SEND: P.String("chan <- ");
-       }
-       P.Print(x.elt);
-}
+       case Scanner.MUL:
+               P.String("*");
+               P.Type(t.elt);
 
+       case Scanner.LPAREN:
+               P.String("(");
+               //P.PrintList(x.params);
+               P.String(")");
+               /*
+               if x.result != nil {
+                       P.String(" (");
+                       P.PrintList(x.result);
+                       P.String(")");
+               }
+               */
 
-func (P *Printer) DoInterfaceType(x *AST.InterfaceType) {
-       P.String("interface ");
-       P.OpenScope("{");
-       for i := 0; i < x.methods.len(); i++ {
-               P.Print(x.methods.at(i));
-               P.newl, P.semi = true, true;
+       default:
+               panic("UNREACHABLE");
        }
-       P.CloseScope("}");
-}
-
-
-func (P *Printer) DoPointerType(x *AST.PointerType) {
-       P.String("*");
-       P.Print(x.base);
 }
 
 
 // ----------------------------------------------------------------------------
-// Declarations
-
-func (P *Printer) DoBlock(x *AST.Block);
-
-
-func (P *Printer) DoImportDecl(x *AST.ImportDecl) {
-       if x.ident != nil {
-               P.Print(x.ident);
-               P.String(" ");
-       }
-       P.String(x.file);
-}
-
-
-func (P *Printer) DoConstDecl(x *AST.ConstDecl) {
-       P.Print(x.ident);
-       P.String(" ");
-       P.Print(x.typ);
-       P.String(" = ");
-       P.Print(x.val);
-       P.semi = true;
-}
-
+// Expressions
 
-func (P *Printer) DoTypeDecl(x *AST.TypeDecl) {
-       P.Print(x.ident);
-       P.String(" ");
-       P.Print(x.typ);
-       P.semi = true;
+func (P *Printer) Val(tok int, val *Node.Val) {
+       P.String(val.s);  // for now
 }
 
 
-func (P *Printer) DoVarDecl(x *AST.VarDecl) {
-       P.PrintList(x.idents);
-       P.String(" ");
-       P.Print(x.typ);
-       if x.vals != nil {
-               P.String(" = ");
-               P.PrintList(x.vals);
+func (P *Printer) Expr(x *Node.Expr) {
+       if x == nil {
+               return;  // empty expression list
        }
-       P.semi = true;
-}
-
 
-func (P *Printer) DoVarDeclList(x *AST.VarDeclList) {
-       if x.idents != nil {
-               P.PrintList(x.idents);  
-               P.String(" ");
-       }
-       P.Print(x.typ);
-}
+       switch x.tok {
+       case Scanner.IDENT:
+               P.String(x.ident);
 
+       case Scanner.INT, Scanner.STRING, Scanner.FLOAT:
+               P.Val(x.tok, x.val);
 
-func (P *Printer) DoFuncDecl(x *AST.FuncDecl) {
-       P.String("func ");
-       if x.typ.recv != nil {
+       case Scanner.LPAREN:
+               // calls
+               P.Expr(x.x);
                P.String("(");
-               P.DoVarDeclList(x.typ.recv);
-               P.String(") ");
-       }
-       P.DoIdent(x.ident);
-       P.DoFunctionType(x.typ);
-       if x.body != nil {
-               P.String(" ");
-               P.DoBlock(x.body);
-       } else {
-               P.String(" ;");
-       }
-       P.NewLine();
-       P.NewLine();
-}
-
-
-func (P *Printer) DoMethodDecl(x *AST.MethodDecl) {
-       P.DoIdent(x.ident);
-       P.DoFunctionType(x.typ);
-}
-
-
-func (P *Printer) DoDeclaration(x *AST.Declaration) {
-       P.String(Scanner.TokenName(x.tok));
-       P.String(" ");
-       switch x.decls.len() {
-       case 0:
-               P.String("()");
-       case 1:
-               P.Print(x.decls.at(0));
+               P.Expr(x.y);
+               P.String(")");
+               
+       case Scanner.LBRACK:
+               P.Expr(x.x);
+               P.String("[");
+               P.Expr(x.y);
+               P.String("]");
+               
        default:
-               P.OpenScope(" (");
-               for i := 0; i < x.decls.len(); i++ {
-                       P.Print(x.decls.at(i));
-                       P.newl, P.semi = true, true;
+               if x.x == nil {
+                       // unary expression
+                       P.String(Scanner.TokenName(x.tok));
+                       P.Expr(x.y);
+               } else {
+                       // binary expression: print ()'s if necessary
+                       // TODO: pass precedence as parameter instead
+                       outer := P.prec;
+                       P.prec = Scanner.Precedence(x.tok);
+                       if P.prec < outer {
+                               print("(");
+                       }
+                       P.Expr(x.x);
+                       if x.tok != Scanner.PERIOD && x.tok != Scanner.COMMA {
+                               P.String(" ");
+                       }
+                       P.String(Scanner.TokenName(x.tok));
+                       if x.tok != Scanner.PERIOD {
+                               P.String(" ");
+                       }
+                       P.Expr(x.y);
+                       if P.prec < outer {
+                               print(")");
+                       }
+                       P.prec = outer; 
                }
-               P.CloseScope(")");
-       }
-       if P.level == 0 {
-               P.NewLine();
-       }
-       P.newl = true;
-}
-
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-func (P *Printer) DoBinary(x *AST.Binary) {
-       outer := P.prec;
-       P.prec = Scanner.Precedence(x.tok);
-       
-       if P.prec < outer {
-               print("(");
-       }
-       
-       P.Print(x.x);
-       P.String(" " + Scanner.TokenName(x.tok) + " ");
-       P.Print(x.y);
-       
-       if P.prec < outer {
-               print(")");
        }
-
-       P.prec = outer; 
-}
-
-
-func (P *Printer) DoUnary(x *AST.Unary) {
-       P.String(Scanner.TokenName(x.tok));
-       P.Print(x.x);
-}
-
-
-func (P *Printer) DoLiteral(x *AST.Literal) {
-       P.String(x.val);
-}
-
-
-func (P *Printer) DoPair(x *AST.Pair) {
-       P.Print(x.x);
-       P.String(" : ");
-       P.Print(x.y);
-}
-
-
-func (P *Printer) DoIndex(x *AST.Index) {
-       P.Print(x.x);
-       P.String("[");
-       P.Print(x.index);
-       P.String("]");
-}
-
-
-func (P *Printer) DoCall(x *AST.Call) {
-       P.Print(x.fun);
-       P.String("(");
-       P.PrintList(x.args);
-       P.String(")");
-}
-
-
-func (P *Printer) DoSelector(x *AST.Selector) {
-       P.Print(x.x);
-       P.String(".");
-       P.String(x.field);
-}
-
-
-func (P *Printer) DoCompositeLit(x *AST.CompositeLit) {
-       P.Print(x.typ);
-       P.String("{");
-       P.PrintList(x.vals);
-       P.String("}");
-}
-
-
-func (P *Printer) DoFunctionLit(x *AST.FunctionLit) {
-       P.String("func ");
-       P.Print(x.typ);
-       P.String(" ");
-       P.Print(x.body);
 }
 
 
 // ----------------------------------------------------------------------------
 // Statements
 
-func (P *Printer) DoBlock(x *AST.Block) {
-       P.OpenScope("{");
-       for i := 0; i < x.stats.len(); i++ {
-               P.Print(x.stats.at(i));
-               P.newl = true;
-       }
-       P.CloseScope("}");
-}
-
-
+/*
 func (P *Printer) DoLabel(x *AST.Label) {
        P.indent--;
        P.newl = true;
@@ -376,133 +227,218 @@ func (P *Printer) DoAssignment(x *AST.Assignment) {
 }
 
 
-func (P *Printer) PrintControlClause(x *AST.ControlClause) {
-       if x.has_init {
+func (P *Printer) DoIfStat(x *AST.IfStat) {
+       P.String("if");
+       P.PrintControlClause(x.ctrl);
+       P.DoBlock(x.then);
+       if x.has_else {
+               P.newl = false;
+               P.String(" else ");
+               P.Print(x.else_);
+       }
+}
+*/
+
+
+func (P *Printer) Stat(s *Node.Stat)
+
+func (P *Printer) StatementList(list *Node.List) {
+       for i, n := 0, list.len(); i < n; i++ {
+               P.Stat(list.at(i).(*Node.Stat));
+               P.newl = true;
+       }
+}
+
+
+func (P *Printer) Block(list *Node.List) {
+       P.OpenScope("{");
+       P.StatementList(list);
+       P.CloseScope("}");
+}
+
+
+func (P *Printer) ControlClause(s *Node.Stat) {
+       if s.init != nil {
                P.String(" ");
-               P.Print(x.init);
+               P.Stat(s.init);
                P.semi = true;
                P.String("");
        }
-       if x.has_expr {
+       if s.expr != nil {
                P.String(" ");
-               P.Print(x.expr);
+               P.Expr(s.expr);
                P.semi = false;
        }
-       if x.has_post {
+       if s.post != nil {
                P.semi = true;
                P.String(" ");
-               P.Print(x.post);
+               P.Stat(s.post);
                P.semi = false;
        }
        P.String(" ");
 }
 
 
-func (P *Printer) DoIfStat(x *AST.IfStat) {
-       P.String("if");
-       P.PrintControlClause(x.ctrl);
-       P.DoBlock(x.then);
-       if x.has_else {
-               P.newl = false;
-               P.String(" else ");
-               P.Print(x.else_);
+func (P *Printer) Declaration(d *Node.Decl);
+
+func (P *Printer) Stat(s *Node.Stat) {
+       if s == nil {  // TODO remove this check
+               P.String("<nil stat>");
+               return;
        }
-}
+       switch s.tok {
+       case 0: // TODO use a real token const
+               P.Expr(s.expr);
+               P.semi = true;
 
+       case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
+               P.Declaration(s.decl);
 
-func (P *Printer) DoForStat(x *AST.ForStat) {
-       P.String("for");
-       P.PrintControlClause(x.ctrl);
-       P.DoBlock(x.body);
-}
+       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:
+               P.String(Scanner.TokenName(s.tok));
+               P.String(" ");
+               P.Expr(s.expr);
+               P.semi = true;
 
+       case Scanner.INC, Scanner.DEC:
+               P.Expr(s.expr);
+               P.String(Scanner.TokenName(s.tok));
+               P.semi = true;
 
-func (P *Printer) DoCaseClause(x *AST.CaseClause) {
-       if x.exprs != nil {
-               P.String("case ");
-               P.PrintList(x.exprs);
+       case Scanner.IF, Scanner.FOR, Scanner.SWITCH, Scanner.SELECT:
+               P.String(Scanner.TokenName(s.tok));
+               P.ControlClause(s);
+               P.Block(s.block);
+               
+       case Scanner.CASE, Scanner.DEFAULT:
+               P.String(Scanner.TokenName(s.tok));
+               if s.expr != nil {
+                       P.String(" ");
+                       P.Expr(s.expr);
+               }
                P.String(":");
-       } else {
-               P.String("default:");
-       }
-       
-       P.OpenScope("");
-       for i := 0; i < x.stats.len(); i++ {
-               P.Print(x.stats.at(i));
-               P.newl = true;
-       }
-       if x.falls {
-               P.String("fallthrough");
+               P.OpenScope("");
+               P.StatementList(s.block);
+               P.CloseScope("");
+               
+       case Scanner.GO, Scanner.RETURN, Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
+               P.String("go ");
+               P.Expr(s.expr);
+               P.semi = true;
+
+       default:
+               P.String("<stat>");
+               P.semi = true;
        }
-       P.CloseScope("");
 }
 
 
-func (P *Printer) DoSwitchStat(x *AST.SwitchStat) {
-       P.String("switch ");
-       P.PrintControlClause(x.ctrl);
-       P.OpenScope("{");
-       P.indent--;
-       for i := 0; i < x.cases.len(); i++ {
-               P.Print(x.cases.at(i));
+// ----------------------------------------------------------------------------
+// Declarations
+
+
+/*
+func (P *Printer) DoImportDecl(x *AST.ImportDecl) {
+       if x.ident != nil {
+               P.Print(x.ident);
+               P.String(" ");
        }
-       P.indent++;
-       P.CloseScope("}");
+       P.String(x.file);
 }
 
 
-func (P *Printer) DoReturnStat(x *AST.ReturnStat) {
-       P.String("return ");
-       P.PrintList(x.res);
-       P.semi = true;
+func (P *Printer) DoFuncDecl(x *AST.FuncDecl) {
+       P.String("func ");
+       if x.typ.recv != nil {
+               P.String("(");
+               P.DoVarDeclList(x.typ.recv);
+               P.String(") ");
+       }
+       P.DoIdent(x.ident);
+       P.DoFunctionType(x.typ);
+       if x.body != nil {
+               P.String(" ");
+               P.DoBlock(x.body);
+       } else {
+               P.String(" ;");
+       }
+       P.NewLine();
+       P.NewLine();
+
 }
 
 
-func (P *Printer) DoIncDecStat(x *AST.IncDecStat) {
-       P.Print(x.expr);
-       P.String(Scanner.TokenName(x.tok));
-       P.semi = true;
+func (P *Printer) DoMethodDecl(x *AST.MethodDecl) {
+       //P.DoIdent(x.ident);
+       //P.DoFunctionType(x.typ);
 }
+*/
 
 
-func (P *Printer) DoControlFlowStat(x *AST.ControlFlowStat) {
-       P.String(Scanner.TokenName(x.tok));
-       if x.label != nil {
+func (P *Printer) Declaration(d *Node.Decl) {
+       if d.tok == Scanner.FUNC || d.ident == nil {
+               if d.exported {
+                       P.String("export ");
+               }
+               P.String(Scanner.TokenName(d.tok));
                P.String(" ");
-               P.Print(x.label);
        }
-       P.semi = true;
-}
 
+       if d.ident == nil {
+               switch d.list.len() {
+               case 0:
+                       P.String("()");
+               case 1:
+                       P.Declaration(d.list.at(0).(*Node.Decl));
+               default:
+                       P.OpenScope("(");
+                       for i := 0; i < d.list.len(); i++ {
+                               P.Declaration(d.list.at(i).(*Node.Decl));
+                               P.newl, P.semi = true, true;
+                       }
+                       P.CloseScope(")");
+               }
 
-func (P *Printer) DoGoStat(x *AST.GoStat) {
-       P.String("go ");
-       P.Print(x.expr);
-       P.semi = true;
+       } else {
+               P.Expr(d.ident);
+               if d.typ != nil {
+                       P.String(" ");
+                       P.Type(d.typ);
+               }
+               if d.val != nil {
+                       P.String(" = ");
+                       P.Expr(d.val);
+               }
+               if d.list != nil {
+                       if d.tok != Scanner.FUNC {
+                               panic("must be a func declaration");
+                       }
+                       P.String(" ");
+                       P.Block(d.list);
+               }
+       }
+
+       if P.level == 0 {
+               P.NewLine();
+       }
+
+       P.newl = true;
 }
 
 
 // ----------------------------------------------------------------------------
 // Program
 
-func (P *Printer) DoProgram(x *AST.Program) {
+func (P *Printer) Program(p *Node.Program) {
        P.String("package ");
-       P.DoIdent(x.ident);
+       P.Expr(p.ident);
        P.NewLine();
-       for i := 0; i < x.decls.len(); i++ {
-               P.Print(x.decls.at(i));
+       for i := 0; i < p.decls.len(); i++ {
+               P.Declaration(p.decls.at(i));
        }
        P.newl = true;
        P.String("");
 }
-
-
-// ----------------------------------------------------------------------------
-// Driver
-
-export func Print(x AST.Node) {
-       var P Printer;
-       (&P).Print(x);
-       print("\n");
-}
-