yaegi icon indicating copy to clipboard operation
yaegi copied to clipboard

Yaegi panics when using a func in a template FuncMap

Open nrwiersma opened this issue 4 years ago • 3 comments

The following program sample.go triggers a panic:

package main

import (
	"bytes"
	"html/template"
)

var str = `{{ stringOr .Data "test" }}`

func main() {
	tmpl, err := template.New("test").
		Funcs(template.FuncMap{
			"stringOr": stringOr,
		}).
		Parse(str)
	if err != nil {
		println(err.Error())
		return
	}

	data := map[string]interface{}{"Data": ""}

	var buf bytes.Buffer
	if err  := tmpl.Execute(&buf, data); err != nil {
		println(err.Error())
		return
	}
	println(buf.String())
}

func stringOr(v, def string) string {
	if v == "" {
		return def
	}
	return v
}

Expected result:

$ go run ./sample.go
test

Got:

$ yaegi ./sample.go
./_test/test.go:11:15: panic
value for stringOr not a function
goroutine 1 [running]:
runtime/debug.Stack(0x1, 0xc0001fec00, 0x40)
	/usr/local/Cellar/go/1.15.2/libexec/src/runtime/debug/stack.go:24 +0x9f
github.com/traefik/yaegi/interp.(*Interpreter).eval.func1(0xc000113d08)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/interp.go:451 +0xc5
panic(0x19bbec0, 0xc00049a0d0)
	/usr/local/Cellar/go/1.15.2/libexec/src/runtime/panic.go:969 +0x175
github.com/traefik/yaegi/interp.runCfg.func1(0xc0002466e0, 0xc0001c9e00)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/run.go:124 +0x217
panic(0x19bbec0, 0xc00049a0d0)
	/usr/local/Cellar/go/1.15.2/libexec/src/runtime/panic.go:969 +0x175
text/template.addValueFuncs(0xc000494630, 0xc000494690)
	/usr/local/Cellar/go/1.15.2/libexec/src/text/template/funcs.go:92 +0x4c9
text/template.(*Template).Funcs(0xc0002e70c0, 0xc000494690, 0x0)
	/usr/local/Cellar/go/1.15.2/libexec/src/text/template/template.go:174 +0x9b
html/template.(*Template).Funcs(0xc000494660, 0xc000494690, 0x0)
	/usr/local/Cellar/go/1.15.2/libexec/src/html/template/template.go:344 +0x39
reflect.Value.call(0x1abe7e0, 0xc0001aac50, 0x1a93, 0x1ae7731, 0x4, 0xc00047b4a0, 0x1, 0x1, 0x18, 0xc00047b4a0, ...)
	/usr/local/Cellar/go/1.15.2/libexec/src/reflect/value.go:475 +0x8c7
reflect.Value.Call(0x1abe7e0, 0xc0001aac50, 0x1a93, 0xc00047b4a0, 0x1, 0x1, 0x1ae4ca0, 0x1a12401, 0xc00047b4a0)
	/usr/local/Cellar/go/1.15.2/libexec/src/reflect/value.go:336 +0xb9
