Repository: goplus/gop
Pull request #1321 (2022-07-05 00:19:42)

TestErrTuple


Patch:
diff --git a/parser/_nofmt/cmdlinestyle1/cmd.gop b/parser/_nofmt/cmdlinestyle1/cmd.gop
new file mode 100644
index 00000000..3da8f4c4
--- /dev/null
+++ b/parser/_nofmt/cmdlinestyle1/cmd.gop
@@ -0,0 +1,10 @@
+package main
+
+func main() {
+	changeYpos -0.7, 8
+	changeYpos -0.7
+	changeYpos - 0.7
+	changeYpos-0.7
+	x[1]
+	x []...
+}
diff --git a/parser/_nofmt/cmdlinestyle1/parser.expect b/parser/_nofmt/cmdlinestyle1/parser.expect
index 22bcdb30..2573a7b0 100644
--- a/parser/_nofmt/cmdlinestyle1/parser.expect
+++ b/parser/_nofmt/cmdlinestyle1/parser.expect
@@ -1,7 +1,6 @@
 package main
 
-file cmd1.gop
-noEntrypoint
+file cmd.gop
 ast.FuncDecl:
   Name:
     ast.Ident:
@@ -17,25 +16,68 @@ ast.FuncDecl:
           X:
             ast.CallExpr:
               Fun:
-                ast.SelectorExpr:
+                ast.Ident:
+                  Name: changeYpos
+              Args:
+                ast.UnaryExpr:
+                  Op: -
                   X:
-                    ast.CallExpr:
-                      Fun:
-                        ast.CallExpr:
-                          Fun:
-                            ast.Ident:
-                              Name: add
-                          Args:
-                            ast.BasicLit:
-                              Kind: INT
-                              Value: 100
-                            ast.BasicLit:
-                              Kind: INT
-                              Value: 200
-                      Args:
-                        ast.BasicLit:
-                          Kind: INT
-                          Value: 0
-                  Sel:
-                    ast.Ident:
-                      Name: Test
+                    ast.BasicLit:
+                      Kind: FLOAT
+                      Value: 0.7
+                ast.BasicLit:
+                  Kind: INT
+                  Value: 8
+        ast.ExprStmt:
+          X:
+            ast.CallExpr:
+              Fun:
+                ast.Ident:
+                  Name: changeYpos
+              Args:
+                ast.UnaryExpr:
+                  Op: -
+                  X:
+                    ast.BasicLit:
+                      Kind: FLOAT
+                      Value: 0.7
+        ast.ExprStmt:
+          X:
+            ast.BinaryExpr:
+              X:
+                ast.Ident:
+                  Name: changeYpos
+              Op: -
+              Y:
+                ast.BasicLit:
+                  Kind: FLOAT
+                  Value: 0.7
+        ast.ExprStmt:
+          X:
+            ast.BinaryExpr:
+              X:
+                ast.Ident:
+                  Name: changeYpos
+              Op: -
+              Y:
+                ast.BasicLit:
+                  Kind: FLOAT
+                  Value: 0.7
+        ast.ExprStmt:
+          X:
+            ast.IndexExpr:
+              X:
+                ast.Ident:
+                  Name: x
+              Index:
+                ast.BasicLit:
+                  Kind: INT
+                  Value: 1
+        ast.ExprStmt:
+          X:
+            ast.CallExpr:
+              Fun:
+                ast.Ident:
+                  Name: x
+              Args:
+                ast.SliceLit:
diff --git a/parser/_nofmt/cmdlinestyle1/cmd1.gop b/parser/_nofmt/cmdlinestyle2/cmd2.gop
similarity index 100%
rename from parser/_nofmt/cmdlinestyle1/cmd1.gop
rename to parser/_nofmt/cmdlinestyle2/cmd2.gop
diff --git a/parser/_nofmt/cmdlinestyle2/parser.expect b/parser/_nofmt/cmdlinestyle2/parser.expect
new file mode 100644
index 00000000..5a5325a1
--- /dev/null
+++ b/parser/_nofmt/cmdlinestyle2/parser.expect
@@ -0,0 +1,41 @@
+package main
+
+file cmd2.gop
+noEntrypoint
+ast.FuncDecl:
+  Name:
+    ast.Ident:
+      Name: main
+  Type:
+    ast.FuncType:
+      Params:
+        ast.FieldList:
+  Body:
+    ast.BlockStmt:
+      List:
+        ast.ExprStmt:
+          X:
+            ast.CallExpr:
+              Fun:
+                ast.SelectorExpr:
+                  X:
+                    ast.CallExpr:
+                      Fun:
+                        ast.CallExpr:
+                          Fun:
+                            ast.Ident:
+                              Name: add
+                          Args:
+                            ast.BasicLit:
+                              Kind: INT
+                              Value: 100
+                            ast.BasicLit:
+                              Kind: INT
+                              Value: 200
+                      Args:
+                        ast.BasicLit:
+                          Kind: INT
+                          Value: 0
+                  Sel:
+                    ast.Ident:
+                      Name: Test
diff --git a/parser/_nofmt/cmdlinestyle3/cmd.gop b/parser/_nofmt/cmdlinestyle3/cmd.gop
new file mode 100644
index 00000000..912bcba5
--- /dev/null
+++ b/parser/_nofmt/cmdlinestyle3/cmd.gop
@@ -0,0 +1,3 @@
+println (1+2i, 2)
+println (1, a...)
+println (a...)
diff --git a/parser/parser.go b/parser/parser.go
index 16d227e3..711904fc 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -40,6 +40,10 @@ import (
 	"github.com/qiniu/x/log"
 )
 
