1
0
mirror of https://github.com/golang/go synced 2024-11-12 10:00:25 -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 (
Node interface {};
Any interface {};
Type struct;
Expr struct;
Stat struct;
@ -23,7 +23,7 @@ type (
// Thus, empty lists can be represented by nil.
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];
}
func (p *List) set(i int, x Node) {
func (p *List) set(i int, x Any) {
p.a[i] = x;
}
func (p *List) Add (x Node) {
func (p *List) Add (x Any) {
a := p.a;
n := len(a);
if n == cap(a) {
b := new([] Node, 2*n);
b := new([] Any, 2*n);
for i := 0; i < n; i++ {
b[i] = a[i];
}
@ -63,16 +63,24 @@ func (p *List) Add (x Node) {
export func NewList() *List {
p := new(List);
p.a = new([] Node, 10) [0 : 0];
p.a = new([] Any, 10) [0 : 0];
return p;
}
// ----------------------------------------------------------------------------
// All nodes have a source position and and token.
export type Node struct {
pos, tok int;
}
// ----------------------------------------------------------------------------
// Expressions
export type Expr struct {
pos, tok int;
Node;
x, y *Expr; // binary (x, y) and unary (y) expressions
// TODO find a more space efficient way to hold these
s string; // identifiers and literals
@ -124,7 +132,7 @@ export const /* channel mode */ (
export type Type struct {
pos, tok int;
Node;
expr *Expr; // type name, array length
mode int; // channel mode
key *Type; // receiver type, map key
@ -171,7 +179,7 @@ export var BadType = NewType(0, Scanner.ILLEGAL);
// Statements
export type Stat struct {
pos, tok int;
Node;
init, post *Stat;
expr *Expr;
block *List;
@ -193,7 +201,7 @@ export var BadStat = NewStat(0, Scanner.ILLEGAL);
// Declarations
export type Decl struct {
pos, tok int;
Node;
exported bool;
ident *Expr; // nil for ()-style declarations
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.Next();
P.expr_lev = 1;
P.expr_lev = 0;
P.scope_lev = 0;
}
@ -631,15 +631,39 @@ func (P *Parser) ParseFunctionLit() *AST.Expr {
x := AST.NewLit(P.pos, Scanner.FUNC, "");
P.Expect(Scanner.FUNC);
x.t = P.ParseFunctionType();
P.expr_lev++;
P.scope_lev++;
x.block = P.ParseBlock();
P.scope_lev--;
P.expr_lev--;
P.Ecart();
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 {
P.Trace("Operand");
@ -669,6 +693,11 @@ func (P *Parser) ParseOperand() *AST.Expr {
case Scanner.FUNC:
x = P.ParseFunctionLit();
/*
case Scanner.NEW:
x = P.ParseNewCall();
*/
default:
t := P.TryType();
if t != nil {
@ -709,7 +738,9 @@ func (P *Parser) ParseIndex(x *AST.Expr) *AST.Expr {
pos := P.pos;
P.Expect(Scanner.LBRACK);
P.expr_lev++;
i := P.ParseExpression(0);
P.expr_lev--;
P.Expect(Scanner.RBRACK);
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) ParseCall(x *AST.Expr) *AST.Expr {
func (P *Parser) ParseCall(x0 *AST.Expr) *AST.Expr {
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);
if P.tok != Scanner.RPAREN {
// the very first argument may be a type if the function called is new()
// call ParseBinaryExpr() which allows type expressions (instead of ParseExpression)
y := P.ParseBinaryExpr(1);
P.expr_lev++;
var t *AST.Type;
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 {
pos := P.pos;
P.Next();
z := P.ParseExpressionList();
y := P.ParseExpressionList();
// create list manually because NewExpr checks for type expressions
z = P.NewExpr(pos, Scanner.COMMA, nil, z);
z.x = y;
y = z;
z := AST.NewExpr(pos, Scanner.COMMA, nil, y);
z.x = x.y;
x.y = z;
}
x.y = y;
} else {
// normal argument list
x.y = P.ParseExpressionList();
}
P.expr_lev--;
}
P.Expect(Scanner.RPAREN);
@ -817,10 +858,10 @@ func (P *Parser) ParsePrimaryExpr() *AST.Expr {
case Scanner.LPAREN: x = P.ParseCall(x);
case Scanner.LBRACE:
// 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)
var t *AST.Type;
if P.expr_lev > 0 {
if P.expr_lev >= 0 {
t = ExprType(x);
}
if t != nil {
@ -1002,7 +1043,7 @@ func (P *Parser) ParseControlClause(keyword int) *AST.Stat {
P.Expect(keyword);
if P.tok != Scanner.LBRACE {
prev_lev := P.expr_lev;
P.expr_lev = 0;
P.expr_lev = -1;
if P.tok != Scanner.SEMICOLON {
s.init = P.ParseSimpleStat();
}
@ -1129,12 +1170,15 @@ func (P *Parser) ParseCommCase() *AST.Stat {
s := AST.NewStat(P.pos, Scanner.CASE);
if P.tok == Scanner.CASE {
P.Next();
P.ParseExpression(1);
x := P.ParseExpression(1);
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
pos, tok := P.pos, P.tok;
P.Next();
P.Expect(Scanner.ARROW);
P.ParseExpression(1);
y := P.ParseExpression(1);
x = AST.NewExpr(pos, tok, x, y);
}
s.expr = x;
} else {
P.Expect(Scanner.DEFAULT);
}

View File

@ -238,9 +238,9 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
case Scanner.COMMA:
// list
// (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.Expr1(x.y, Scanner.LowestPrec);
P.Expr(x.y);
case Scanner.PERIOD:
// selector or type guard
@ -265,14 +265,14 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
// call
P.Expr1(x.x, Scanner.HighestPrec);
P.String(x.pos, "(");
P.Expr1(x.y, Scanner.LowestPrec);
P.Expr(x.y);
P.String(0, ")");
case Scanner.LBRACE:
// composite
P.Type(x.t);
P.String(x.pos, "{");
P.Expr1(x.y, Scanner.LowestPrec);
P.Expr(x.y);
P.String(0, "}");
default:

View File

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

View File

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