type (
- Node interface {};
+ Any interface {};
Type struct;
Expr struct;
Stat struct;
// Thus, empty lists can be represented by nil.
export type List struct {
- a *[] Node;
+ a *[] Any;
}
}
-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];
}
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
export type Type struct {
- pos, tok int;
+ Node;
expr *Expr; // type name, array length
mode int; // channel mode
key *Type; // receiver type, map key
// Statements
export type Stat struct {
- pos, tok int;
+ Node;
init, post *Stat;
expr *Expr;
block *List;
// Declarations
export type Decl struct {
- pos, tok int;
+ Node;
exported bool;
ident *Expr; // nil for ()-style declarations
typ *Type;
P.comments = AST.NewList();
P.Next();
- P.expr_lev = 1;
+ P.expr_lev = 0;
P.scope_lev = 0;
}
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");
case Scanner.FUNC:
x = P.ParseFunctionLit();
-
+
+ /*
+ case Scanner.NEW:
+ x = P.ParseNewCall();
+ */
+
default:
t := P.TryType();
if t != nil {
pos := P.pos;
P.Expect(Scanner.LBRACK);
+ P.expr_lev++;
i := P.ParseExpression(0);
+ P.expr_lev--;
P.Expect(Scanner.RBRACK);
P.Ecart();
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);
- if P.tok == Scanner.COMMA {
- pos := P.pos;
- P.Next();
- z := P.ParseExpressionList();
- // create list manually because NewExpr checks for type expressions
- z = P.NewExpr(pos, Scanner.COMMA, nil, z);
- z.x = y;
- y = z;
+ 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();
+ y := P.ParseExpressionList();
+ // create list manually because NewExpr checks for type expressions
+ z := AST.NewExpr(pos, Scanner.COMMA, nil, y);
+ z.x = x.y;
+ x.y = z;
+ }
+ } else {
+ // normal argument list
+ x.y = P.ParseExpressionList();
}
- x.y = y;
+ P.expr_lev--;
}
P.Expect(Scanner.RPAREN);
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 {
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();
}
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);
}
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
// 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:
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;
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;
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;
S.filename = filename;
S.nerrors = 0;
S.errpos = 0;
+ S.columns = columns;
S.src = src;
S.pos = 0;
- S.columns = columns;
+ S.linepos = 0;
+
S.testmode = testmode;
-
- S.ExpectNoErrors(); // after setting S.src
- S.Next(); // after S.ExpectNoErrrors()
+ S.ExpectNoErrors(); // S.src must be set
+ S.Next(); // S.ExpectNoErrrors() must be called before
}
if S.ch == '/' {
// comment
+ S.Next();
for S.ch >= 0 {
S.Next();
if S.ch == '\n' {
- S.Next();
goto exit;
}
}
ch := S.ch;
S.Next();
if ch == '*' && S.ch == '/' {
- S.Next();
goto exit;
}
}
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;
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
}
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 \