+const (
+	msgTupleNotSupported = "tuple is not supported"
+)
+
 // The parser structure holds the parser's internal state.
 type parser struct {
 	file    *token.File
@@ -484,7 +488,6 @@ func (p *parser) atComma(context string, follow token.Token) bool {
 		p.error(p.pos, msgctx)
 		if debugParseError {
 			log.Std.Output("", log.Linfo, 2, msgctx)
-			panic(msgctx)
 		}
 		return true // "insert" comma and continue
 	}
@@ -1385,8 +1388,8 @@ func (p *parser) parseOperand(lhs, allowTuple, allowCmd bool) (x ast.Expr, isTup
 			return &tupleExpr{opening: lparen, closing: p.pos}, true
 		}
 		p.exprLev++
-		x := p.parseRHSOrType() // types may be parenthesized: (some type)
-		if allowTuple && p.tok == token.COMMA {
+		x = p.parseRHSOrType() // types may be parenthesized: (some type)
+		if allowTuple && (p.tok == token.COMMA || p.tok == token.ELLIPSIS) {
 			// (x, y, ...) => expr
 			items := make([]ast.Expr, 1, 2)
 			items[0] = x
@@ -1394,9 +1397,14 @@ func (p *parser) parseOperand(lhs, allowTuple, allowCmd bool) (x ast.Expr, isTup
 				p.next()
 				items = append(items, p.parseRHSOrType())
 			}
+			t := &tupleExpr{opening: lparen, items: items, closing: p.pos}
+			if p.tok == token.ELLIPSIS {
+				t.ellipsis = p.pos
+				p.next()
+			}
 			p.exprLev--
 			p.expect(token.RPAREN)
-			return &tupleExpr{opening: lparen, items: items, closing: p.pos}, true
+			return t, true
 		}
 		p.exprLev--
 		rparen := p.expect(token.RPAREN)
@@ -1557,8 +1565,13 @@ func (p *parser) parseCallOrConversion(fun ast.Expr, isCmd bool) *ast.CallExpr {
 	for p.tok != endTok && p.tok != token.EOF && !ellipsis.IsValid() {
 		expr, isTuple := p.parseRHSOrTypeEx(isCmd && len(list) == 0)
 		if isTuple {
-			tuple := expr.(*tupleExpr)
-			list, lparen, rparen, isCmd = tuple.items, tuple.opening, tuple.closing, false
+			t := expr.(*tupleExpr)
+			if p.tok != token.SEMICOLON && p.tok != token.RBRACE && p.tok != token.EOF {
+				p.error(t.opening, msgTupleNotSupported)
+				p.advance(stmtStart)
+			}
+			list, lparen, ellipsis, rparen = t.items, t.opening, t.ellipsis, t.closing
+			isCmd = true
 			break
 		}
 		list = append(list, expr) // builtins may expect a type: make(some type, ...)
@@ -1759,7 +1772,8 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	case *ast.LambdaExpr:
 	case *ast.LambdaExpr2:
 	case *tupleExpr:
-		p.error(v.opening, "tuple is not supported")
+		p.error(v.opening, msgTupleNotSupported)
+		x = &ast.BadExpr{From: v.opening, To: v.closing}
 	default:
 		// all other nodes are not proper expressions
 		p.errorExpected(x.Pos(), "expression", 3)
@@ -2028,26 +2042,20 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int, allowTuple, allowCmd bool)
 		defer un(trace(p, "BinaryExpr"))
 	}
 
-	x, isTuple = p.parseUnaryExpr(lhs, allowTuple, allowCmd)
+	if x, isTuple = p.parseUnaryExpr(lhs, allowTuple, allowCmd); isTuple {
+		return
+	}
 	for {
 		op, oprec := p.tokPrec()
 		if oprec < prec1 {
 			return
 		}
-		if isTuple {
-			p.error(x.(*tupleExpr).opening, "tuple is not supported")
-			return
-		}
 		pos := p.expect(op)
 		if lhs {
 			p.resolve(x)
 			lhs = false
 		}
-		y, yIsTuple := p.parseBinaryExpr(false, oprec+1, true, false)
-		if yIsTuple {
-			p.error(y.(*tupleExpr).opening, "tuple is not supported")
-			return
-		}
+		y, _ := p.parseBinaryExpr(false, oprec+1, false, false)
 		x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
 	}
 }
@@ -2077,9 +2085,10 @@ func (p *parser) parseRangeExpr(allowTuple, allowCmd bool) (x ast.Expr, isTuple
 
 type tupleExpr struct {
 	ast.Expr
-	opening token.Pos
-	items   []ast.Expr
-	closing token.Pos
+	opening  token.Pos
+	items    []ast.Expr
+	ellipsis token.Pos
+	closing  token.Pos
 }
 
 func (p *parser) parseLambdaExpr(allowTuple, allowCmd, allowRangeExpr bool) (x ast.Expr, isTuple bool) {
@@ -2155,7 +2164,8 @@ func (p *parser) parseLambdaExpr(allowTuple, allowCmd, allowRangeExpr bool) (x a
 			RhsHasParen: rhsHasParen,
 		}, false
 	} else if isTuple && !allowTuple {
-		p.error(x.(*tupleExpr).opening, "tuple is not supported")
+		p.error(x.(*tupleExpr).opening, msgTupleNotSupported)
+		p.advance(stmtStart)
 	}
 	return
 }


Test patch:
diff --git a/parser/_testdata/cmdlinestyle6/parser.expect b/parser/_nofmt/cmdlinestyle3/parser.expect
similarity index 59%
rename from parser/_testdata/cmdlinestyle6/parser.expect
rename to parser/_nofmt/cmdlinestyle3/parser.expect
index dcdefb1d..8e9f7eaa 100644
--- a/parser/_testdata/cmdlinestyle6/parser.expect
+++ b/parser/_nofmt/cmdlinestyle3/parser.expect
@@ -33,3 +33,24 @@ ast.FuncDecl:
                 ast.BasicLit:
                   Kind: INT
                   Value: 2
+        ast.ExprStmt:
+          X:
+            ast.CallExpr:
+              Fun:
+                ast.Ident:
+                  Name: println
+              Args:
+                ast.BasicLit:
+                  Kind: INT
+                  Value: 1
+                ast.Ident:
+                  Name: a
+        ast.ExprStmt:
+          X:
+            ast.CallExpr:
+              Fun:
+                ast.Ident:
+                  Name: println
+              Args:
+                ast.Ident:
+                  Name: a
diff --git a/parser/_testdata/cmdlinestyle1/cmd.gop b/parser/_testdata/cmdlinestyle1/cmd.gop
index 3da8f4c4..f6d42c61 100644
--- a/parser/_testdata/cmdlinestyle1/cmd.gop
+++ b/parser/_testdata/cmdlinestyle1/cmd.gop
@@ -1,10 +1,1 @@
-package main
-
-func main() {
-	changeYpos -0.7, 8
-	changeYpos -0.7
-	changeYpos - 0.7
-	changeYpos-0.7
-	x[1]
-	x []...
-}
+println (1+2i)*2
diff --git a/parser/_testdata/cmdlinestyle1/parser.expect b/parser/_testdata/cmdlinestyle1/parser.expect
index 2573a7b0..519b39fa 100644
--- a/parser/_testdata/cmdlinestyle1/parser.expect
+++ b/parser/_testdata/cmdlinestyle1/parser.expect
@@ -1,6 +1,7 @@
 package main
 
 file cmd.gop
+noEntrypoint
 ast.FuncDecl:
   Name:
     ast.Ident:
@@ -17,67 +18,24 @@ ast.FuncDecl:
             ast.CallExpr:
               Fun:
                 ast.Ident:
-                  Name: changeYpos
+                  Name: println
               Args:
-                ast.UnaryExpr:
-                  Op: -
+                ast.BinaryExpr:
                   X:
+                    ast.ParenExpr:
+                      X:
+                        ast.BinaryExpr:
+                          X:
+                            ast.BasicLit:
+                              Kind: INT
+                              Value: 1
+                          Op: +
+                          Y:
+                            ast.BasicLit:
+                              Kind: IMAG
+                              Value: 2i
+                  Op: *
+                  Y:
                     ast.BasicLit:
-                      Kind: FLOAT
-                      Value: 0.7
-                ast.BasicLit:
-                  Kind: INT
-                  Value: 8
-        ast.ExprStmt:
-          X:
-            ast.CallExpr:
-              Fun:
-                ast.Ident:
-                  Name: changeYpos
-              Args:
-                ast.UnaryExpr:
-                  Op: -
-                  X:
-                    ast.BasicLit:
-                      Kind: FLOAT
-                      Value: 0.7
-        ast.ExprStmt:
-          X:
-            ast.BinaryExpr:
-              X:
-                ast.Ident:
-                  Name: changeYpos
-              Op: -
-              Y:
-                ast.BasicLit:
-                  Kind: FLOAT
-                  Value: 0.7
-        ast.ExprStmt:
-          X:
-            ast.BinaryExpr:
-              X:
-                ast.Ident:
-                  Name: changeYpos
-              Op: -
-              Y:
-                ast.BasicLit:
-                  Kind: FLOAT
-                  Value: 0.7
-        ast.ExprStmt:
-          X:
-            ast.IndexExpr:
-              X:
-                ast.Ident:
-                  Name: x
-              Index:
-                ast.BasicLit:
-                  Kind: INT
-                  Value: 1
-        ast.ExprStmt:
-          X:
-            ast.CallExpr:
-              Fun:
-                ast.Ident:
-                  Name: x
-              Args:
-                ast.SliceLit:
+                      Kind: INT
+                      Value: 2
diff --git a/parser/_testdata/cmdlinestyle5/cmd5.gop b/parser/_testdata/cmdlinestyle5/cmd5.gop
deleted file mode 100644
index f6d42c61..00000000
--- a/parser/_testdata/cmdlinestyle5/cmd5.gop
+++ /dev/null
@@ -1,1 +0,0 @@
-println (1+2i)*2
diff --git a/parser/_testdata/cmdlinestyle5/parser.expect b/parser/_testdata/cmdlinestyle5/parser.expect
deleted file mode 100644
index ef36cabb..00000000
--- a/parser/_testdata/cmdlinestyle5/parser.expect
+++ /dev/null
@@ -1,41 +0,0 @@
-package main
-
-file cmd5.gop
-noEntrypoint
-ast.FuncDecl:
-  Name:
-    ast.Ident:
-      Name: main
-  Type:
-    ast.FuncType:
-      Params:
-        ast.FieldList:
-  Body:
-    ast.BlockStmt:
-      List:
-        ast.ExprStmt:
-          X:
-            ast.CallExpr:
-              Fun:
-                ast.Ident:
-                  Name: println
-              Args:
-                ast.BinaryExpr:
-                  X:
-                    ast.ParenExpr:
-                      X:
-                        ast.BinaryExpr:
-                          X:
-                            ast.BasicLit:
-                              Kind: INT
-                              Value: 1
-                          Op: +
-                          Y:
-                            ast.BasicLit:
-                              Kind: IMAG
-                              Value: 2i
-                  Op: *
-                  Y:
-                    ast.BasicLit:
-                      Kind: INT
-                      Value: 2
diff --git a/parser/_testdata/cmdlinestyle6/cmd.gop b/parser/_testdata/cmdlinestyle6/cmd.gop
deleted file mode 100644
index 126b37c5..00000000
--- a/parser/_testdata/cmdlinestyle6/cmd.gop
+++ /dev/null
@@ -1,1 +0,0 @@
-println (1+2i,2)
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 62be14b5..c8995720 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -50,12 +50,18 @@ func testErrCode(t *testing.T, code string, errExp, panicExp string) {
 	}
 }
 
