Repository: goplus/gop
Pull request #957 (2021-11-28 12:32:12)

parser: check toIdent error
parser add toIdent check and dump error.
```
func test(v string, f func( int)) {
	f(100)
}

test "hello" => {
	println "lambda",x
}
```
```
main.gop:5:6: expected 'IDENT', found "hello"
```


Patch:
diff --git a/parser/parser.go b/parser/parser.go
index 0d8beba5..e1ecaf4c 100644
--- a/parser/parser.go
+++ b/parser/parser.go
@@ -1411,7 +1411,7 @@ func (p *parser) parseOperand(lhs, allowTuple bool) ast.Expr {
 		if allowTuple && p.tok == token.COMMA {
 			// (x, y, ...) => expr
 			items := make([]*ast.Ident, 1, 2)
-			items[0] = x.(*ast.Ident)
+			items[0] = p.toIdent(x)
 			for p.tok == token.COMMA {
 				p.next()
 				items = append(items, p.parseIdent())
@@ -2095,13 +2095,16 @@ func (p *parser) parseLambdaExpr(allowCmd, allowRangeExpr bool) ast.Expr {
 		}
 		var lhs []*ast.Ident
 		if x != nil {
-			switch v := x.(type) {
+			e := x
+		retry:
+			switch v := e.(type) {
 			case *tupleExpr:
 				lhs, lhsHasParen = v.items, true
 			case *ast.ParenExpr:
-				lhs, lhsHasParen = []*ast.Ident{v.X.(*ast.Ident)}, true
+				e, lhsHasParen = v.X, true
+				goto retry
 			default:
-				lhs = []*ast.Ident{x.(*ast.Ident)}
+				lhs = []*ast.Ident{p.toIdent(v)}
 			}
 		}
 		if debugParseOutput {
@@ -2738,20 +2741,25 @@ func (p *parser) parseForPhraseStmtPart(lhs []ast.Expr) *ast.ForPhraseStmt {
 	stmt := &ast.ForPhraseStmt{ForPhrase: &ast.ForPhrase{TokPos: tokPos, X: x, Cond: cond}}
 	switch len(lhs) {
 	case 1:
-		stmt.Value = toIdent(lhs[0])
+		stmt.Value = p.toIdent(lhs[0])
 	case 2:
-		stmt.Key, stmt.Value = toIdent(lhs[0]), toIdent(lhs[1])
+		stmt.Key, stmt.Value = p.toIdent(lhs[0]), p.toIdent(lhs[1])
 	default:
 		log.Panicln("TODO: parseForPhraseStmt - too many variables, 1 or 2 is required")
 	}
 	return stmt
 }
 
-func toIdent(e ast.Expr) *ast.Ident {
-	if i, ok := e.(*ast.Ident); ok {
-		return i
+func (p *parser) toIdent(e ast.Expr) *ast.Ident {
+	switch v := e.(type) {
+	case *ast.Ident:
+		return v
+	case *ast.BasicLit:
+		p.errorExpected(e.Pos(), fmt.Sprintf("'IDENT', found %v", v.Value), 2)
+	default:
+		p.errorExpected(e.Pos(), "'IDENT'", 2)
 	}
-	panic("ident expr is required")
+	return nil
 }
 
 func (p *parser) parseForPhrase() *ast.ForPhrase { // for k, v <- container, cond


Test patch:
diff --git a/parser/parser_test.go b/parser/parser_test.go
index 30c46fa9..9ece8b55 100644
--- a/parser/parser_test.go
+++ b/parser/parser_test.go
@@ -58,6 +58,33 @@ func TestErrMissingComma(t *testing.T) {
 	testErrCode(t, `func a(b int c)`, ``, `missing ',' in parameter list`)
 }
 
+func TestErrLambda(t *testing.T) {
+	testErrCode(t, `func test(v string, f func( int)) {
+}
+test "hello" => {
+	println "lambda",x
+}
+`, `/foo/bar.gop:3:6: expected 'IDENT', found "hello"`, ``)
+	testErrCode(t, `func test(v string, f func( int)) {
+}
+test "hello", "x" => {
+	println "lambda",x
+}
+`, `/foo/bar.gop:3:15: expected 'IDENT', found "x"`, ``)
+	testErrCode(t, `func test(v string, f func( int)) {
+}
+test "hello", ("x") => {
+	println "lambda",x
+}
+`, `/foo/bar.gop:3:16: expected 'IDENT', found "x"`, ``)
+	testErrCode(t, `func test(v string, f func(int,int)) {
+}
+test "hello", (x, "y") => {
+	println "lambda",x,y
+}
+`, `/foo/bar.gop:3:19: expected 'IDENT', found "y"`, ``)
+}
+
 func TestErrTooMany(t *testing.T) {
 	testErrCode(t, `
 func f() { var }