mirror of
https://github.com/golang/go
synced 2024-11-12 10:20:27 -07:00
- simplified parsing of composite literals and slices by
treating ":" as lowest-level binary operator - more precise error message for composites - added flag -columns (false) - when set, prints precise error column - a few more tests R=r OCL=17428 CL=17428
This commit is contained in:
parent
e45eb60657
commit
52e9080d56
@ -161,7 +161,7 @@ func (P *Parser) NewExpr(pos, tok int, x, y *Node.Expr) *Node.Expr {
|
|||||||
// Common productions
|
// Common productions
|
||||||
|
|
||||||
func (P *Parser) TryType() *Node.Type;
|
func (P *Parser) TryType() *Node.Type;
|
||||||
func (P *Parser) ParseExpression() *Node.Expr;
|
func (P *Parser) ParseExpression(prec int) *Node.Expr;
|
||||||
func (P *Parser) ParseStatement() *Node.Stat;
|
func (P *Parser) ParseStatement() *Node.Stat;
|
||||||
func (P *Parser) ParseDeclaration() *Node.Decl;
|
func (P *Parser) ParseDeclaration() *Node.Decl;
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ func (P *Parser) ParseArrayType() *Node.Type {
|
|||||||
t := Node.NewType(P.pos, Scanner.LBRACK);
|
t := Node.NewType(P.pos, Scanner.LBRACK);
|
||||||
P.Expect(Scanner.LBRACK);
|
P.Expect(Scanner.LBRACK);
|
||||||
if P.tok != Scanner.RBRACK {
|
if P.tok != Scanner.RBRACK {
|
||||||
t.expr = P.ParseExpression();
|
t.expr = P.ParseExpression(1);
|
||||||
}
|
}
|
||||||
P.Expect(Scanner.RBRACK);
|
P.Expect(Scanner.RBRACK);
|
||||||
t.elt = P.ParseType();
|
t.elt = P.ParseType();
|
||||||
@ -603,7 +603,7 @@ func (P *Parser) ParseBlock() *Node.List {
|
|||||||
func (P *Parser) ParseExpressionList() *Node.Expr {
|
func (P *Parser) ParseExpressionList() *Node.Expr {
|
||||||
P.Trace("ExpressionList");
|
P.Trace("ExpressionList");
|
||||||
|
|
||||||
x := P.ParseExpression();
|
x := P.ParseExpression(1);
|
||||||
if P.tok == Scanner.COMMA {
|
if P.tok == Scanner.COMMA {
|
||||||
pos := P.pos;
|
pos := P.pos;
|
||||||
P.Next();
|
P.Next();
|
||||||
@ -644,7 +644,7 @@ func (P *Parser) ParseOperand() *Node.Expr {
|
|||||||
// (currently not working)
|
// (currently not working)
|
||||||
P.Next();
|
P.Next();
|
||||||
P.expr_lev++;
|
P.expr_lev++;
|
||||||
x = P.ParseExpression();
|
x = P.ParseExpression(1);
|
||||||
P.expr_lev--;
|
P.expr_lev--;
|
||||||
P.Expect(Scanner.RPAREN);
|
P.Expect(Scanner.RPAREN);
|
||||||
|
|
||||||
@ -695,31 +695,12 @@ func (P *Parser) ParseSelectorOrTypeGuard(x *Node.Expr) *Node.Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// mode = 0: single or pair accepted
|
|
||||||
// mode = 1: single only accepted
|
|
||||||
// mode = 2: pair only accepted
|
|
||||||
func (P *Parser) ParseExpressionPair(mode int) *Node.Expr {
|
|
||||||
P.Trace("ExpressionPair");
|
|
||||||
|
|
||||||
x := P.ParseExpression();
|
|
||||||
if mode == 0 && P.tok == Scanner.COLON || mode == 2 {
|
|
||||||
pos := P.pos;
|
|
||||||
P.Expect(Scanner.COLON);
|
|
||||||
y := P.ParseExpression();
|
|
||||||
x = P.NewExpr(pos, Scanner.COLON, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
P.Ecart();
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (P *Parser) ParseIndex(x *Node.Expr) *Node.Expr {
|
func (P *Parser) ParseIndex(x *Node.Expr) *Node.Expr {
|
||||||
P.Trace("IndexOrSlice");
|
P.Trace("IndexOrSlice");
|
||||||
|
|
||||||
pos := P.pos;
|
pos := P.pos;
|
||||||
P.Expect(Scanner.LBRACK);
|
P.Expect(Scanner.LBRACK);
|
||||||
i := P.ParseExpressionPair(0);
|
i := P.ParseExpression(0);
|
||||||
P.Expect(Scanner.RBRACK);
|
P.Expect(Scanner.RBRACK);
|
||||||
|
|
||||||
P.Ecart();
|
P.Ecart();
|
||||||
@ -736,7 +717,7 @@ func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
|
|||||||
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()
|
// the very first argument may be a type if the function called is new()
|
||||||
// call ParseBinaryExpr() which allows type expressions
|
// call ParseBinaryExpr() which allows type expressions (instead of ParseExpression)
|
||||||
y := P.ParseBinaryExpr(1);
|
y := P.ParseBinaryExpr(1);
|
||||||
if P.tok == Scanner.COMMA {
|
if P.tok == Scanner.COMMA {
|
||||||
pos := P.pos;
|
pos := P.pos;
|
||||||
@ -756,29 +737,34 @@ func (P *Parser) ParseCall(x *Node.Expr) *Node.Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO make this non-recursive
|
func (P *Parser) ParseCompositeList(mode int) *Node.Expr {
|
||||||
func (P *Parser) ParseExpressionPairList(mode int) *Node.Expr {
|
x := P.ParseExpression(0);
|
||||||
P.Trace("ExpressionPairList");
|
|
||||||
|
|
||||||
x := P.ParseExpressionPair(mode);
|
switch mode {
|
||||||
if mode == 0 {
|
case 0: // first element determines mode
|
||||||
// first expression determines mode
|
mode = 1;
|
||||||
if x.tok == Scanner.COLON {
|
if x.tok == Scanner.COLON {
|
||||||
mode = 2;
|
mode = 2;
|
||||||
} else {
|
}
|
||||||
mode = 1;
|
case 1:
|
||||||
|
if x.tok == Scanner.COLON {
|
||||||
|
P.Error(x.x.pos, "single value expected; found pair");
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if x.tok != Scanner.COLON {
|
||||||
|
P.Error(x.pos, "key:value pair expected; found single value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if P.tok == Scanner.COMMA {
|
if P.tok == Scanner.COMMA {
|
||||||
pos := P.pos;
|
pos := P.pos;
|
||||||
P.Next();
|
P.Next();
|
||||||
if P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
|
if P.tok != Scanner.RBRACE {
|
||||||
y := P.ParseExpressionPairList(mode);
|
y := P.ParseCompositeList(mode);
|
||||||
x = P.NewExpr(pos, Scanner.COMMA, x, y);
|
x = P.NewExpr(pos, Scanner.COMMA, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P.Ecart();
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -790,7 +776,7 @@ func (P *Parser) ParseCompositeLit(t *Node.Type) *Node.Expr {
|
|||||||
x.t = t;
|
x.t = t;
|
||||||
P.Expect(Scanner.LBRACE);
|
P.Expect(Scanner.LBRACE);
|
||||||
if P.tok != Scanner.RBRACE {
|
if P.tok != Scanner.RBRACE {
|
||||||
x.y = P.ParseExpressionPairList(0);
|
x.y = P.ParseCompositeList(0);
|
||||||
}
|
}
|
||||||
P.Expect(Scanner.RBRACE);
|
P.Expect(Scanner.RBRACE);
|
||||||
|
|
||||||
@ -876,11 +862,14 @@ func (P *Parser) ParseBinaryExpr(prec1 int) *Node.Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (P *Parser) ParseExpression() *Node.Expr {
|
func (P *Parser) ParseExpression(prec int) *Node.Expr {
|
||||||
P.Trace("Expression");
|
P.Trace("Expression");
|
||||||
indent := P.indent;
|
indent := P.indent;
|
||||||
|
|
||||||
x := P.NoType(P.ParseBinaryExpr(1));
|
if prec < 0 {
|
||||||
|
panic("precedence must be >= 0");
|
||||||
|
}
|
||||||
|
x := P.NoType(P.ParseBinaryExpr(prec));
|
||||||
|
|
||||||
if indent != P.indent {
|
if indent != P.indent {
|
||||||
panic("imbalanced tracing code (Expression)");
|
panic("imbalanced tracing code (Expression)");
|
||||||
@ -948,7 +937,7 @@ func (P *Parser) ParseGoStat() *Node.Stat {
|
|||||||
|
|
||||||
s := Node.NewStat(P.pos, Scanner.GO);
|
s := Node.NewStat(P.pos, Scanner.GO);
|
||||||
P.Expect(Scanner.GO);
|
P.Expect(Scanner.GO);
|
||||||
s.expr = P.ParseExpression();
|
s.expr = P.ParseExpression(1);
|
||||||
|
|
||||||
P.Ecart();
|
P.Ecart();
|
||||||
return s;
|
return s;
|
||||||
@ -997,7 +986,7 @@ func (P *Parser) ParseControlClause(keyword int) *Node.Stat {
|
|||||||
if P.tok == Scanner.SEMICOLON {
|
if P.tok == Scanner.SEMICOLON {
|
||||||
P.Next();
|
P.Next();
|
||||||
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
|
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
|
||||||
s.expr = P.ParseExpression();
|
s.expr = P.ParseExpression(1);
|
||||||
}
|
}
|
||||||
if keyword == Scanner.FOR {
|
if keyword == Scanner.FOR {
|
||||||
P.Expect(Scanner.SEMICOLON);
|
P.Expect(Scanner.SEMICOLON);
|
||||||
@ -1117,11 +1106,11 @@ func (P *Parser) ParseCommCase() *Node.Stat {
|
|||||||
s := Node.NewStat(P.pos, Scanner.CASE);
|
s := Node.NewStat(P.pos, Scanner.CASE);
|
||||||
if P.tok == Scanner.CASE {
|
if P.tok == Scanner.CASE {
|
||||||
P.Next();
|
P.Next();
|
||||||
P.ParseExpression();
|
P.ParseExpression(1);
|
||||||
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
|
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
|
||||||
P.Next();
|
P.Next();
|
||||||
P.Expect(Scanner.ARROW);
|
P.Expect(Scanner.ARROW);
|
||||||
P.ParseExpression();
|
P.ParseExpression(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
P.Expect(Scanner.DEFAULT);
|
P.Expect(Scanner.DEFAULT);
|
||||||
@ -1171,7 +1160,7 @@ func (P *Parser) ParseRangeStat() *Node.Stat {
|
|||||||
P.Expect(Scanner.RANGE);
|
P.Expect(Scanner.RANGE);
|
||||||
P.ParseIdentList();
|
P.ParseIdentList();
|
||||||
P.Expect(Scanner.DEFINE);
|
P.Expect(Scanner.DEFINE);
|
||||||
s.expr = P.ParseExpression();
|
s.expr = P.ParseExpression(1);
|
||||||
s.block = P.ParseBlock();
|
s.block = P.ParseBlock();
|
||||||
|
|
||||||
P.Ecart();
|
P.Ecart();
|
||||||
@ -1265,7 +1254,7 @@ func (P *Parser) ParseConstSpec(exported bool) *Node.Decl {
|
|||||||
d.typ = P.TryType();
|
d.typ = P.TryType();
|
||||||
if P.tok == Scanner.ASSIGN {
|
if P.tok == Scanner.ASSIGN {
|
||||||
P.Next();
|
P.Next();
|
||||||
d.val = P.ParseExpression();
|
d.val = P.ParseExpression(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
P.Ecart();
|
P.Ecart();
|
||||||
|
@ -15,6 +15,7 @@ var (
|
|||||||
silent = Flag.Bool("s", false, nil, "silent mode: no pretty print output");
|
silent = Flag.Bool("s", false, nil, "silent mode: no pretty print output");
|
||||||
verbose = Flag.Bool("v", false, nil, "verbose mode: trace parsing");
|
verbose = Flag.Bool("v", false, nil, "verbose mode: trace parsing");
|
||||||
sixg = Flag.Bool("6g", true, nil, "6g compatibility mode");
|
sixg = Flag.Bool("6g", true, nil, "6g compatibility mode");
|
||||||
|
columns = Flag.Bool("columns", Platform.USER == "gri", nil, "print column info in error messages");
|
||||||
testmode = Flag.Bool("t", false, nil, "test mode: interprets /* ERROR */ and /* SYNC */ comments");
|
testmode = Flag.Bool("t", false, nil, "test mode: interprets /* ERROR */ and /* SYNC */ comments");
|
||||||
tokenchan = Flag.Bool("token_chan", false, nil, "use token channel for scanner-parser connection");
|
tokenchan = Flag.Bool("token_chan", false, nil, "use token channel for scanner-parser connection");
|
||||||
)
|
)
|
||||||
@ -45,7 +46,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scanner := new(Scanner.Scanner);
|
scanner := new(Scanner.Scanner);
|
||||||
scanner.Open(src_file, src, testmode.BVal());
|
scanner.Open(src_file, src, columns.BVal(), testmode.BVal());
|
||||||
|
|
||||||
var tstream *<-chan *Scanner.Token;
|
var tstream *<-chan *Scanner.Token;
|
||||||
if tokenchan.BVal() {
|
if tokenchan.BVal() {
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package Scanner
|
package Scanner
|
||||||
|
|
||||||
import Platform "platform"
|
|
||||||
import Utils "utils"
|
import Utils "utils"
|
||||||
|
|
||||||
|
|
||||||
@ -213,8 +211,9 @@ export func TokenString(tok int) string {
|
|||||||
|
|
||||||
|
|
||||||
export func Precedence(tok int) int {
|
export func Precedence(tok int) int {
|
||||||
// TODO should use a map or array here for lookup
|
|
||||||
switch tok {
|
switch tok {
|
||||||
|
case COLON:
|
||||||
|
return 0;
|
||||||
case LOR:
|
case LOR:
|
||||||
return 1;
|
return 1;
|
||||||
case LAND:
|
case LAND:
|
||||||
@ -228,23 +227,18 @@ export func Precedence(tok int) int {
|
|||||||
case MUL, QUO, REM, SHL, SHR, AND:
|
case MUL, QUO, REM, SHL, SHR, AND:
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var Keywords *map [string] int;
|
var Keywords *map [string] int;
|
||||||
var VerboseMsgs bool; // error message customization
|
|
||||||
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Keywords = new(map [string] int);
|
Keywords = new(map [string] int);
|
||||||
|
|
||||||
for i := KEYWORDS_BEG + 1; i < KEYWORDS_END; i++ {
|
for i := KEYWORDS_BEG + 1; i < KEYWORDS_END; i++ {
|
||||||
Keywords[TokenString(i)] = i;
|
Keywords[TokenString(i)] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide column information in error messages for gri only...
|
|
||||||
VerboseMsgs = Platform.USER == "gri";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -277,6 +271,7 @@ export type Scanner struct {
|
|||||||
filename string; // error reporting only
|
filename string; // error reporting only
|
||||||
nerrors int; // number of errors
|
nerrors int; // number of errors
|
||||||
errpos int; // last error position
|
errpos int; // last error position
|
||||||
|
columns bool; // if set, print columns in error messages
|
||||||
|
|
||||||
// scanning
|
// scanning
|
||||||
src string; // scanned source
|
src string; // scanned source
|
||||||
@ -416,7 +411,7 @@ func (S *Scanner) ErrorMsg(pos int, msg string) {
|
|||||||
if pos >= 0 {
|
if pos >= 0 {
|
||||||
// print position
|
// print position
|
||||||
line, col := S.LineCol(pos);
|
line, col := S.LineCol(pos);
|
||||||
if VerboseMsgs {
|
if S.columns {
|
||||||
print(":", line, ":", col);
|
print(":", line, ":", col);
|
||||||
} else {
|
} else {
|
||||||
print(":", line);
|
print(":", line);
|
||||||
@ -464,13 +459,14 @@ func (S *Scanner) ExpectNoErrors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (S *Scanner) Open(filename, src string, testmode bool) {
|
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.src = src;
|
S.src = src;
|
||||||
S.pos = 0;
|
S.pos = 0;
|
||||||
|
S.columns = columns;
|
||||||
S.testmode = testmode;
|
S.testmode = testmode;
|
||||||
|
|
||||||
S.ExpectNoErrors(); // after setting S.src
|
S.ExpectNoErrors(); // after setting S.src
|
||||||
|
@ -18,13 +18,21 @@ func /* ERROR receiver */ () f0() {} /* SYNC */
|
|||||||
func /* ERROR receiver */ (*S0, *S0) f1() {} /* SYNC */
|
func /* ERROR receiver */ (*S0, *S0) f1() {} /* SYNC */
|
||||||
|
|
||||||
|
|
||||||
func f0(a b, c /* ERROR type */ ) {}
|
func f0(a b, c /* ERROR type */ ) /* SYNC */ {}
|
||||||
|
|
||||||
|
|
||||||
func f1() {
|
func f1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func CompositeLiterals() {
|
||||||
|
a1 := []int{};
|
||||||
|
a2 := []int{0, 1, 2, };
|
||||||
|
a3 := []int{0, 1, 2, /* ERROR single value expected */ 3 : 4, 5}; /* SYNC */
|
||||||
|
a1 := []int{0 : 1, 2 : 3, /* ERROR key:value pair expected */ 4, }; /* SYNC */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func main () {
|
func main () {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user