Commit 89319cfb authored by Robert Griesemer's avatar Robert Griesemer

- implemented heuristic for composite literals starting with a type name:

  if in a if, for, or switch header, must be parenthesized
- implemented string concatenation
- simplified a lot of code
- added many more tests: can now parse all *.go files I got my hands on
- printing output currently broken in some cases, use with -s (silent) option

R=r
OCL=16932
CL=16934
parent 827dcb86
...@@ -11,18 +11,11 @@ pretty: pretty.6 ...@@ -11,18 +11,11 @@ pretty: pretty.6
test: pretty test: pretty
pretty -s *.go pretty -s *.go
pretty -s ../gosrc/*.go pretty -s ../gosrc/*.go
pretty -s $(GOROOT)/test/235.go pretty -s $(GOROOT)/test/*.go
pretty -s $(GOROOT)/test/args.go
pretty -s $(GOROOT)/test/bufiolib.go
pretty -s $(GOROOT)/test/char_lit.go
pretty -s $(GOROOT)/test/sieve.go
pretty -s $(GOROOT)/src/pkg/*.go pretty -s $(GOROOT)/src/pkg/*.go
pretty -s $(GOROOT)/src/lib/flag.go pretty -s $(GOROOT)/src/lib/*.go
pretty -s $(GOROOT)/src/lib/fmt.go pretty -s $(GOROOT)/src/lib/*/*.go
pretty -s $(GOROOT)/src/lib/rand.go pretty -s $(GOROOT)/usr/r/*/*.go
pretty -s $(GOROOT)/src/lib/math/*.go
pretty -s $(GOROOT)/src/lib/container/*.go
pretty -s $(GOROOT)/src/lib/syscall/*.go
echo "DONE" echo "DONE"
testnoisy: pretty testnoisy: pretty
...@@ -42,6 +35,17 @@ testnoisy: pretty ...@@ -42,6 +35,17 @@ testnoisy: pretty
pretty $(GOROOT)/src/lib/syscall/*.go pretty $(GOROOT)/src/lib/syscall/*.go
echo "DONE" echo "DONE"
# These tests don't work yet
testfull: pretty
pretty *.go
pretty ../gosrc/*.go
pretty $(GOROOT)/test/*.go
pretty $(GOROOT)/src/pkg/*.go
pretty $(GOROOT)/src/lib/*.go
pretty $(GOROOT)/src/lib/*/*.go
pretty $(GOROOT)/usr/r/*/*.go
echo "DONE"
install: pretty install: pretty
cp pretty $(HOME)/bin/pretty cp pretty $(HOME)/bin/pretty
......
...@@ -18,10 +18,13 @@ export type Parser struct { ...@@ -18,10 +18,13 @@ export type Parser struct {
pos int; // token source position pos int; // token source position
tok int; // one token look-ahead tok int; // one token look-ahead
val string; // token value (for IDENT, NUMBER, STRING only) val string; // token value (for IDENT, NUMBER, STRING only)
semi bool; // true if a semicolon was inserted by the previous statement
// Nesting level // Non-syntactic parser control
level int; // 0 = global scope, -1 = function scope of global functions, etc. opt_semi bool; // true if semicolon is optional
// Nesting levels
expr_lev int; // 0 = control clause level, 1 = expr inside ()'s
scope_lev int; // 0 = global scope, 1 = function scope of global functions, etc.
}; };
...@@ -60,7 +63,7 @@ func (P *Parser) Next() { ...@@ -60,7 +63,7 @@ func (P *Parser) Next() {
t := <-P.tokchan; t := <-P.tokchan;
P.tok, P.pos, P.val = t.tok, t.pos, t.val; P.tok, P.pos, P.val = t.tok, t.pos, t.val;
} }
P.semi = false; P.opt_semi = false;
if P.verbose { if P.verbose {
P.PrintIndent(); P.PrintIndent();
print("[", P.pos, "] ", Scanner.TokenName(P.tok), "\n"); print("[", P.pos, "] ", Scanner.TokenName(P.tok), "\n");
...@@ -74,7 +77,8 @@ func (P *Parser) Open(verbose bool, scanner *Scanner.Scanner, tokchan *<-chan *S ...@@ -74,7 +77,8 @@ func (P *Parser) Open(verbose bool, scanner *Scanner.Scanner, tokchan *<-chan *S
P.scanner = scanner; P.scanner = scanner;
P.tokchan = tokchan; P.tokchan = tokchan;
P.Next(); P.Next();
P.level = 0; P.expr_lev = 1;
P.scope_lev = 0;
} }
...@@ -98,17 +102,6 @@ func (P *Parser) OptSemicolon() { ...@@ -98,17 +102,6 @@ func (P *Parser) OptSemicolon() {
} }
// ----------------------------------------------------------------------------
// Scopes
func (P *Parser) OpenScope() {
}
func (P *Parser) CloseScope() {
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Common productions // Common productions
...@@ -498,8 +491,8 @@ func (P *Parser) ParseStatementList() *AST.List { ...@@ -498,8 +491,8 @@ func (P *Parser) ParseStatementList() *AST.List {
stats.Add(P.ParseStatement()); stats.Add(P.ParseStatement());
if P.tok == Scanner.SEMICOLON { if P.tok == Scanner.SEMICOLON {
P.Next(); P.Next();
} else if P.semi { } else if P.opt_semi {
P.semi = false; // consume inserted ";" P.opt_semi = false; // "consume" optional semicolon
} else { } else {
break; break;
} }
...@@ -517,14 +510,12 @@ func (P *Parser) ParseBlock() *AST.Block { ...@@ -517,14 +510,12 @@ func (P *Parser) ParseBlock() *AST.Block {
block.pos = P.pos; block.pos = P.pos;
P.Expect(Scanner.LBRACE); P.Expect(Scanner.LBRACE);
P.OpenScope();
if P.tok != Scanner.RBRACE { if P.tok != Scanner.RBRACE {
block.stats = P.ParseStatementList(); block.stats = P.ParseStatementList();
} }
P.OptSemicolon(); P.OptSemicolon();
P.CloseScope();
P.Expect(Scanner.RBRACE); P.Expect(Scanner.RBRACE);
P.semi = true; // allow optional semicolon P.opt_semi = true;
P.Ecart(); P.Ecart();
return block; return block;
...@@ -562,7 +553,9 @@ func (P *Parser) ParseFunctionLit() *AST.FunctionLit { ...@@ -562,7 +553,9 @@ func (P *Parser) ParseFunctionLit() *AST.FunctionLit {
P.Expect(Scanner.FUNC); P.Expect(Scanner.FUNC);
fun.typ = P.ParseFunctionType(); fun.typ = P.ParseFunctionType();
P.scope_lev++;
fun.body = P.ParseBlock(); fun.body = P.ParseBlock();
P.scope_lev--;
P.Ecart(); P.Ecart();
return fun; return fun;
...@@ -588,52 +581,11 @@ func (P *Parser) ParseExpressionPairList(list *AST.List) { ...@@ -588,52 +581,11 @@ func (P *Parser) ParseExpressionPairList(list *AST.List) {
list.Add(P.ParseExpressionPair()); list.Add(P.ParseExpressionPair());
for P.tok == Scanner.COMMA { for P.tok == Scanner.COMMA {
list.Add(P.ParseExpressionPair());
}
P.Ecart();
}
func (P *Parser) ParseCompositeLit(typ AST.Type) AST.Expr {
P.Trace("CompositeLit");
lit := new(AST.CompositeLit);
lit.pos = P.pos;
lit.typ = typ;
lit.vals = AST.NewList();
P.Expect(Scanner.LBRACE);
// TODO: should allow trailing ','
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);
}
} else if P.tok == Scanner.COLON {
p := new(AST.Pair);
p.pos = P.pos;
p.x = x;
P.Next(); P.Next();
p.y = P.ParseExpression(); list.Add(P.ParseExpressionPair());
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);
}
} }
P.Expect(Scanner.RBRACE);
P.Ecart(); P.Ecart();
return lit;
} }
...@@ -648,32 +600,35 @@ func (P *Parser) ParseOperand() AST.Expr { ...@@ -648,32 +600,35 @@ func (P *Parser) ParseOperand() AST.Expr {
case Scanner.LPAREN: case Scanner.LPAREN:
P.Next(); P.Next();
P.expr_lev++;
op = P.ParseExpression(); op = P.ParseExpression();
P.expr_lev--;
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
case Scanner.INT, Scanner.FLOAT, Scanner.STRING: case Scanner.INT, Scanner.FLOAT:
lit := new(AST.Literal); lit := new(AST.Literal);
lit.pos, lit.tok, lit.val = P.pos, P.tok, P.val; lit.pos, lit.tok, lit.val = P.pos, P.tok, P.val;
op = lit; op = lit;
P.Next(); 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();
}
op = lit;
case Scanner.FUNC: case Scanner.FUNC:
op = P.ParseFunctionLit(); op = P.ParseFunctionLit();
case Scanner.HASH:
P.Next();
typ := P.ParseType();
P.ParseCompositeLit(typ);
op = AST.NIL;
default: default:
if P.tok != Scanner.IDENT {
typ, ok := P.TryType(); typ, ok := P.TryType();
if ok { if ok {
op = P.ParseCompositeLit(typ); op = typ;
break; break;
} }
}
P.Error(P.pos, "operand expected"); P.Error(P.pos, "operand expected");
P.Next(); // make progress P.Next(); // make progress
...@@ -739,33 +694,53 @@ func (P *Parser) ParseCall(x AST.Expr) *AST.Call { ...@@ -739,33 +694,53 @@ func (P *Parser) ParseCall(x AST.Expr) *AST.Call {
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN { if P.tok != Scanner.RPAREN {
// first arguments could be a type if the call is to "new" call.args = P.ParseNewExpressionList();
// - exclude type names because they could be expression starts }
// - exclude "("'s because function types are not allowed and they indicate an expression P.Expect(Scanner.RPAREN);
// - still a problem for "new(*T)" (the "*")
// - possibility: make "new" a keyword again (or disallow "*" types in new) P.Ecart();
if P.tok != Scanner.IDENT && P.tok != Scanner.LPAREN { return call;
typ, ok := P.TryType(); }
if ok {
call.args = AST.NewList();
call.args.Add(typ); func (P *Parser) ParseCompositeLit(typ AST.Type) AST.Expr {
P.Trace("CompositeLit");
lit := new(AST.CompositeLit);
lit.pos = P.pos;
lit.typ = typ;
lit.vals = AST.NewList();
P.Expect(Scanner.LBRACE);
if P.tok != Scanner.RBRACE {
x := P.ParseExpression();
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
P.Next(); P.Next();
if P.tok != Scanner.RPAREN { lit.vals.Add(x);
P.ParseExpressionList(call.args); if P.tok != Scanner.RBRACE {
P.ParseExpressionList(lit.vals);
} }
} else if P.tok == Scanner.COLON {
p := new(AST.Pair);
p.pos = P.pos;
p.x = x;
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 {
call.args = P.ParseNewExpressionList();
} }
} else { } else {
call.args = P.ParseNewExpressionList(); lit.vals.Add(x);
} }
} }
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RBRACE);
P.Ecart(); P.Ecart();
return call; return lit;
} }
...@@ -778,6 +753,12 @@ func (P *Parser) ParsePrimaryExpr() AST.Expr { ...@@ -778,6 +753,12 @@ func (P *Parser) ParsePrimaryExpr() AST.Expr {
case Scanner.PERIOD: x = P.ParseSelectorOrTypeGuard(x); case Scanner.PERIOD: x = P.ParseSelectorOrTypeGuard(x);
case Scanner.LBRACK: x = P.ParseIndexOrSlice(x); case Scanner.LBRACK: x = P.ParseIndexOrSlice(x);
case Scanner.LPAREN: x = P.ParseCall(x); case Scanner.LPAREN: x = P.ParseCall(x);
case Scanner.LBRACE:
if P.expr_lev > 0 {
x = P.ParseCompositeLit(x);
} else {
goto exit;
}
default: goto exit; default: goto exit;
} }
} }
...@@ -872,7 +853,7 @@ func (P *Parser) ParseSimpleStat() AST.Stat { ...@@ -872,7 +853,7 @@ func (P *Parser) ParseSimpleStat() AST.Stat {
l.ident = AST.NIL; l.ident = AST.NIL;
} }
P.Next(); // consume ":" P.Next(); // consume ":"
P.semi = true; // allow optional semicolon P.opt_semi = true;
stat = l; stat = l;
case case
...@@ -969,6 +950,8 @@ func (P *Parser) ParseControlClause(keyword int) *AST.ControlClause { ...@@ -969,6 +950,8 @@ func (P *Parser) ParseControlClause(keyword int) *AST.ControlClause {
P.Expect(keyword); P.Expect(keyword);
if P.tok != Scanner.LBRACE { if P.tok != Scanner.LBRACE {
prev_lev := P.expr_lev;
P.expr_lev = 0;
if P.tok != Scanner.SEMICOLON { if P.tok != Scanner.SEMICOLON {
ctrl.init = P.ParseSimpleStat(); ctrl.init = P.ParseSimpleStat();
ctrl.has_init = true; ctrl.has_init = true;
...@@ -990,6 +973,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.ControlClause { ...@@ -990,6 +973,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.ControlClause {
ctrl.expr, ctrl.has_expr = ctrl.init, ctrl.has_init; ctrl.expr, ctrl.has_expr = ctrl.init, ctrl.has_init;
ctrl.init, ctrl.has_init = AST.NIL, false; ctrl.init, ctrl.has_init = AST.NIL, false;
} }
P.expr_lev = prev_lev;
} }
P.Ecart(); P.Ecart();
...@@ -1079,7 +1063,7 @@ func (P *Parser) ParseSwitchStat() *AST.SwitchStat { ...@@ -1079,7 +1063,7 @@ func (P *Parser) ParseSwitchStat() *AST.SwitchStat {
stat.cases.Add(P.ParseCaseClause()); stat.cases.Add(P.ParseCaseClause());
} }
P.Expect(Scanner.RBRACE); P.Expect(Scanner.RBRACE);
P.semi = true; // allow optional semicolon P.opt_semi = true;
P.Ecart(); P.Ecart();
return stat; return stat;
...@@ -1127,7 +1111,7 @@ func (P *Parser) ParseSelectStat() { ...@@ -1127,7 +1111,7 @@ func (P *Parser) ParseSelectStat() {
P.ParseCommClause(); P.ParseCommClause();
} }
P.Expect(Scanner.RBRACE); P.Expect(Scanner.RBRACE);
P.semi = true; // allow optional semicolon P.opt_semi = true;
P.Ecart(); P.Ecart();
} }
...@@ -1172,7 +1156,11 @@ func (P *Parser) ParseStatement() AST.Stat { ...@@ -1172,7 +1156,11 @@ func (P *Parser) ParseStatement() AST.Stat {
case Scanner.FUNC: case Scanner.FUNC:
// for now we do not allow local function declarations // for now we do not allow local function declarations
fallthrough; fallthrough;
case Scanner.MUL, Scanner.ARROW, Scanner.IDENT, Scanner.LPAREN: case
// only the tokens that are legal top-level expression starts
Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING, Scanner.LPAREN, // operand
Scanner.LBRACK, Scanner.STRUCT, // composite type
Scanner.MUL, Scanner.AND, Scanner.ARROW: // unary
stat = P.ParseSimpleStat(); stat = P.ParseSimpleStat();
case Scanner.GO: case Scanner.GO:
stat = P.ParseGoStat(); stat = P.ParseGoStat();
...@@ -1259,7 +1247,7 @@ func (P *Parser) ParseTypeSpec(exported bool) *AST.TypeDecl { ...@@ -1259,7 +1247,7 @@ func (P *Parser) ParseTypeSpec(exported bool) *AST.TypeDecl {
decl := new(AST.TypeDecl); decl := new(AST.TypeDecl);
decl.ident = P.ParseIdent(); decl.ident = P.ParseIdent();
decl.typ = P.ParseType(); decl.typ = P.ParseType();
P.semi = true; // allow optional semicolon P.opt_semi = true;
P.Ecart(); P.Ecart();
return decl; return decl;
...@@ -1320,7 +1308,7 @@ func (P *Parser) ParseDecl(exported bool, keyword int) *AST.Declaration { ...@@ -1320,7 +1308,7 @@ func (P *Parser) ParseDecl(exported bool, keyword int) *AST.Declaration {
} }
} }
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
P.semi = true; // allow optional semicolon P.opt_semi = true;
} else { } else {
decl.decls.Add(P.ParseSpec(exported, keyword)); decl.decls.Add(P.ParseSpec(exported, keyword));
...@@ -1348,9 +1336,6 @@ func (P *Parser) ParseFunctionDecl(exported bool) *AST.FuncDecl { ...@@ -1348,9 +1336,6 @@ func (P *Parser) ParseFunctionDecl(exported bool) *AST.FuncDecl {
P.Expect(Scanner.FUNC); P.Expect(Scanner.FUNC);
P.OpenScope();
P.level--;
var recv *AST.VarDeclList; var recv *AST.VarDeclList;
if P.tok == Scanner.LPAREN { if P.tok == Scanner.LPAREN {
pos := P.pos; pos := P.pos;
...@@ -1367,11 +1352,10 @@ func (P *Parser) ParseFunctionDecl(exported bool) *AST.FuncDecl { ...@@ -1367,11 +1352,10 @@ func (P *Parser) ParseFunctionDecl(exported bool) *AST.FuncDecl {
fun.typ = P.ParseFunctionType(); fun.typ = P.ParseFunctionType();
fun.typ.recv = recv; fun.typ.recv = recv;
P.level++;
P.CloseScope();
if P.tok == Scanner.LBRACE { if P.tok == Scanner.LBRACE {
P.scope_lev++;
fun.body = P.ParseBlock(); fun.body = P.ParseBlock();
P.scope_lev--;
} }
P.Ecart(); P.Ecart();
...@@ -1414,7 +1398,7 @@ func (P *Parser) ParseDeclaration() AST.Node { ...@@ -1414,7 +1398,7 @@ func (P *Parser) ParseDeclaration() AST.Node {
exported := false; exported := false;
if P.tok == Scanner.EXPORT { if P.tok == Scanner.EXPORT {
if P.level == 0 { if P.scope_lev == 0 {
exported = true; exported = true;
} else { } else {
P.Error(P.pos, "local declarations cannot be exported"); P.Error(P.pos, "local declarations cannot be exported");
...@@ -1456,17 +1440,11 @@ func (P *Parser) ParseDeclaration() AST.Node { ...@@ -1456,17 +1440,11 @@ func (P *Parser) ParseDeclaration() AST.Node {
func (P *Parser) ParseProgram() *AST.Program { func (P *Parser) ParseProgram() *AST.Program {
P.Trace("Program"); P.Trace("Program");
P.OpenScope();
pos := P.pos; pos := P.pos;
P.Expect(Scanner.PACKAGE); P.Expect(Scanner.PACKAGE);
ident := P.ParseIdent(); ident := P.ParseIdent();
decls := AST.NewList(); decls := AST.NewList();
{ P.OpenScope();
if P.level != 0 {
panic("incorrect scope level");
}
for P.tok == Scanner.IMPORT { for P.tok == Scanner.IMPORT {
decls.Add(P.ParseDecl(false, Scanner.IMPORT)); decls.Add(P.ParseDecl(false, Scanner.IMPORT));
P.OptSemicolon(); P.OptSemicolon();
...@@ -1477,13 +1455,6 @@ func (P *Parser) ParseProgram() *AST.Program { ...@@ -1477,13 +1455,6 @@ func (P *Parser) ParseProgram() *AST.Program {
P.OptSemicolon(); P.OptSemicolon();
} }
if P.level != 0 {
panic("incorrect scope level");
}
P.CloseScope();
}
P.CloseScope();
P.Ecart(); P.Ecart();
x := new(AST.Program); x := new(AST.Program);
......
...@@ -58,7 +58,6 @@ export const ( ...@@ -58,7 +58,6 @@ export const (
DEFINE; DEFINE;
NOT; NOT;
ELLIPSIS; ELLIPSIS;
HASH;
LPAREN; LPAREN;
RPAREN; RPAREN;
...@@ -158,7 +157,6 @@ export func TokenName(tok int) string { ...@@ -158,7 +157,6 @@ export func TokenName(tok int) string {
case DEFINE: return ":="; case DEFINE: return ":=";
case NOT: return "!"; case NOT: return "!";
case ELLIPSIS: return "..."; case ELLIPSIS: return "...";
case HASH: return "#";
case LPAREN: return "("; case LPAREN: return "(";
case RPAREN: return ")"; case RPAREN: return ")";
...@@ -784,7 +782,6 @@ func (S *Scanner) Scan() (pos, tok int, val string) { ...@@ -784,7 +782,6 @@ func (S *Scanner) Scan() (pos, tok int, val string) {
case '!': tok = S.Select2(NOT, NEQ); case '!': tok = S.Select2(NOT, NEQ);
case '&': tok = S.Select3(AND, AND_ASSIGN, '&', LAND); case '&': tok = S.Select3(AND, AND_ASSIGN, '&', LAND);
case '|': tok = S.Select3(OR, OR_ASSIGN, '|', LOR); case '|': tok = S.Select3(OR, OR_ASSIGN, '|', LOR);
case '#': tok = HASH;
default: default:
S.Error(pos, "illegal character " + CharString(ch)); S.Error(pos, "illegal character " + CharString(ch));
tok = ILLEGAL; tok = ILLEGAL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment