1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:00:07 -07:00

- expanded parsing heuristics to deal with new(T, ...)

- fixed an issue with select
- added all bugs and fixedbugs tests that are syntactically correct to the test suite
- minor cosmetic changes

R=r
OCL=17759
CL=17759
This commit is contained in:
Robert Griesemer 2008-10-23 17:56:54 -07:00
parent 8327b54169
commit 816c1cefff
5 changed files with 107 additions and 51 deletions

View File

@ -8,7 +8,7 @@ import Scanner "scanner"
type ( type (
Node interface {}; Any interface {};
Type struct; Type struct;
Expr struct; Expr struct;
Stat struct; Stat struct;
@ -23,7 +23,7 @@ type (
// Thus, empty lists can be represented by nil. // Thus, empty lists can be represented by nil.
export type List struct { export type List struct {
a *[] Node; a *[] Any;
} }
@ -33,22 +33,22 @@ func (p *List) len() int {
} }
func (p *List) at(i int) Node { func (p *List) at(i int) Any {
return p.a[i]; return p.a[i];
} }
func (p *List) set(i int, x Node) { func (p *List) set(i int, x Any) {
p.a[i] = x; p.a[i] = x;
} }
func (p *List) Add (x Node) { func (p *List) Add (x Any) {
a := p.a; a := p.a;
n := len(a); n := len(a);
if n == cap(a) { if n == cap(a) {
b := new([] Node, 2*n); b := new([] Any, 2*n);
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
b[i] = a[i]; b[i] = a[i];
} }
@ -63,16 +63,24 @@ func (p *List) Add (x Node) {
export func NewList() *List { export func NewList() *List {
p := new(List); p := new(List);
p.a = new([] Node, 10) [0 : 0]; p.a = new([] Any, 10) [0 : 0];
return p; return p;
} }
// ----------------------------------------------------------------------------
// All nodes have a source position and and token.
export type Node struct {
pos, tok int;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Expressions // Expressions
export type Expr struct { export type Expr struct {
pos, tok int; Node;
x, y *Expr; // binary (x, y) and unary (y) expressions x, y *Expr; // binary (x, y) and unary (y) expressions
// TODO find a more space efficient way to hold these // TODO find a more space efficient way to hold these
s string; // identifiers and literals s string; // identifiers and literals
@ -124,7 +132,7 @@ export const /* channel mode */ (
export type Type struct { export type Type struct {
pos, tok int; Node;
expr *Expr; // type name, array length expr *Expr; // type name, array length
mode int; // channel mode mode int; // channel mode
key *Type; // receiver type, map key key *Type; // receiver type, map key
@ -171,7 +179,7 @@ export var BadType = NewType(0, Scanner.ILLEGAL);
// Statements // Statements
export type Stat struct { export type Stat struct {
pos, tok int; Node;
init, post *Stat; init, post *Stat;
expr *Expr; expr *Expr;
block *List; block *List;
@ -193,7 +201,7 @@ export var BadStat = NewStat(0, Scanner.ILLEGAL);
// Declarations // Declarations
export type Decl struct { export type Decl struct {
pos, tok int; Node;
exported bool; exported bool;
ident *Expr; // nil for ()-style declarations ident *Expr; // nil for ()-style declarations
typ *Type; typ *Type;

View File

@ -93,7 +93,7 @@ func (P *Parser) Open(verbose, sixg bool, scanner *Scanner.Scanner, tokchan *<-c
P.comments = AST.NewList(); P.comments = AST.NewList();
P.Next(); P.Next();
P.expr_lev = 1; P.expr_lev = 0;
P.scope_lev = 0; P.scope_lev = 0;
} }
@ -631,15 +631,39 @@ func (P *Parser) ParseFunctionLit() *AST.Expr {
x := AST.NewLit(P.pos, Scanner.FUNC, ""); x := AST.NewLit(P.pos, Scanner.FUNC, "");
P.Expect(Scanner.FUNC); P.Expect(Scanner.FUNC);
x.t = P.ParseFunctionType(); x.t = P.ParseFunctionType();
P.expr_lev++;
P.scope_lev++; P.scope_lev++;
x.block = P.ParseBlock(); x.block = P.ParseBlock();
P.scope_lev--; P.scope_lev--;
P.expr_lev--;
P.Ecart(); P.Ecart();
return x; return x;
} }
/*
func (P *Parser) ParseNewCall() *AST.Expr {
P.Trace("NewCall");
x := AST.NewExpr(P.pos, Scanner.NEW, nil, nil);
P.Next();
P.Expect(Scanner.LPAREN);
P.expr_lev++;
x.t = P.ParseType();
if P.tok == Scanner.COMMA {
P.Next();
x.y = P.ParseExpressionList();
}
P.expr_lev--;
P.Expect(Scanner.RPAREN);
P.Ecart();
return x;
}
*/
func (P *Parser) ParseOperand() *AST.Expr { func (P *Parser) ParseOperand() *AST.Expr {
P.Trace("Operand"); P.Trace("Operand");
@ -669,6 +693,11 @@ func (P *Parser) ParseOperand() *AST.Expr {
case Scanner.FUNC: case Scanner.FUNC:
x = P.ParseFunctionLit(); x = P.ParseFunctionLit();
/*
case Scanner.NEW:
x = P.ParseNewCall();
*/
default: default:
t := P.TryType(); t := P.TryType();
if t != nil { if t != nil {
@ -709,7 +738,9 @@ func (P *Parser) ParseIndex(x *AST.Expr) *AST.Expr {
pos := P.pos; pos := P.pos;
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
P.expr_lev++;
i := P.ParseExpression(0); i := P.ParseExpression(0);
P.expr_lev--;
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
P.Ecart(); P.Ecart();
@ -719,25 +750,35 @@ func (P *Parser) ParseIndex(x *AST.Expr) *AST.Expr {
func (P *Parser) ParseBinaryExpr(prec1 int) *AST.Expr func (P *Parser) ParseBinaryExpr(prec1 int) *AST.Expr
func (P *Parser) ParseCall(x *AST.Expr) *AST.Expr { func (P *Parser) ParseCall(x0 *AST.Expr) *AST.Expr {
P.Trace("Call"); P.Trace("Call");
x = P.NewExpr(P.pos, Scanner.LPAREN, x, nil); x := P.NewExpr(P.pos, Scanner.LPAREN, x0, nil);
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN { if P.tok != Scanner.RPAREN {
// the very first argument may be a type if the function called is new() P.expr_lev++;
// call ParseBinaryExpr() which allows type expressions (instead of ParseExpression) var t *AST.Type;
y := P.ParseBinaryExpr(1); if x0.tok == Scanner.IDENT && x0.s == "new" {
// heuristic: assume it's a new(T, ...) call, try to parse a type
t = P.TryType();
}
if t != nil {
// we found a type
x.y = AST.NewTypeExpr(t);
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
pos := P.pos; pos := P.pos;
P.Next(); P.Next();
z := P.ParseExpressionList(); y := P.ParseExpressionList();
// create list manually because NewExpr checks for type expressions // create list manually because NewExpr checks for type expressions
z = P.NewExpr(pos, Scanner.COMMA, nil, z); z := AST.NewExpr(pos, Scanner.COMMA, nil, y);
z.x = y; z.x = x.y;
y = z; x.y = z;
} }
x.y = y; } else {
// normal argument list
x.y = P.ParseExpressionList();
}
P.expr_lev--;
} }
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
@ -817,10 +858,10 @@ func (P *Parser) ParsePrimaryExpr() *AST.Expr {
case Scanner.LPAREN: x = P.ParseCall(x); case Scanner.LPAREN: x = P.ParseCall(x);
case Scanner.LBRACE: case Scanner.LBRACE:
// assume a composite literal only if x could be a type // assume a composite literal only if x could be a type
// and if we are not inside control clause (expr_lev > 0) // and if we are not inside control clause (expr_lev >= 0)
// (composites inside control clauses must be parenthesized) // (composites inside control clauses must be parenthesized)
var t *AST.Type; var t *AST.Type;
if P.expr_lev > 0 { if P.expr_lev >= 0 {
t = ExprType(x); t = ExprType(x);
} }
if t != nil { if t != nil {
@ -1002,7 +1043,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
P.Expect(keyword); P.Expect(keyword);
if P.tok != Scanner.LBRACE { if P.tok != Scanner.LBRACE {
prev_lev := P.expr_lev; prev_lev := P.expr_lev;
P.expr_lev = 0; P.expr_lev = -1;
if P.tok != Scanner.SEMICOLON { if P.tok != Scanner.SEMICOLON {
s.init = P.ParseSimpleStat(); s.init = P.ParseSimpleStat();
} }
@ -1129,12 +1170,15 @@ func (P *Parser) ParseCommCase() *AST.Stat {
s := AST.NewStat(P.pos, Scanner.CASE); s := AST.NewStat(P.pos, Scanner.CASE);
if P.tok == Scanner.CASE { if P.tok == Scanner.CASE {
P.Next(); P.Next();
P.ParseExpression(1); x := P.ParseExpression(1);
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE { if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
pos, tok := P.pos, P.tok;
P.Next(); P.Next();
P.Expect(Scanner.ARROW); P.Expect(Scanner.ARROW);
P.ParseExpression(1); y := P.ParseExpression(1);
x = AST.NewExpr(pos, tok, x, y);
} }
s.expr = x;
} else { } else {
P.Expect(Scanner.DEFAULT); P.Expect(Scanner.DEFAULT);
} }

View File

@ -238,9 +238,9 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
case Scanner.COMMA: case Scanner.COMMA:
// list // list
// (don't use binary expression printing because of different spacing) // (don't use binary expression printing because of different spacing)
P.Expr1(x.x, Scanner.LowestPrec); P.Expr(x.x);
P.String(x.pos, ", "); P.String(x.pos, ", ");
P.Expr1(x.y, Scanner.LowestPrec); P.Expr(x.y);
case Scanner.PERIOD: case Scanner.PERIOD:
// selector or type guard // selector or type guard
@ -265,14 +265,14 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
// call // call
P.Expr1(x.x, Scanner.HighestPrec); P.Expr1(x.x, Scanner.HighestPrec);
P.String(x.pos, "("); P.String(x.pos, "(");
P.Expr1(x.y, Scanner.LowestPrec); P.Expr(x.y);
P.String(0, ")"); P.String(0, ")");
case Scanner.LBRACE: case Scanner.LBRACE:
// composite // composite
P.Type(x.t); P.Type(x.t);
P.String(x.pos, "{"); P.String(x.pos, "{");
P.Expr1(x.y, Scanner.LowestPrec); P.Expr(x.y);
P.String(0, "}"); P.String(0, "}");
default: default:

View File

@ -285,6 +285,7 @@ export type Scanner struct {
pos int; // current reading position pos int; // current reading position
ch int; // one char look-ahead ch int; // one char look-ahead
chpos int; // position of ch chpos int; // position of ch
linepos int; // position of beginning of line
// testmode // testmode
testmode bool; testmode bool;
@ -298,8 +299,8 @@ func (S *Scanner) Next() {
if S.pos < len(S.src) { if S.pos < len(S.src) {
// assume ascii // assume ascii
r, w := int(S.src[S.pos]), 1; r, w := int(S.src[S.pos]), 1;
if r > 0x80 { if r >= 0x80 {
// wasn't ascii // not ascii
r, w = sys.stringtorune(S.src, S.pos); r, w = sys.stringtorune(S.src, S.pos);
} }
S.ch = r; S.ch = r;
@ -430,17 +431,16 @@ func (S *Scanner) LineCol(pos int) (line, col int) {
func (S *Scanner) ErrorMsg(pos int, msg string) { func (S *Scanner) ErrorMsg(pos int, msg string) {
print(S.filename); print(S.filename, ":");
if pos >= 0 { if pos >= 0 {
// print position // print position
line, col := S.LineCol(pos); line, col := S.LineCol(pos);
print(line, ":");
if S.columns { if S.columns {
print(":", line, ":", col); print(col, ":");
} else {
print(":", line);
} }
} }
print(": ", msg, "\n"); print(" ", msg, "\n");
S.nerrors++; S.nerrors++;
S.errpos = pos; S.errpos = pos;
@ -486,14 +486,15 @@ func (S *Scanner) Open(filename, src string, columns, testmode bool) {
S.filename = filename; S.filename = filename;
S.nerrors = 0; S.nerrors = 0;
S.errpos = 0; S.errpos = 0;
S.columns = columns;
S.src = src; S.src = src;
S.pos = 0; S.pos = 0;
S.columns = columns; S.linepos = 0;
S.testmode = testmode;
S.ExpectNoErrors(); // after setting S.src S.testmode = testmode;
S.Next(); // after S.ExpectNoErrrors() S.ExpectNoErrors(); // S.src must be set
S.Next(); // S.ExpectNoErrrors() must be called before
} }
@ -535,10 +536,10 @@ func (S *Scanner) ScanComment() string {
if S.ch == '/' { if S.ch == '/' {
// comment // comment
S.Next();
for S.ch >= 0 { for S.ch >= 0 {
S.Next(); S.Next();
if S.ch == '\n' { if S.ch == '\n' {
S.Next();
goto exit; goto exit;
} }
} }
@ -550,7 +551,6 @@ func (S *Scanner) ScanComment() string {
ch := S.ch; ch := S.ch;
S.Next(); S.Next();
if ch == '*' && S.ch == '/' { if ch == '*' && S.ch == '/' {
S.Next();
goto exit; goto exit;
} }
} }
@ -559,7 +559,9 @@ func (S *Scanner) ScanComment() string {
S.Error(pos, "comment not terminated"); S.Error(pos, "comment not terminated");
exit: exit:
S.Next();
comment := S.src[pos : S.chpos]; comment := S.src[pos : S.chpos];
if S.testmode { if S.testmode {
// interpret ERROR and SYNC comments // interpret ERROR and SYNC comments
oldpos := -1; oldpos := -1;

View File

@ -21,8 +21,8 @@ count() {
apply1() { apply1() {
#echo $1 $2 #echo $1 $2
case `basename $F` in case `basename $F` in
selftest.go | func3.go ) ;; # skip - these are test cases for syntax errors selftest.go | func3.go | bug014.go | bug029.go | bug032.go | bug050.go | \
newfn.go ) ;; # skip these - cannot parse w/o type information bug068.go | bug088.go | bug083.go | bug106.go ) ;; # skip - files contain syntax errors
* ) $1 $2; count ;; * ) $1 $2; count ;;
esac esac
} }
@ -42,6 +42,8 @@ apply() {
for F in \ for F in \
$GOROOT/usr/gri/pretty/*.go \ $GOROOT/usr/gri/pretty/*.go \
$GOROOT/test/*.go \ $GOROOT/test/*.go \
$GOROOT/test/bugs/*.go \
$GOROOT/test/fixedbugs/*.go \
$GOROOT/src/pkg/*.go \ $GOROOT/src/pkg/*.go \
$GOROOT/src/lib/*.go \ $GOROOT/src/lib/*.go \
$GOROOT/src/lib/*/*.go \ $GOROOT/src/lib/*/*.go \