- fixed several parser issues
R=r
OCL=13441
CL=13441
diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go
index 302db22..05fc742 100644
--- a/usr/gri/gosrc/parser.go
+++ b/usr/gri/gosrc/parser.go
@@ -208,12 +208,15 @@
}
-func (P *Parser) ParseQualifiedIdent() *Globals.Object {
+func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
P.Trace("QualifiedIdent");
+ if pos < 0 {
+ pos = P.pos;
+ ident = P.ParseIdent();
+ }
+
if EnableSemanticTests {
- pos := P.pos;
- ident := P.ParseIdent();
obj := P.Lookup(ident);
if obj == nil {
P.Error(pos, `"` + ident + `" is not declared`);
@@ -229,7 +232,6 @@
return obj;
} else {
- P.ParseIdent();
if P.tok == Scanner.PERIOD {
P.Next();
P.ParseIdent();
@@ -261,7 +263,7 @@
P.Trace("TypeName");
if EnableSemanticTests {
- obj := P.ParseQualifiedIdent();
+ obj := P.ParseQualifiedIdent(-1, "");
typ := obj.typ;
if obj.kind != Object.TYPE {
P.Error(obj.pos, `"` + obj.ident + `" is not a type`);
@@ -270,7 +272,7 @@
P.Ecart();
return typ;
} else {
- P.ParseQualifiedIdent();
+ P.ParseQualifiedIdent(-1, "");
P.Ecart();
return Universe.bad_t;
}
@@ -510,11 +512,11 @@
P.OpenScope();
typ := Globals.NewType(Type.INTERFACE);
typ.scope = P.top_scope;
- for P.tok != Scanner.RBRACE {
+ for P.tok == Scanner.IDENT {
P.ParseMethodDecl();
}
P.CloseScope();
- P.Next();
+ P.Expect(Scanner.RBRACE);
P.Ecart();
return typ;
@@ -708,6 +710,15 @@
}
+func (P *Parser) ParseBuiltinCall() {
+ P.Trace("BuiltinCall");
+
+ P.ParseExpressionList(); // TODO should be optional
+
+ P.Ecart();
+}
+
+
func (P *Parser) ParseCompositeLit(typ *Globals.Type) {
P.Trace("CompositeLit");
@@ -749,18 +760,36 @@
}
-func (P *Parser) ParseOperand() {
+func (P *Parser) ParseOperand(pos int, ident string) {
P.Trace("Operand");
+
+ if pos < 0 && P.tok == Scanner.IDENT {
+ // no look-ahead yet
+ pos = P.pos;
+ ident = P.val;
+ P.Next();
+ }
- switch P.tok {
- case Scanner.IDENT:
- P.ParseQualifiedIdent();
+ if pos >= 0 {
+ // TODO set these up properly in the Universe
+ if ident == "panic" || ident == "print" {
+ P.ParseBuiltinCall();
+ goto exit;
+ }
+
+ P.ParseQualifiedIdent(pos, ident);
// TODO enable code below
/*
if obj.kind == Object.TYPE {
P.ParseCompositeLit(obj.typ);
}
*/
+ goto exit;
+ }
+
+ switch P.tok {
+ case Scanner.IDENT:
+ panic "UNREACHABLE";
case Scanner.LPAREN:
P.Next();
P.ParseExpression();
@@ -786,6 +815,7 @@
}
}
+exit:
P.Ecart();
}
@@ -821,8 +851,8 @@
}
-func (P *Parser) ParseInvocation() {
- P.Trace("Invocation");
+func (P *Parser) ParseCall() {
+ P.Trace("Call");
P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN {
@@ -834,10 +864,10 @@
}
-func (P *Parser) ParsePrimaryExpr() {
+func (P *Parser) ParsePrimaryExpr(pos int, ident string) AST.Expr {
P.Trace("PrimaryExpr");
- P.ParseOperand();
+ P.ParseOperand(pos, ident);
for {
switch P.tok {
case Scanner.PERIOD:
@@ -845,24 +875,25 @@
case Scanner.LBRACK:
P.ParseIndexOrSlice();
case Scanner.LPAREN:
- P.ParseInvocation();
+ P.ParseCall();
default:
P.Ecart();
- return;
+ return nil;
}
}
P.Ecart();
+ return nil;
}
func (P *Parser) ParsePrimaryExprList() {
P.Trace("PrimaryExprList");
- P.ParsePrimaryExpr();
+ P.ParsePrimaryExpr(-1, "");
for P.tok == Scanner.COMMA {
P.Next();
- P.ParsePrimaryExpr();
+ P.ParsePrimaryExpr(-1, "");
}
P.Ecart();
@@ -885,7 +916,7 @@
P.Ecart();
return nil; // TODO fix this
}
- P.ParsePrimaryExpr();
+ P.ParsePrimaryExpr(-1, "");
P.Ecart();
return nil; // TODO fix this
@@ -912,10 +943,15 @@
}
-func (P *Parser) ParseBinaryExpr(prec1 int) AST.Expr {
+func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) AST.Expr {
P.Trace("BinaryExpr");
- x := P.ParseUnaryExpr();
+ var x AST.Expr;
+ if pos >= 0 {
+ x = P.ParsePrimaryExpr(pos, ident);
+ } else {
+ x = P.ParseUnaryExpr();
+ }
for prec := Precedence(P.tok); prec >= prec1; prec-- {
for Precedence(P.tok) == prec {
e := new(AST.BinaryExpr);
@@ -923,7 +959,7 @@
e.op = P.tok; // TODO should we use tokens or separate operator constants?
e.x = x;
P.Next();
- e.y = P.ParseBinaryExpr(prec + 1);
+ e.y = P.ParseBinaryExpr(-1, "", prec + 1);
x = e;
}
}
@@ -932,11 +968,13 @@
}
-func (P *Parser) ParseExpression() {
- P.Trace("Expression");
+// Expressions where the first token may be an
+// identifier that has already been consumed.
+func (P *Parser) ParseIdentExpression(pos int, ident string) {
+ P.Trace("IdentExpression");
indent := P.indent;
- P.ParseBinaryExpr(1);
+ P.ParseBinaryExpr(pos, ident, 1);
if indent != P.indent {
panic "imbalanced tracing code (Expression)";
@@ -945,32 +983,102 @@
}
+func (P *Parser) ParseExpression() {
+ P.Trace("Expression");
+ P.ParseIdentExpression(-1, "");
+ P.Ecart();
+}
+
+
// ----------------------------------------------------------------------------
// Statements
-func (P *Parser) ParseBuiltinStat() {
- P.Trace("BuiltinStat");
- P.Expect(Scanner.IDENT);
- P.ParseExpressionList(); // TODO should be optional
+func (P *Parser) ParseIdentOrExpr(nidents int) int {
+ P.Trace("IdentOrExpr");
+ if nidents >= 0 && P.tok == Scanner.IDENT {
+ pos := P.pos;
+ ident := P.val;
+ P.Next();
+ switch P.tok {
+ case Scanner.COMMA,
+ Scanner.COLON,
+ Scanner.DEFINE,
+ Scanner.ASSIGN,
+ Scanner.ADD_ASSIGN,
+ 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:
+ // identifier is not part of a more complicated expression
+ nidents++;
+
+ default:
+ // assume identifier is part of a more complicated expression
+ P.ParseIdentExpression(pos, ident);
+ nidents = -nidents - 1;
+ }
+ } else {
+ P.ParseExpression();
+ if nidents > 0 {
+ nidents = -nidents;
+ }
+ nidents--;
+ }
P.Ecart();
+ return nidents;
+}
+
+
+// temporary - will go away eventually
+func abs(x int) int {
+ if x < 0 {
+ x = -x;
+ }
+ return x;
}
func (P *Parser) ParseSimpleStat() {
P.Trace("SimpleStat");
- P.ParseExpression();
- if P.tok == Scanner.COLON {
+
+ // If we see an identifier, we don't know if it's part of a
+ // label declaration, (multiple) variable declaration, assignment,
+ // or simply an expression, without looking ahead.
+ // Strategy: We parse an expression list, but simultaneously, as
+ // long as possible, maintain a list of identifiers which is converted
+ // into an expression list only if neccessary.
+ // TODO: maintain the lists
+
+ nidents := P.ParseIdentOrExpr(0);
+ for P.tok == Scanner.COMMA {
P.Next();
- P.Ecart();
- return;
+ nidents = P.ParseIdentOrExpr(nidents);
}
- if P.tok == Scanner.COMMA {
- P.Next();
- P.ParsePrimaryExprList();
- }
+
switch P.tok {
+ case Scanner.COLON:
+ // label declaration
+ P.Next();
+ if nidents != 1 {
+ // TODO provide exact error position
+ P.Error(P.pos, "illegal label declaration");
+ }
+
+ case Scanner.DEFINE:
+ // variable declaration
+ P.Next();
+ P.ParseExpressionList();
+ if nidents < 0 {
+ // TODO provide exact error position
+ P.Error(P.pos, "illegal identifier list for declaration");
+ }
+
case Scanner.ASSIGN: fallthrough;
- case Scanner.DEFINE: fallthrough;
case Scanner.ADD_ASSIGN: fallthrough;
case Scanner.SUB_ASSIGN: fallthrough;
case Scanner.MUL_ASSIGN: fallthrough;
@@ -983,11 +1091,19 @@
case Scanner.SHR_ASSIGN:
P.Next();
P.ParseExpressionList();
- case Scanner.INC:
+ case Scanner.INC, Scanner.DEC:
P.Next();
- case Scanner.DEC:
- P.Next();
+ if abs(nidents) != 1 {
+ // TODO provide exact error position
+ P.Error(P.pos, "too many expressions for '++' or '--'");
+ }
+ default:
+ if abs(nidents) != 1 {
+ // TODO provide exact error position
+ P.Error(P.pos, "too many expressions for expression statement");
+ }
}
+
P.Ecart();
}
@@ -1144,7 +1260,7 @@
}
}
P.Expect(Scanner.LBRACE);
- for P.tok != Scanner.RBRACE {
+ for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT {
P.ParseCaseClause();
}
P.Expect(Scanner.RBRACE);
@@ -1214,7 +1330,7 @@
P.Expect(Scanner.SELECT);
P.Expect(Scanner.LBRACE);
- for P.tok != Scanner.RBRACE {
+ for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
P.ParseCommClause();
}
P.Next();
@@ -1236,16 +1352,8 @@
case Scanner.FUNC:
// for now we do not allow local function declarations
fallthrough;
- case Scanner.SEND: fallthrough;
- case Scanner.RECV:
- P.ParseSimpleStat(); // send or receive
- case Scanner.IDENT:
- switch P.val {
- case "print", "panic":
- P.ParseBuiltinStat();
- default:
- P.ParseSimpleStat();
- }
+ case Scanner.MUL, Scanner.SEND, Scanner.RECV, Scanner.IDENT:
+ P.ParseSimpleStat();
case Scanner.GO:
P.ParseGoStat();
case Scanner.RETURN:
@@ -1300,7 +1408,7 @@
P.Expect(Scanner.IMPORT);
if P.tok == Scanner.LPAREN {
P.Next();
- for P.tok != Scanner.RPAREN {
+ for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
P.ParseImportSpec();
P.Optional(Scanner.SEMICOLON); // TODO this seems wrong
}
@@ -1338,7 +1446,7 @@
P.Expect(Scanner.CONST);
if P.tok == Scanner.LPAREN {
P.Next();
- for P.tok != Scanner.RPAREN {
+ for P.tok == Scanner.IDENT {
P.ParseConstSpec();
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
@@ -1390,7 +1498,7 @@
P.Expect(Scanner.TYPE);
if P.tok == Scanner.LPAREN {
P.Next();
- for P.tok != Scanner.RPAREN {
+ for P.tok == Scanner.IDENT {
P.ParseTypeSpec();
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
@@ -1433,7 +1541,7 @@
P.Expect(Scanner.VAR);
if P.tok == Scanner.LPAREN {
P.Next();
- for P.tok != Scanner.RPAREN {
+ for P.tok == Scanner.IDENT {
P.ParseVarSpec();
if P.tok != Scanner.RPAREN {
P.Expect(Scanner.SEMICOLON);
@@ -1467,20 +1575,20 @@
func (P *Parser) ParseExportDecl() {
P.Trace("ExportDecl");
+ // TODO this needs to be clarified - the current syntax is
+ // "everything goes" - sigh...
P.Expect(Scanner.EXPORT);
+ has_paren := false;
if P.tok == Scanner.LPAREN {
P.Next();
- for P.tok != Scanner.RPAREN {
- P.exports.AddStr(P.ParseIdent());
- P.Optional(Scanner.COMMA); // TODO this seems wrong
- }
- P.Next();
- } else {
+ has_paren = true;
+ }
+ for P.tok == Scanner.IDENT {
P.exports.AddStr(P.ParseIdent());
- for P.tok == Scanner.COMMA {
- P.Next();
- P.exports.AddStr(P.ParseIdent());
- }
+ P.Optional(Scanner.COMMA); // TODO this seems wrong
+ }
+ if has_paren {
+ P.Expect(Scanner.RPAREN)
}
P.Ecart();