Repository: goplus/gop
Pull request #1286 (2022-06-18 05:44:41)

TestErrWrapCall/TestErrWrapCommand


Patch:
diff --git a/ast/ast.go b/ast/ast.go
index bec832a8..28e546bd 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -468,6 +468,11 @@ func (x *CallExpr) End() token.Pos {
 	return x.Rparen + 1
 }
 
+// IsCommand returns if a CallExpr is a command style CallExpr or not.
+func (x *CallExpr) IsCommand() bool {
+	return x.NoParenEnd != token.NoPos
+}
+
 // End returns position of first character immediately after the node.
 func (x *StarExpr) End() token.Pos { return x.X.End() }
 
diff --git a/cl/expr.go b/cl/expr.go
index 55d37889..09731b73 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -247,7 +247,7 @@ func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) {
 	case *ast.ParenExpr:
 		compileExpr(ctx, v.X, inFlags...)
 	case *ast.ErrWrapExpr:
-		compileErrWrapExpr(ctx, v)
+		compileErrWrapExpr(ctx, v, 0)
 	case *ast.FuncType:
 		ctx.cb.Typ(toFuncType(ctx, v, nil), v)
 	case *ast.Ellipsis:
@@ -468,6 +468,16 @@ func compileCallExpr(ctx *blockCtx, v *ast.CallExpr, inFlags int) {
 		compileIdent(ctx, fn, clIdentAllowBuiltin|inFlags)
 	case *ast.SelectorExpr:
 		compileSelectorExpr(ctx, fn, 0)
+	case *ast.ErrWrapExpr:
+		if v.IsCommand() {
+			callExpr := *v
+			callExpr.Fun = fn.X
+			ewExpr := *fn
+			ewExpr.X = &callExpr
+			compileErrWrapExpr(ctx, &ewExpr, inFlags)
+			return
+		}
+		compileErrWrapExpr(ctx, fn, 0)
 	default:
 		compileExpr(ctx, fn)
 	}
@@ -956,14 +966,14 @@ var (
 	tyError = types.Universe.Lookup("error").Type()
 )
 
-func compileErrWrapExpr(ctx *blockCtx, v *ast.ErrWrapExpr) {
+func compileErrWrapExpr(ctx *blockCtx, v *ast.ErrWrapExpr, inFlags int) {
 	pkg, cb := ctx.pkg, ctx.cb
 	useClosure := v.Tok == token.NOT || v.Default != nil
 	if !useClosure && (cb.Scope().Parent() == types.Universe) {
 		panic("TODO: can't use expr? in global")
 	}
 
-	compileExpr(ctx, v.X)
+	compileExpr(ctx, v.X, inFlags)
 	x := cb.InternalStack().Pop()
 	n := 0
 	results, ok := x.Type.(*types.Tuple)


Test patch:
diff --git a/cl/builtin_test.go b/cl/builtin_test.go
index d42087c5..0b7236f2 100644
--- a/cl/builtin_test.go
+++ b/cl/builtin_test.go
@@ -47,7 +47,7 @@ func TestCompileErrWrapExpr(t *testing.T) {
 	}()
 	pkg := gox.NewPackage("", "foo", goxConf)
 	ctx := &blockCtx{pkg: pkg, cb: pkg.CB()}
-	compileErrWrapExpr(ctx, &ast.ErrWrapExpr{Tok: token.QUESTION})
+	compileErrWrapExpr(ctx, &ast.ErrWrapExpr{Tok: token.QUESTION}, 0)
 }
 
 func TestToString(t *testing.T) {
diff --git a/cl/compile_test.go b/cl/compile_test.go
index da815440..989d5506 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -1411,7 +1411,7 @@ func foo(script string) {
 `)
 }
 
-func TestErrWrap(t *testing.T) {
+func TestErrWrapBasic(t *testing.T) {
 	gopClTest(t, `
 import "strconv"
 
@@ -1497,6 +1497,56 @@ var ret int = func() (_gop_ret int) {
 `)
 }
 
+func TestErrWrapCommand(t *testing.T) {
+	gopClTest(t, `
+func mkdir(name string) error {
+	return nil
+}
+
+mkdir! "foo"
+`, `package main
+
+func mkdir(name string) error {
+	return nil
+}
+func main() {
+	func() {
+		var _gop_err error
+		_gop_err = mkdir("foo")
+		if _gop_err != nil {
+			panic(_gop_err)
+		}
+		return
+	}()
+}
+`)
+}
+
+func TestErrWrapCall(t *testing.T) {
+	gopClTest(t, `
+func foo() (func(), error) {
+	return nil, nil
+}
+
+foo()!()
+`, `package main
+
+func foo() (func(), error) {
+	return nil, nil
+}
+func main() {
+	func() (_gop_ret func()) {
+		var _gop_err error
+		_gop_ret, _gop_err = foo()
+		if _gop_err != nil {
+			panic(_gop_err)
+		}
+		return
+	}()()
+}
+`)
+}
+
 func TestMakeAndNew(t *testing.T) {
 	gopClTest(t, `
 var a *int = new(int)