+func TestErrTuple(t *testing.T) {
+	testErrCode(t, `println (1,2)*2`, `/foo/bar.gop:1:9: tuple is not supported`, ``)
+	testErrCode(t, `println 2*(1,2)`, `/foo/bar.gop:1:13: expected ')', found ','`, ``)
+	testErrCode(t, `func test() (int,int) { return (100,100)`, `/foo/bar.gop:1:32: tuple is not supported`, ``)
+}
+
 func TestErrOperand(t *testing.T) {
 	testErrCode(t, `a :=`, `/foo/bar.gop:1:5: expected operand, found 'EOF'`, ``)
 }
 
 func TestErrMissingComma(t *testing.T) {
-	testErrCode(t, `func a(b int c)`, ``, `missing ',' in parameter list`)
+	testErrCode(t, `func a(b int c)`, `/foo/bar.gop:1:14: missing ',' in parameter list`, ``)
 }
 
 func TestErrLambda(t *testing.T) {
@@ -369,10 +375,4 @@ ast.FuncDecl:
 `)
 }
 
-func TestErrTuple(t *testing.T) {
-	testErrCode(t, `println (1,2)*2`, `/foo/bar.gop:1:9: tuple is not supported`, ``)
-	testErrCode(t, `println 2*(1,2)`, `/foo/bar.gop:1:11: tuple is not supported`, ``)
-	testErrCode(t, `func test() (int,int) { return (100,100)`, `/foo/bar.gop:1:32: tuple is not supported`, ``)
-}
-
 // -----------------------------------------------------------------------------
diff --git a/printer/gop_test.go b/printer/gop_test.go
index 0440e7d9..70293574 100644
--- a/printer/gop_test.go
+++ b/printer/gop_test.go
@@ -182,9 +182,6 @@ func TestFromParse(t *testing.T) {
 			return err
 		}
 		name := info.Name()
-		if name == "cmd.gop" { // skip this file
-			return nil
-		}
 		if !info.IsDir() && filepath.Ext(name) == ".gop" {
 			testFrom(t, path, sel, 0)
 		}