+++ /dev/null
-// 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); }
package Parser
import Scanner "scanner"
-import AST "ast"
+import Node "node"
export type Parser struct {
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");
// ----------------------------------------------------------------------------
// 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 {
}
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();
}
-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");
}
}
-func (P *Parser) ParseVarType() AST.Type {
+func (P *Parser) ParseVarType() *Node.Type {
P.Trace("VarType");
typ := P.ParseType();
}
-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();
}
-// 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();
}
-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;
}
// (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);
}
}
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);
}
}
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 {
}
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;
}
}
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);
}
-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;
}
}
-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,
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();
}
-func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
+func (P *Parser) ParseBinaryExpr(prec1 int) *Node.Expr {
P.Trace("BinaryExpr");
x := P.ParseUnaryExpr();
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);
}
}
}
-func (P *Parser) ParseExpression() AST.Expr {
+func (P *Parser) ParseExpression() *Node.Expr {
P.Trace("Expression");
indent := P.indent;
if indent != P.indent {
panic("imbalanced tracing code (Expression)");
}
-
P.Ecart();
return x;
}
// ----------------------------------------------------------------------------
// 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;
}
}
-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;
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
}
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);
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 {
P.opt_semi = true;
} else {
- decl.decls.Add(P.ParseSpec(exported, keyword));
+ d = P.ParseSpec(exported, keyword);
}
P.Ecart();
- return decl;
+ return d;
}
// 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;
}
has_paren = true;
}
for P.tok == Scanner.IDENT {
- ident := P.ParseIdent();
+ P.ParseIdent();
if P.tok == Scanner.COMMA {
P.Next(); // TODO this seems wrong
}
}
-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 {
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");
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;
}
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 ";"
}
-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;
}
-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");
-}
-