From 7c3a2c47b06fbe7b87055236af1b16675aa35611 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 14 Oct 2008 18:14:01 -0700 Subject: [PATCH] - snapshot of pretty printer work - 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 | 6 +- usr/gri/pretty/ast.go | 525 ----------------------- usr/gri/pretty/node.go | 248 +++++++++++ usr/gri/pretty/parser.go | 849 ++++++++++++++++---------------------- usr/gri/pretty/pretty.go | 4 +- usr/gri/pretty/printer.go | 628 +++++++++++++--------------- 6 files changed, 897 insertions(+), 1363 deletions(-) delete mode 100644 usr/gri/pretty/ast.go create mode 100644 usr/gri/pretty/node.go diff --git a/usr/gri/pretty/Makefile b/usr/gri/pretty/Makefile index 0ef3e40251..d1d2c277b2 100644 --- a/usr/gri/pretty/Makefile +++ b/usr/gri/pretty/Makefile @@ -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 index cd31f3f21a..0000000000 --- a/usr/gri/pretty/ast.go +++ /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 index 0000000000..93f646b530 --- /dev/null +++ b/usr/gri/pretty/node.go @@ -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; +} diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go index ba033ce401..4dcacdc16f 100644 --- a/usr/gri/pretty/parser.go +++ b/usr/gri/pretty/parser.go @@ -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; } diff --git a/usr/gri/pretty/pretty.go b/usr/gri/pretty/pretty.go index ab52cfe569..1dde213079 100644 --- a/usr/gri/pretty/pretty.go +++ b/usr/gri/pretty/pretty.go @@ -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); } } } diff --git a/usr/gri/pretty/printer.go b/usr/gri/pretty/printer.go index e6db7ed39d..1bd44fd168 100644 --- a/usr/gri/pretty/printer.go +++ b/usr/gri/pretty/printer.go @@ -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(""); -} - - -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(""); + 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(""); + 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"); -} - -- 2.50.0