test: pretty
pretty -s *.go
pretty -s ../gosrc/*.go
- pretty -s $(GOROOT)/test/*.go
+ #pretty -s $(GOROOT)/test/*.go # contains incorrect programs
+ pretty -s $(GOROOT)/test/235.go
+ pretty -s $(GOROOT)/test/args.go
+ pretty -s $(GOROOT)/test/bufiolib.go
+ pretty -s $(GOROOT)/test/char_lit.go
+ pretty -s $(GOROOT)/test/complit.go
+ pretty -s $(GOROOT)/test/const.go
+ pretty -s $(GOROOT)/test/dialgoogle.go
+ pretty -s $(GOROOT)/test/empty.go
+ pretty -s $(GOROOT)/test/env.go
+ pretty -s $(GOROOT)/test/float_lit.go
+ pretty -s $(GOROOT)/test/fmt_test.go
+ pretty -s $(GOROOT)/test/for.go
+ pretty -s $(GOROOT)/test/func.go
+ pretty -s $(GOROOT)/test/func1.go
+ pretty -s $(GOROOT)/test/func2.go
pretty -s $(GOROOT)/src/pkg/*.go
pretty -s $(GOROOT)/src/lib/*.go
pretty -s $(GOROOT)/src/lib/*/*.go
import Scanner "scanner"
-type Node interface {}
type (
+ Node interface {};
Type struct;
Expr struct;
Stat struct;
}
-/*
-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];
// 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
+ s string; // identifiers and literals
+ t *Type; // declarations and composite literals
}
}
-/*
-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;
}
-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 {
+export func NewLit(pos, tok int, s string) *Expr {
e := new(Expr);
- e.pos, e.tok, e.val = pos, tok, val;
+ e.pos, e.tok, e.s = pos, tok, s;
return e;
}
export type Stat struct {
pos, tok int;
- init *Stat;
- expr *Expr;
- post *Stat;
+ init, post *Stat;
+ lhs, expr *Expr;
block *List;
decl *Decl;
}
// ----------------------------------------------------------------------------
// Declarations
-export type VarDeclList struct {
-}
-
-
-func (d *VarDeclList) Print() {
-}
-
-
export type Decl struct {
pos, tok int;
exported bool;
P.opt_semi = false;
if P.verbose {
P.PrintIndent();
- print("[", P.pos, "] ", Scanner.TokenName(P.tok), "\n");
+ print("[", P.pos, "] ", Scanner.TokenString(P.tok), "\n");
}
}
func (P *Parser) Expect(tok int) {
if P.tok != tok {
- P.Error(P.pos, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
+ P.Error(P.pos, "expected '" + Scanner.TokenString(tok) + "', found '" + Scanner.TokenString(P.tok) + "'");
}
P.Next(); // make progress in any case
}
var x *Node.Expr;
if P.tok == Scanner.IDENT {
- x = Node.NewIdent(P.pos, P.val);
+ x = Node.NewLit(P.pos, Scanner.IDENT, P.val);
if P.verbose {
P.PrintIndent();
- print("Ident = \"", x.val, "\"\n");
+ print("Ident = \"", x.s, "\"\n");
}
P.Next();
} else {
}
-func (P *Parser) ParseVarDeclList() *Node.VarDeclList {
+func (P *Parser) ParseVarDeclList() {
P.Trace("VarDeclList");
- list := new(Node.VarDeclList);
- P.ParseType();
+ list := Node.NewList();
+ list.Add(P.ParseType());
for P.tok == Scanner.COMMA {
P.Next();
- P.ParseType();
+ list.Add(P.ParseType());
}
-
+
typ := P.TryType();
- if typ == nil {
- // we must have a list of types
+ if typ != nil {
+ // all list entries must be identifiers;
+ // convert the list into an expression list of identifiers
+ for i, n := 0, list.len(); i < n; i++ {
+ t := list.at(i).(*Node.Type);
+ if t.tok == Scanner.IDENT && t.expr.tok == Scanner.IDENT {
+ x := t.expr;
+ } else {
+ P.Error(t.pos, "identifier expected");
+ }
+ }
+ } else {
+ // all list entries are types
+
}
P.Ecart();
- return list;
}
P.Trace("ParameterList");
list := Node.NewList();
- list.Add(P.ParseVarDeclList());
+ P.ParseVarDeclList();
for P.tok == Scanner.COMMA {
P.Next();
- list.Add(P.ParseVarDeclList());
+ P.ParseVarDeclList();
}
P.Ecart();
P.Next();
t.list = Node.NewList();
for P.tok == Scanner.IDENT {
- t.list.Add(P.ParseVarDeclList());
+ P.ParseVarDeclList();
if P.tok != Scanner.RBRACE {
P.Expect(Scanner.SEMICOLON);
}
P.expr_lev--;
P.Expect(Scanner.RPAREN);
- case Scanner.INT, Scanner.FLOAT:
- val := new(Node.Val);
- val.s = P.val;
- x = Node.NewVal(P.pos, P.tok, val);
+ case Scanner.INT, Scanner.FLOAT, Scanner.STRING:
+ x = Node.NewLit(P.pos, P.tok, P.val);
P.Next();
-
- case Scanner.STRING:
- 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;
+ if x.tok == Scanner.STRING {
+ for ; P.tok == Scanner.STRING; P.Next() {
+ x.s += P.val;
+ }
}
case Scanner.FUNC:
P.Trace("SimpleStat");
var s *Node.Stat;
- list := P.ParseExpressionList();
+ x := P.ParseExpressionList();
switch P.tok {
case Scanner.COLON:
// label declaration
- if list.len() == 1 {
+ if x.len() == 1 {
} else {
P.Error(P.pos, "illegal label declaration");
}
Scanner.XOR_ASSIGN, Scanner.SHL_ASSIGN, Scanner.SHR_ASSIGN:
s = Node.NewStat(P.pos, P.tok);
P.Next();
+ s.lhs = x;
s.expr = P.ParseExpressionList();
default:
if P.tok == Scanner.INC || P.tok == Scanner.DEC {
s = Node.NewStat(P.pos, P.tok);
- if list.len() == 1 {
- s.expr = list;
+ if x.len() == 1 {
+ s.expr = x;
} else {
P.Error(P.pos, "more then one operand");
}
P.Next();
} else {
s = Node.NewStat(P.pos, 0); // TODO give this a token value
- if list.len() == 1 {
- s.expr = list;
+ if x.len() == 1 {
+ s.expr = x;
} else {
P.Error(P.pos, "syntax error");
}
func (P *Parser) ParseControlClause(keyword int) *Node.Stat {
- P.Trace("StatHeader");
+ P.Trace("ControlClause");
s := Node.NewStat(P.pos, keyword);
P.Expect(keyword);
if P.tok == Scanner.ELSE {
P.Next();
if P.tok == Scanner.IF {
- P.ParseIfStat();
+ s.post = P.ParseIfStat();
} else {
- P.ParseStatement();
+ s.post = P.ParseStatement();
}
}
}
-func (P *Parser) ParseEmptyStat() {
- P.Trace("EmptyStat");
- P.Ecart();
-}
-
-
func (P *Parser) ParseRangeStat() *Node.Stat {
P.Trace("RangeStat");
}
+func (P *Parser) ParseEmptyStat() {
+ P.Trace("EmptyStat");
+ P.Ecart();
+}
+
+
func (P *Parser) ParseStatement() *Node.Stat {
P.Trace("Statement");
indent := P.indent;
indent int; // indentation level
semi bool; // pending ";"
newl bool; // pending "\n"
- prec int; // operator precedence
}
}
+func (P *Printer) Token(tok int) {
+ P.String(Scanner.TokenString(tok));
+}
+
+
func (P *Printer) NewLine() { // explicit "\n"
print("\n");
P.semi, P.newl = false, true;
// ----------------------------------------------------------------------------
// Expressions
-func (P *Printer) Val(tok int, val *Node.Val) {
- P.String(val.s); // for now
-}
-
-
-func (P *Printer) Expr(x *Node.Expr) {
+func (P *Printer) Expr1(x *Node.Expr, prec1 int) {
if x == nil {
return; // empty expression list
}
switch x.tok {
- case Scanner.IDENT:
- P.String(x.ident);
-
- case Scanner.INT, Scanner.STRING, Scanner.FLOAT:
- P.Val(x.tok, x.val);
-
- case Scanner.LPAREN:
- // calls
- P.Expr(x.x);
- P.String("(");
- P.Expr(x.y);
- P.String(")");
+ case Scanner.IDENT, Scanner.INT, Scanner.STRING, Scanner.FLOAT:
+ P.String(x.s);
+
+ case Scanner.COMMA:
+ P.Expr1(x.x, 0);
+ P.String(", ");
+ P.Expr1(x.y, 0);
+
+ case Scanner.PERIOD:
+ P.Expr1(x.x, 8);
+ P.String(".");
+ P.Expr1(x.y, 8);
case Scanner.LBRACK:
- P.Expr(x.x);
+ P.Expr1(x.x, 8);
P.String("[");
- P.Expr(x.y);
+ P.Expr1(x.y, 0);
P.String("]");
+
+ case Scanner.LPAREN:
+ P.Expr1(x.x, 8);
+ P.String("(");
+ P.Expr1(x.y, 0);
+ P.String(")");
default:
if x.x == nil {
// unary expression
- P.String(Scanner.TokenName(x.tok));
- P.Expr(x.y);
+ P.Token(x.tok);
+ P.Expr1(x.y, 7);
} 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 {
+ prec := Scanner.Precedence(x.tok);
+ if prec < prec1 {
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 {
+ P.Expr1(x.x, prec);
+ P.String(" ");
+ P.Token(x.tok);
+ P.String(" ");
+ P.Expr1(x.y, prec);
+ if prec < prec1 {
print(")");
}
- P.prec = outer;
}
}
}
-// ----------------------------------------------------------------------------
-// Statements
-
-/*
-func (P *Printer) DoLabel(x *AST.Label) {
- P.indent--;
- P.newl = true;
- P.Print(x.ident);
- P.String(":");
- P.indent++;
-}
-
-
-func (P *Printer) DoExprStat(x *AST.ExprStat) {
- P.Print(x.expr);
- P.semi = true;
-}
-
-
-func (P *Printer) DoAssignment(x *AST.Assignment) {
- P.PrintList(x.lhs);
- P.String(" " + Scanner.TokenName(x.tok) + " ");
- P.PrintList(x.rhs);
- P.semi = true;
+func (P *Printer) Expr(x *Node.Expr) {
+ P.Expr1(x, 0);
}
-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_);
- }
-}
-*/
-
+// ----------------------------------------------------------------------------
+// Statements
func (P *Printer) Stat(s *Node.Stat)
}
-func (P *Printer) Block(list *Node.List) {
+func (P *Printer) Block(list *Node.List, indent bool) {
P.OpenScope("{");
+ if !indent {
+ P.indent--;
+ }
P.StatementList(list);
+ if !indent {
+ P.indent++;
+ }
P.CloseScope("}");
}
P.Expr(s.expr);
P.semi = false;
}
- if s.post != nil {
+ if s.tok == Scanner.FOR && s.post != nil {
P.semi = true;
P.String(" ");
P.Stat(s.post);
P.String("<nil stat>");
return;
}
+
switch s.tok {
case 0: // TODO use a real token const
P.Expr(s.expr);
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.Expr(s.lhs);
+ P.String(" ");
+ P.Token(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.Token(s.tok);
P.semi = true;
- case Scanner.IF, Scanner.FOR, Scanner.SWITCH, Scanner.SELECT:
- P.String(Scanner.TokenName(s.tok));
+ case Scanner.LBRACE:
+ P.Block(s.block, true);
+
+ case Scanner.IF:
+ P.String("if");
P.ControlClause(s);
- P.Block(s.block);
-
+ P.Block(s.block, true);
+ if s.post != nil {
+ P.newl = false;
+ P.String(" else ");
+ P.Stat(s.post);
+ }
+
+ case Scanner.FOR:
+ P.String("for");
+ P.ControlClause(s);
+ P.Block(s.block, true);
+
+ case Scanner.SWITCH, Scanner.SELECT:
+ P.Token(s.tok);
+ P.ControlClause(s);
+ P.Block(s.block, false);
+
case Scanner.CASE, Scanner.DEFAULT:
- P.String(Scanner.TokenName(s.tok));
+ P.Token(s.tok);
if s.expr != nil {
P.String(" ");
P.Expr(s.expr);
P.OpenScope("");
P.StatementList(s.block);
P.CloseScope("");
-
+
case Scanner.GO, Scanner.RETURN, Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
- P.String("go ");
+ P.Token(s.tok);
+ P.String(" ");
P.Expr(s.expr);
P.semi = true;
/*
-func (P *Printer) DoImportDecl(x *AST.ImportDecl) {
- if x.ident != nil {
- P.Print(x.ident);
- P.String(" ");
- }
- P.String(x.file);
-}
-
-
func (P *Printer) DoFuncDecl(x *AST.FuncDecl) {
P.String("func ");
if x.typ.recv != nil {
if d.exported {
P.String("export ");
}
- P.String(Scanner.TokenName(d.tok));
+ P.Token(d.tok);
P.String(" ");
}
panic("must be a func declaration");
}
P.String(" ");
- P.Block(d.list);
+ P.Block(d.list, true);
}
}
+ // extra newline at the top level
if P.level == 0 {
P.NewLine();
}
)
-export func TokenName(tok int) string {
+export func TokenString(tok int) string {
switch (tok) {
case ILLEGAL: return "ILLEGAL";
Keywords = new(map [string] int);
for i := KEYWORDS_BEG + 1; i < KEYWORDS_END; i++ {
- Keywords[TokenName(i)] = i;
+ Keywords[TokenString(i)] = i;
}
// Provide column information in error messages for gri only...