github.com/traefik/yaegi/interp.callBin.func1(0x1abe7e0, 0xc0001aac50, 0x1a93, 0xc00047b4a0, 0x1, 0x1, 0x15, 0x19e64a0, 0xc00049a070)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/run.go:1078 +0x65
github.com/traefik/yaegi/interp.callBin.func10(0xc0002466e0, 0xc000498000)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/run.go:1225 +0x1c2
github.com/traefik/yaegi/interp.runCfg(0xc0001c9e00, 0xc0002466e0)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/run.go:130 +0x6e
github.com/traefik/yaegi/interp.(*Interpreter).run(0xc000374000, 0xc0001c9000, 0xc000246640)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/run.go:108 +0x2af
github.com/traefik/yaegi/interp.(*Interpreter).eval(0xc000374000, 0xc0002f5680, 0x20d, 0x7ffeefbff966, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/interp.go:543 +0x809
github.com/traefik/yaegi/interp.(*Interpreter).EvalPath(0xc000374000, 0x7ffeefbff966, 0xf, 0xc0002f5400, 0x20d, 0x0, 0x0, 0xc000478000)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/interp/interp.go:392 +0xfa
main.runFile(0xc000374000, 0x7ffeefbff966, 0xf, 0xc0001accc0, 0x1)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/cmd/yaegi/run.go:113 +0xae
main.run(0xc0001941a0, 0x1, 0x1, 0x1b2f318, 0x19cd9e0)
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/cmd/yaegi/run.go:77 +0x725
main.main()
	/Users/nrwiersma/Go/src/github.com/traefik/yaegi/cmd/yaegi/yaegi.go:119 +0x2ff

run: value for stringOr not a function
exit status 1

nrwiersma avatar Oct 05 '20 11:10 nrwiersma

Just retested it, and it works with v0.12.0

mvertes avatar May 24 '22 11:05 mvertes

Hi @mvertes, sorry for replying to a closed issue.

I encountered the same problem while using map[string]interface{} instead of template.FuncMap:

package main

import (
	"bytes"
	"html/template"
)

var str = `{{ stringOr .Data "test" }}`

func main() {
	tmpl, err := template.New("test").
-		Funcs(template.FuncMap{
+		Funcs(map[string]interface{}{
			"stringOr": stringOr,
		}).
		Parse(str)
	if err != nil {
		println(err.Error())
		return
	}

	data := map[string]interface{}{"Data": ""}

	var buf bytes.Buffer
	if err  := tmpl.Execute(&buf, data); err != nil {
		println(err.Error())
		return
	}
	println(buf.String())
}

func stringOr(v, def string) string {
	if v == "" {
		return def
	}
	return v
}

Got:

$ yaegi ./sample.go
./sample.go:11:15: panic
run: value for stringOr not a function
goroutine 1 [running]:
runtime/debug.Stack()
	/usr/local/go/src/runtime/debug/stack.go:24 +0x65
github.com/traefik/yaegi/interp.(*Interpreter).Execute.func1()
	/Users/russellluo/Labs/learn_go/projects/pkg/mod/github.com/traefik/[email protected]/interp/program.go:141 +0x94
panic({0x19296a0, 0xc000207e00})
	/usr/local/go/src/runtime/panic.go:838 +0x207
github.com/traefik/yaegi/interp.runCfg.func1()
	/Users/russellluo/Labs/learn_go/projects/pkg/mod/github.com/traefik/[email protected]/interp/run.go:192 +0x145
panic({0x19296a0, 0xc000207e00})
	/usr/local/go/src/runtime/panic.go:838 +0x207
text/template.addValueFuncs(0x10bb965?, 0x1c25540?)
	/usr/local/go/src/text/template/funcs.go:95 +0x314
text/template.(*Template).Funcs(0xc0002112c0, 0x1?)
	/usr/local/go/src/text/template/template.go:181 +0x15c
html/template.(*Template).Funcs(0xc0004b2e40, 0x106ce99?)
	/usr/local/go/src/html/template/template.go:346 +0x25
reflect.Value.call({0x1a268a0?, 0xc000208788?, 0x1011a25?}, {0x1a46745, 0x4}, {0xc000204c78, 0x1, 0xc0004a1948?})
	/usr/local/go/src/reflect/value.go:556 +0x845
reflect.Value.Call({0x1a268a0?, 0xc000208788?, 0x1053f52?}, {0xc000204c78, 0x1, 0x1})
	/usr/local/go/src/reflect/value.go:339 +0xbf
github.com/traefik/yaegi/interp.callBin.func2({0x1a268a0?, 0xc000208788?, 0xc0002087b8?}, {0xc000204c78?, 0xc0004b2e70?, 0xc000495968?})
...

RussellLuo avatar Jun 23 '22 02:06 RussellLuo

reopen it, due to above test

mvertes avatar Jun 23 '22 07:06 mvertes