Git Product home page Git Product logo

yaegi's Introduction

Yaegi

release Build Status GoDoc

Yaegi is Another Elegant Go Interpreter. It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go runtime.

Features

  • Complete support of Go specification
  • Written in pure Go, using only the standard library
  • Simple interpreter API: New(), Eval(), Use()
  • Works everywhere Go works
  • All Go & runtime resources accessible from script (with control)
  • Security: unsafe and syscall packages neither used nor exported by default
  • Support the latest 2 major releases of Go (Go 1.21 and Go 1.22)

Install

Go package

import "github.com/traefik/yaegi/interp"

Command-line executable

go install github.com/traefik/yaegi/cmd/yaegi@latest

Note that you can use rlwrap (install with your favorite package manager), and alias the yaegi command in alias yaegi='rlwrap yaegi' in your ~/.bashrc, to have history and command line edition.

CI Integration

curl -sfL https://raw.githubusercontent.com/traefik/yaegi/master/install.sh | bash -s -- -b $GOPATH/bin v0.9.0

Usage

As an embedded interpreter

Create an interpreter with New(), run Go code with Eval():

package main

import (
	"github.com/traefik/yaegi/interp"
	"github.com/traefik/yaegi/stdlib"
)

func main() {
	i := interp.New(interp.Options{})

	i.Use(stdlib.Symbols)

	_, err := i.Eval(`import "fmt"`)
	if err != nil {
		panic(err)
	}

	_, err = i.Eval(`fmt.Println("Hello Yaegi")`)
	if err != nil {
		panic(err)
	}
}

Go Playground

As a dynamic extension framework

The following program is compiled ahead of time, except bar() which is interpreted, with the following steps:

  1. use of i.Eval(src) to evaluate the script in the context of interpreter
  2. use of v, err := i.Eval("foo.Bar") to get the symbol from the interpreter context, as a reflect.Value
  3. application of Interface() method and type assertion to convert v into bar, as if it was compiled
package main

import "github.com/traefik/yaegi/interp"

const src = `package foo
func Bar(s string) string { return s + "-Foo" }`

func main() {
	i := interp.New(interp.Options{})

	_, err := i.Eval(src)
	if err != nil {
		panic(err)
	}

	v, err := i.Eval("foo.Bar")
	if err != nil {
		panic(err)
	}

	bar := v.Interface().(func(string) string)

	r := bar("Kung")
	println(r)
}

Go Playground

As a command-line interpreter

The Yaegi command can run an interactive Read-Eval-Print-Loop:

$ yaegi
> 1 + 2
3
> import "fmt"
> fmt.Println("Hello World")
Hello World
>

Note that in interactive mode, all stdlib package are pre-imported, you can use them directly:

$ yaegi
> reflect.TypeOf(time.Date)
: func(int, time.Month, int, int, int, int, int, *time.Location) time.Time
>

Or interpret Go packages, directories or files, including itself:

$ yaegi -syscall -unsafe -unrestricted github.com/traefik/yaegi/cmd/yaegi
>

Or for Go scripting in the shebang line:

$ cat /tmp/test
#!/usr/bin/env yaegi
package main

import "fmt"

func main() {
	fmt.Println("test")
}
$ ls -la /tmp/test
-rwxr-xr-x 1 dow184 dow184 93 Jan  6 13:38 /tmp/test
$ /tmp/test
test

Documentation

Documentation about Yaegi commands and libraries can be found at usual godoc.org.

Limitations

Beside the known bugs which are supposed to be fixed in the short term, there are some limitations not planned to be addressed soon:

  • Assembly files (.s) are not supported.
  • Calling C code is not supported (no virtual "C" package).
  • Directives about the compiler, the linker, or embedding files are not supported.
  • Interfaces to be used from the pre-compiled code can not be added dynamically, as it is required to pre-compile interface wrappers.
  • Representation of types by reflect and printing values using %T may give different results between compiled mode and interpreted mode.
  • Interpreting computation intensive code is likely to remain significantly slower than in compiled mode.

Go modules are not supported yet. Until that, it is necessary to install the source into $GOPATH/src/github.com/traefik/yaegi to pass all the tests.

Contributing

Contributing guide.

License

Apache 2.0.

yaegi's People

Contributors

bai-yingjie avatar cclerget avatar creekorful avatar cuonglm avatar dennwc avatar dtomcej avatar firelizzard18 avatar for-acgn avatar jlevesy avatar julienbreux avatar juneezee avatar kamilsk avatar kortschak avatar ldez avatar mpl avatar mvertes avatar nrwiersma avatar rsteube avatar russellluo avatar sbinet avatar sentriz avatar sleeping-barber avatar svendowideit avatar theclapp avatar themightygit avatar traefiker avatar tttoad avatar ullaakut avatar whereswaldon avatar xaionaro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yaegi's Issues

multi-assign expression panic

The following program sample.go triggers a panic:

package main

func r2() (int, int) { return 1, 2 }
var a, b int = r2()
func main() { println(a, b) }

Expected result:

$ go run ./sample.go
1 2

Got:

$ dyngo ./sample.go
cfg.go:681: 20 unresolved symbol b
cfg.go:681: 34 unresolved symbol b
panic: reflect: call of reflect.Value.Set on zero Value

goroutine 1 [running]:
reflect.flag.mustBeAssignable(0x0)
	/usr/local/Cellar/go/1.11.4/libexec/src/reflect/value.go:227 +0xc0
reflect.Value.Set(0x0, 0x0, 0x0, 0x1778ea0, 0xc00009c9a8, 0x182)
	/usr/local/Cellar/go/1.11.4/libexec/src/reflect/value.go:1397 +0x2f
github.com/containous/dyngo/interp.assign.func1(0xc00009fc40, 0xc0000af7c0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:166 +0xb6
github.com/containous/dyngo/interp.runCfg(0xc00020d7a0, 0xc00009fc40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:73 +0x40
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0000ad2c0, 0xc00020c000, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:65 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0000ad2c0, 0xc0000ca380, 0x7a, 0xc0000ad2c0, 0xc0000ca380, 0x7a, 0x0, 0x1778ea0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:222 +0x35c
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:49 +0x32f

Pointer as receiver and slice

The following program sample.go triggers a panic:

package main

import "fmt"

type IntArray []int

func (h *IntArray) Add(x int) {
	*h = append(*h, x)
}

func main() {
	a := IntArray{}
	a.Add(4)

	fmt.Println(a)
}

// Output:
// [4]

Expected result:

$ go run ./sample.go
[4]

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x61710a]

goroutine 1 [running]:
testing.runExample.func2(0xbf0ec75995597752, 0x29112e, 0x12cf140, 0xc00000e050, 0xc0000aa008, 0xc00002e1e0, 0xc60bbd, 0xd, 0xc913b8, 0xc55b2b, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/example.go:116 +0x6f8
panic(0xb98540, 0x12b4f50)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.(*Type).TypeOf(0x0, 0x0, 0x1)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/type.go:466 +0x3a
github.com/containous/dyngo/interp.isInt(0x0, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/type.go:518 +0x2b
github.com/containous/dyngo/interp.(*Interpreter).Cfg.func2(0xc000216360)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:293 +0x4d83
github.com/containous/dyngo/interp.(*Node).Walk(0xc000216360, 0xc0001d5af8, 0xc0001d5ab8)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:114 +0xa5
github.com/containous/dyngo/interp.(*Node).Walk(0xc000216240, 0xc0001d5af8, 0xc0001d5ab8)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001ed440, 0xc0001d5af8, 0xc0001d5ab8)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001ec900, 0xc0001d5af8, 0xc0001d5ab8)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Interpreter).Cfg(0xc0001f41c0, 0xc0001ec900, 0x0, 0x0, 0x0, 0x0, 0x4)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:141 +0x1af
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001f41c0, 0xc86bd6, 0xa5, 0xc55e33, 0x4, 0xc0001f41c0, 0xc0001d5c98, 0x68)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:208 +0xfb
github.com/containous/dyngo/interp_test.Example_type8()
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp_test.go:6638 +0x97
testing.runExample(0xc60bbd, 0xd, 0xc913b8, 0xc55b2b, 0x4, 0x0, 0x0)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/example.go:121 +0x1fd
testing.runExamples(0xc0001d5ef0, 0x12c9e20, 0xcf, 0xcf, 0x410100)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/example.go:45 +0x1ad
testing.(*M).Run(0xc000184100, 0x0)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:1035 +0x1fb
main.main()
	_testmain.go:466 +0x13d

Functions returns

tree
├── _fninterface
│   └── src
│       └── github.com
│           └── foo
│               └── bar
│                   └── bar.go
└ my_test.go
my_test.go
package here

import (
	"path/filepath"
	"reflect"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestFunctionCall(t *testing.T) {
	goPath, err := filepath.Abs("./_fncall/")
	if err != nil {
		t.Fatal(err)
	}

	// Init go interpreter
	i := interp.New(interp.Opt{
		GoPath: goPath,
	})
	i.Use(stdlib.Value, stdlib.Type) // Use binary standard library

	if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
		t.Fatal(err)
	}

	fnNewSample, err := i.Eval(`bar.NewSample()`)
	if err != nil {
		t.Fatal(err)
	}

	values := fnNewSample.Call([]reflect.Value{reflect.ValueOf("aaa"), reflect.ValueOf("bbb")})

	fnHello := values[0].Interface().(func(string))
	fnHello("hello")
}
bar.go
package bar

import (
	"fmt"
)

var version = "v1"

func NewSample() func(string, string) func(string) {
	return func(val string, name string) func(string) {
		fmt.Println("in function", version, val, name)
		return func(msg string) {
			fmt.Println("here", msg)
		}
	}
}

Got:

panic: reflect: function created by MakeFunc using closure returned wrong type: have *interp.Node for func(string) [recovered]
	panic: reflect: function created by MakeFunc using closure returned wrong type: have *interp.Node for func(string)

goroutine 35 [running]:
testing.tRunner.func1(0xc000186200)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:792 +0x387
panic(0xb50b60, 0xc000176fb0)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.callReflect(0xc000236390, 0xc0001d5b20, 0xc0001d5b08)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:551 +0x7e6
reflect.makeFuncStub(0xc546f9, 0x3, 0xc54729, 0x3, 0x0, 0xb50b60, 0xc0002363d0, 0xdc0480, 0xc0001d5e28, 0x4d0c44, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/asm_amd64.s:20 +0x42
reflect.Value.call(0xc0001715c0, 0xc000236390, 0x13, 0xc54b10, 0x4, 0xc0001d5f68, 0x2, 0x2, 0x7050103, 0xc0002380b0, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:447 +0x454
reflect.Value.Call(0xc0001715c0, 0xc000236390, 0x13, 0xc0001d5f68, 0x2, 0x2, 0x0, 0x0, 0xf)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:308 +0xa4
github.com/containous/dyngo-exp.TestFunctionCall(0xc000186200)
	/home/ldez/sources/go/src/github.com/containous/dyngo-exp/fncall_test.go:33 +0x3ac
testing.tRunner(0xc000186200, 0xc86168)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:878 +0x35c

comparison between numeric values of different types panic

The following program sample.go triggers a panic:

package main

func main() {
    println(2 < 2.5)
}

Expected result:

$ go run ./sample.go
true

Got:

$ dyngo ./sample.go
panic: reflect: call of reflect.Value.Int on float64 Value [recovered]
	panic: reflect: call of reflect.Value.Int on float64 Value

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc00016c2d0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:95 +0x134
panic(0x17c11a0, 0xc000162720)
	/usr/local/Cellar/go/1.11.4/libexec/src/runtime/panic.go:513 +0x1b9
reflect.Value.Int(...)
	/usr/local/Cellar/go/1.11.4/libexec/src/reflect/value.go:961
github.com/containous/dyngo/interp.lower.func2(0xc00016c2d0, 0x18be028)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:905 +0x230
github.com/containous/dyngo/interp.runCfg(0xc0001d8ea0, 0xc00016c2d0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:100 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0001da070, 0xc0001d8480, 0xc00016c230)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:82 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001da070, 0xc000166030, 0x30, 0x188998f, 0x4, 0xc0001da070, 0x0, 0x1785820)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4bb
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

Multiple variables declaration separated by functions

The following program sample.go triggers a panic:

package main

import (
	"fmt"
)

type Foo struct {
	A string
}

var f Foo // <-- the root cause

func Hello() {
	fmt.Println("in")
}

var name = "v1" // <-- the root cause

func main() {
	Hello()
	fmt.Println("Hello", f.A, name)
}

Expected result:

$ go run ./sample.go
in
Hello  v1

Got:

$ dyngo ./sample.go
in
panic: runtime error: index out of range [recovered]
        panic: runtime error: index out of range

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc0001a85a0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:97 +0x134
panic(0xbe3840, 0x1644f70)
        /home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.callBin.func4(0xc0001a85a0, 0xc0001a8460)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:611 +0x299
github.com/containous/dyngo/interp.runCfg(0xc00020f320, 0xc0001a85a0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:102 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000216070, 0xc00020e360, 0x0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:84 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000216070, 0xc00021a000, 0x106, 0xc9f17f, 0x4, 0xc000216070, 0x0, 0x1157e98)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:233 +0x48c
main.main()
        /home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

Get function by Name

package sample

import (
	"fmt"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestSample(t *testing.T) {
    i := interp.New(interp.Opt{
        GoPath: "./_gopath/",
    })
    i.Use(stdlib.Value, stdlib.Type)

    if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
        t.Fatal(err)
    }

    val, err := i.Eval(`bar.NewFoo`)
    if err != nil {
        t.Fatal(err)
    }

    fmt.Println(val.Call(nil))
}
.
├── exp_test.go
└── _gopath
    └── src
        └── github.com
            └── foo
                └── bar
                    └── foobar.go
package bar

type Foo struct {
	A string
}

func NewFoo() *Foo {
	return &Foo{A: "test"}
}

Got:

panic: reflect: call of reflect.Value.Call on ptr Value [recovered]
	panic: reflect: call of reflect.Value.Call on ptr Value

goroutine 20 [running]:
testing.tRunner.func1(0xc0001fc200)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:792 +0x387
panic(0xb7b5e0, 0xc000174c60)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.flag.mustBe(0x16, 0x13)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:207 +0xb4
reflect.Value.Call(0xc000176440, 0xc00016a830, 0x16, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc000204180)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:306 +0x38
github.com/containous/dyngo-exp/exp01.TestPlugin.func1(0xc0001fc200)
	/home/ldez/sources/go/src/github.com/containous/dyngo-exp/exp01/exp_test.go:41 +0x1f0
testing.tRunner(0xc0001fc200, 0xc0001bf200)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:878 +0x35c

Review current test cases

a316f40

  • chan6.go ?
Got: "123 false\n"
want: "123 true\n"
  • select1.go ?
Got:  "start for\nreceived one\nfinish 1\nend for\nstart for\nreceived #2  false\nend for\nBye\n",
want: "start for\nreceived one\nfinish 1\nend for\nstart for\nreceived #2 two true\nend for\nBye\n"
  • ret1.go
Got: "<nil>\n"
want: "5\n"
  • run0.go
# command-line-arguments
../_test/run11.go:4:11: multiple-value f() in single-value context
    
exit status 2
  • run11.go
# command-line-arguments
../_test/run11.go:4:11: multiple-value f() in single-value context
    
exit status 2
  • time3.go
Got: "20\n"
want: "20 24 43\n"
  • type5.go
Got: "int\n"
want: "main.T\n"
  • type6.go
Got: "int\n"
want: "main.T\n"

Retrieval nil error (interface)

package exp02

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestSample(t *testing.T) {
	i := interp.New(interp.Opt{
		GoPath: "./_gopath",
	})
	i.Use(stdlib.Value, stdlib.Type)

	if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
		t.Fatal(err)
	}

	fn, err := i.Eval(`bar.New()`)
	if err != nil {
		t.Fatal(err)
	}

	args := []reflect.Value{reflect.ValueOf("toto")}
	results := fn.Call(args)
	fmt.Println(results)
}
package exp02

type Fromage struct {
	Name string
}
.
├── exp_test.go
├── _gopath
│   └── src
│       └── github.com
│           └── foo
│               └── bar
│                   └── foobar.go
└── types.go
package bar

import (
	"fmt"
)

func New() func(string) error {
	return func(v string) error {
		fmt.Println(v)
		fmt.Println("foo")
		// return fmt.Errorf("test")
		return nil
	}
}

Got:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x4c1546]

goroutine 19 [running]:
testing.tRunner.func1(0xc000170400)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:792 +0x387
panic(0xb88a60, 0x1284f50)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.(*rtype).String(0x0, 0xc48f30, 0x7)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/type.go:761 +0x26
reflect.callReflect(0xc000204360, 0xc0001bbb50, 0xc0001bbb38)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:553 +0x6c4
reflect.makeFuncStub(0xc45ac8, 0x4, 0x0, 0x0, 0xc0001bbe38, 0x4d0c44, 0xc0002042d0, 0xc000204360, 0xc000164e20, 0x1000000020, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/asm_amd64.s:20 +0x42
reflect.Value.call(0xb5c960, 0xc000204360, 0x13, 0xc451e4, 0x4, 0xc0001bbf68, 0x1, 0x1, 0x13, 0x0, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:447 +0x454
reflect.Value.Call(0xb5c960, 0xc000204360, 0x13, 0xc0001bbf68, 0x1, 0x1, 0x0, 0x0, 0x33)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:308 +0xa4
github.com/containous/dyngo-exp/exp02.TestSample02(0xc000170400)
	/home/ldez/sources/go/src/github.com/containous/dyngo-exp/exp02/exp_test.go:45 +0x2fd
testing.tRunner(0xc000170400, 0xc76390)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:878 +0x35c

Global vars

func Example_cli1() {
	src := `
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
)

func client(uri string) {
	resp, err := http.Get(uri)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(body))
}

func server(ln net.Listener, ready chan bool) {
	fmt.Printf("%p", http.DefaultServeMux)
	http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		var r1 *http.Request = r
		fmt.Fprintln(w, "Welcome to my website!", r1.RequestURI)
	})

	go http.Serve(ln, nil)
	ready <- true
}

func main() {
	http.DefaultServeMux = &http.ServeMux{}
	ln, err := net.Listen("tcp", ":0")
	if err != nil {
		log.Fatal(err)
	}
	defer ln.Close()

	ready := make(chan bool)
	go server(ln, ready)
	<-ready

	client(fmt.Sprintf("http://%s/hello", ln.Addr().String()))
	http.DefaultServeMux = &http.ServeMux{}
}
`
	i := interp.New(interp.Opt{Entry: "main"})
	i.Use(stdlib.Value, stdlib.Type)
	_, err := i.Eval(src)
	if err != nil {
		panic(err)
	}

	i = interp.New(interp.Opt{Entry: "main"})
	i.Use(stdlib.Value, stdlib.Type)
	_, err = i.Eval(src)
	if err != nil {
		panic(err)
	}

	// Output:
	// Welcome to my website! /hello
}
panic: http: multiple registrations for /hello [recovered]
	panic: http: multiple registrations for /hello

goroutine 31 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc000207130)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:97 +0x134
panic(0xb4b4c0, 0xc000296590)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
net/http.(*ServeMux).Handle(0x12bc4e0, 0xc0000a9321, 0x6, 0xdc3c60, 0xc000284d50)
	/home/ldez/.gvm/gos/go1.11.5/src/net/http/server.go:2377 +0x221
net/http.(*ServeMux).HandleFunc(0x12bc4e0, 0xc0000a9321, 0x6, 0xc000284d50)
	/home/ldez/.gvm/gos/go1.11.5/src/net/http/server.go:2395 +0x5a
net/http.HandleFunc(0xc0000a9321, 0x6, 0xc000284d50)
	/home/ldez/.gvm/gos/go1.11.5/src/net/http/server.go:2407 +0x4b
reflect.Value.call(0xb662e0, 0xc87fb0, 0x13, 0xc4e622, 0x4, 0xc000284cf0, 0x2, 0x2, 0xc00028d560, 0xb64c60, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:447 +0x454
reflect.Value.Call(0xb662e0, 0xc87fb0, 0x13, 0xc000284cf0, 0x2, 0x2, 0xc000284c01, 0xc000298360, 0xc000226f98)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:308 +0xa4
github.com/containous/dyngo/interp.callBin.func4(0xc000207130, 0xc000206e60)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:608 +0x1d0
github.com/containous/dyngo/interp.runCfg(0xc00028c6c0, 0xc000207130)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:102 +0x62
created by github.com/containous/dyngo/interp.call.func2
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:507 +0x671

Assignation of a func as a struct field

The following program sample.go triggers a panic:

package main

import "fmt"

type Fromage struct {
	Name string
	Call func(string) string
}

func main() {
	a := Fromage{}
	a.Name = "test"

	a.Call = func(s string) string {
		return s
	}

	fmt.Println(a.Call(a.Name))
}

// Output:
// test

Expected result:

$ go run ./sample.go
test

Got:

$ dyngo ./sample.go
panic: reflect.Set: value of type *interp.Node is not assignable to type func(string) string [recovered]
	panic: reflect.Set: value of type *interp.Node is not assignable to type func(string) string

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc0001944b0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xb9d580, 0xc000180a80)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.Value.assignTo(0xc1d700, 0xc0002570e0, 0x16, 0xcac792, 0xb, 0xbb83a0, 0x0, 0x120, 0xc96100, 0xc000217d01)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:2269 +0x44c
reflect.Value.Set(0xbb83a0, 0xc00017ee50, 0x193, 0xc1d700, 0xc0002570e0, 0x16)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:1403 +0xa7
github.com/containous/dyngo/interp.assign.func2(0xc0001944b0, 0xc00017ed60)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:208 +0xb6
github.com/containous/dyngo/interp.runCfg(0xc0002545a0, 0xc0001944b0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000200070, 0xc0001f9c20, 0xc000194460)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000200070, 0xc000204000, 0xf0, 0xca131f, 0x4, 0xc000200070, 0x0, 0x115a5b8)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

Invalid use of builtin triggers a panic

The following program sample.go triggers a panic:

package main

func main() {
    f := println
    f("hello")
}

Expected result:

$ go run ./sample.go
_test/bltn.go:4:7: use of builtin println not in function call

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11e718a]

goroutine 1 [running]:
github.com/containous/dyngo/interp.(*Type).TypeOf(0x0, 0x1, 0x1)
	/Users/marc/go/src/github.com/containous/dyngo/interp/type.go:458 +0x3a
github.com/containous/dyngo/interp.isInt(0x0, 0x213d000)
	/Users/marc/go/src/github.com/containous/dyngo/interp/type.go:510 +0x2b
github.com/containous/dyngo/interp.(*Interpreter).Cfg.func2(0xc0001dad80)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:277 +0x4b65
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001dad80, 0xc0001fbd80, 0xc0001fbd40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:114 +0xa5
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001dac60, 0xc0001fbd80, 0xc0001fbd40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001da6c0, 0xc0001fbd80, 0xc0001fbd40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001da480, 0xc0001fbd80, 0xc0001fbd40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Interpreter).Cfg(0xc0001e4070, 0xc0001da480, 0x0, 0x0, 0x0, 0x0, 0x4)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:141 +0x1af
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001e4070, 0xc0001e8000, 0x38, 0x188fa4f, 0x4, 0xc0001e4070, 0x0, 0x178ada0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:208 +0xfb
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

Unauthorized truncation

The following program sample.go:

package main

import "fmt"

func main() {
	var a int64 = 3
	a *= 4
	a = int64(3.2) // Error

	fmt.Println(a)
}

Expected result:

$ go run ./sample.go
sample.go:8:11: constant 3.2 truncated to integer

Got:

$ dyngo ./sample.go
3

Type alias

The following program sample.go triggers a panic:

package main

import "fmt"

type Root struct {
	Name string
}

func (r *Root) Hello() {
	fmt.Println("Hello", r.Name)
}

type One = Root

type Hi interface {
	Hello()
}

func main() {
	one := &One{Name: "test"}

	fmt.Println(one)
}

// Output:
// &{test}

Expected result:

$ go run ./sample.go
&{test}

Got:

$ dyngo ./sample.go
panic: reflect: call of reflect.Append on struct Value [recovered]
	panic: reflect: call of reflect.Append on struct Value

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc00019a500)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xbdc840, 0xc000188b80)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.flag.mustBe(0x199, 0x17)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:207 +0xb4
reflect.Append(0xc000207020, 0xc00018c8c0, 0x199, 0xc00021dd10, 0x1, 0x1, 0x0, 0x23, 0x7463757274732a2a)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:1891 +0x3e
github.com/containous/dyngo/interp.arrayLit.func2(0xc00019a500, 0xc000194640)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:944 +0x11d
github.com/containous/dyngo/interp.runCfg(0xc00025c360, 0xc00019a500)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000208070, 0xc00025b680, 0xc00019a4b0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000208070, 0xc00020c000, 0xff, 0xca583f, 0x4, 0xc000208070, 0x0, 0x115f2e0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

String comparison

The following program sample.go triggers a panic:

package main

import "fmt"

func main() {
	a := "hhh"
	a += "fff"

	fmt.Println(a > "ggg")
	fmt.Println(a >= "ggg")
	fmt.Println(a < "ggg")
	fmt.Println(a <= "ggg")
	fmt.Println(a == "hhhfff")
}

Expected result:

$ go run ./sample.go
true
true
false
false
true

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x603d49]

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc000196460)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:97 +0x134
panic(0xbe3840, 0x1644f30)
        /home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.greater.func8(0xc000196460, 0xc0001c9890)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/op.go:862 +0x49
github.com/containous/dyngo/interp.runCfg(0xc0001f6fc0, 0xc000196460)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:102 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0001fe070, 0xc0001f6900, 0xc000196410)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:84 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001fe070, 0xc000202000, 0x10d, 0xc9f17f, 0x4, 0xc0001fe070, 0x0, 0x1157f58)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
        /home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

Map and implicit slice type

The following program sample.go triggers a panic:

package main

import (
	"fmt"
	"sort"
)

func main() {
	m := map[string][]string{
		"hello": {"foo", "bar"},
		"world": {"truc", "machin"},
	}

	var content []string

	for key, values := range m {
		for _, value := range values {
			content = append(content, key+value)
		}
	}

	sort.Strings(content)
	fmt.Println(content)
}

Expected result:

$ go run ./sample.go
// [hellobar hellofoo worldmachin worldtruc]

Got:

$ dyngo ./sample.go 
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x5eb35a]

goroutine 1 [running]:
github.com/containous/dyngo/interp.(*Type).TypeOf(0x0, 0x1, 0x1)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/type.go:458 +0x3a
github.com/containous/dyngo/interp.arrayLit(0xc000231b00)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:854 +0x1c3
github.com/containous/dyngo/interp.setExec.func1(0xc000231b00)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:1150 +0xb2
github.com/containous/dyngo/interp.setExec.func1(0xc000231320)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:1139 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc000231560)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:1139 +0x25d
github.com/containous/dyngo/interp.setExec(0xc000231560)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:1153 +0xf5
github.com/containous/dyngo/interp.genRun.func1(0xc0002307e0, 0x1)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:976 +0x192
github.com/containous/dyngo/interp.(*Node).Walk(0xc0002307e0, 0xc0001ffdb0, 0x0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:107 +0xb5
github.com/containous/dyngo/interp.(*Node).Walk(0xc000230480, 0xc0001ffdb0, 0x0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001cdc20, 0xc0001ffdb0, 0x0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.genRun(0xc0001cdc20, 0x0, 0x0)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:961 +0x65
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0000fa700, 0xc0001ea000, 0x17e, 0xc9f17f, 0x4, 0xc0000fa700, 0x0, 0x1157e98)
        /home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:228 +0x34a
main.main()
        /home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

float and modulo

package main

import "fmt"

func main() {
	var e float32 = 64
	e %= 64
	fmt.Printf("e: %v %T", e, e)
	fmt.Println()
}

Expected result:

$ go run ./sample.go
# command-line-arguments
_test/opfloat32.go:7:4: invalid operation: e %= 64 (operator % not defined on float32)

Got:

$ dyngo ./sample.go
e: 0 int

package main

import "fmt"

func main() {
	var e float64 = 64
	e %= 64
	fmt.Printf("e: %v %T", e, e)
	fmt.Println()
}

Expected result:

$ go run ./sample.go
# command-line-arguments
_test/opfloat64.go:7:4: invalid operation: e %= 64 (operator % not defined on float64)

Got:

$ dyngo ./sample.go
e: 0 int

Better error handling in type parsing

An error in type parsing results in calls to log.Panicor log.Fatal. An error with source location and proper diagnostic should be returned instead.

struct with many fields panic

The following program sample.go triggers a panic:

package main

import "fmt"

type T struct {
    a, b, c, d, e, f, g, h, i, j, k, l, m, n string
    o map[string]int
    p []string
}

func main() {
    a := T{
        o: map[string]int{"truc": 1, "machin": 2},
        p: []string{"hello", "world"},
    }
    fmt.Println(a)
}

Expected result:

$ go run ./sample.go
{              map[truc:1 machin:2] [hello world]}

Got:

$ dyngo ./sample.go
panic: runtime error: index out of range

goroutine 1 [running]:
github.com/containous/dyngo/interp.frameTypes.func1(0xc000233440, 0x1)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1352 +0x2a7
github.com/containous/dyngo/interp.(*Node).Walk(0xc000233440, 0xc0001edc40, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:108 +0xb5
github.com/containous/dyngo/interp.(*Node).Walk(0xc000233200, 0xc0001edc40, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:112 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000232fc0, 0xc0001edc40, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:112 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000232ea0, 0xc0001edc40, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:112 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000232900, 0xc0001edc40, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:112 +0x66
github.com/containous/dyngo/interp.frameTypes(0xc000232900, 0x8, 0x0, 0xc00015a0f8, 0xc0001edce0, 0x11ce446, 0xc0001cec60)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1342 +0xd7
github.com/containous/dyngo/interp.genRun.func1(0xc000232900, 0xc0001edda8)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1121 +0x1b8
github.com/containous/dyngo/interp.(*Node).Walk(0xc000232900, 0xc0001edda8, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:108 +0xb5
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001ce360, 0xc0001edda8, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:112 +0x66
github.com/containous/dyngo/interp.genRun(0xc0001ce360, 0xc0001a12f0, 0xc00015e060)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1110 +0x65
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001d6070, 0xc0001da000, 0x153, 0x189b0ad, 0x4, 0xc0001d6070, 0x0, 0x1795a00)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:233 +0x397
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

Fix operators

Arithmetic and comparison operators should handle all possible types (mainly numeric), as defined in the go specification, not just int.

panic: reflect.Value.Call: call of nil function

The following program sample.go triggers a panic:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
)

func client(uri string) {
	resp, err := http.Get(uri)
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(body))
}

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Welcome to my website!")
	})

	server := httptest.NewServer(mux)
	defer server.Close()

	client(server.URL)
}

// Output:
// Welcome to my website!

Expected result:

$ go run ./sample.go
Welcome to my website!

Got:

$ dyngo ./sample.go
Welcome to my website!
panic: reflect.Value.Call: call of nil function

goroutine 1 [running]:
reflect.Value.call(0xc000179560, 0xc0001843e0, 0x193, 0xc911fb, 0x4, 0xc0001838a0, 0x0, 0x0, 0x0, 0x0, ...)
	/home/ldez/.gvm/gos/go1.11.4/src/reflect/value.go:344 +0x1620
reflect.Value.Call(0xc000179560, 0xc0001843e0, 0x193, 0xc0001838a0, 0x0, 0x0, 0xc000215d38, 0xc000179680, 0xc000190910)
	/home/ldez/.gvm/gos/go1.11.4/src/reflect/value.go:308 +0xa4
github.com/containous/dyngo/interp.runCfg.func1(0xc000190870)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:80 +0xe6
github.com/containous/dyngo/interp.runCfg(0xc00025a000, 0xc000190870)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0x6d
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000178de0, 0xc000259560, 0xc000190820)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:70 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000178de0, 0xc000202000, 0x22e, 0xc000178de0, 0xc000202000, 0x22e, 0x0, 0x114a118)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:230 +0x4bb
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x32f

Named import

The following program sample.go triggers a panic:

Based on example/pkg/_pkg1

package main

import (
	"fmt"

	fr "github.com/foo/pkg/fromage"
)

func Here() string {
	return "root"
}

func NewSample() func() string {
	return func() string {
		return fmt.Sprintf("%s %s", Here(), fr.Hello())
	}
}

Expected result:

$ go run ./sample.go
root Fromage!

Got:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x6205c7]

goroutine 36 [running]:
testing.tRunner.func1(0xc0001a4500)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:792 +0x387
panic(0xb87cc0, 0x1283f50)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.(*Interpreter).Cfg.func2(0xc0002545a0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:870 +0x2117
github.com/containous/dyngo/interp.(*Node).Walk(0xc0002545a0, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:114 +0xa5
github.com/containous/dyngo/interp.(*Node).Walk(0xc000254480, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000253c20, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000253b00, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0002539e0, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0002530e0, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000252fc0, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000252ea0, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000252120, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc00020eb40, 0xc0001f37b0, 0xc0001f3770)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Interpreter).Cfg(0xc0002161c0, 0xc00020eb40, 0xc0001a2160, 0x12, 0x0, 0x0, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:141 +0x1af
github.com/containous/dyngo/interp.(*Interpreter).importSrcFile(0xc0002161c0, 0x0, 0x0, 0xc0001a20e1, 0x12, 0xe6267aa9f807bc00, 0xc0000c9cb0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/src.go:60 +0x2d4
github.com/containous/dyngo/interp.(*Interpreter).Gta.func1(0xc00020e900, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/gta.go:103 +0x780
github.com/containous/dyngo/interp.(*Node).Walk(0xc00020e900, 0xc0001f3d80, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:107 +0xb5
github.com/containous/dyngo/interp.(*Node).Walk(0xc00020e7e0, 0xc0001f3d80, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc00020e5a0, 0xc0001f3d80, 0x0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Interpreter).Gta(0xc0002161c0, 0xc00020e5a0, 0x0, 0x0, 0x0, 0x125b03f)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/gta.go:16 +0xc7
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0002161c0, 0xc5b9a6, 0x1b, 0x0, 0x0, 0xc0002161c0, 0xf, 0x124ea6d)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:203 +0xca
github.com/containous/dyngo/example/pkg.TestPackages.func1(0xc0001a4500)
	/home/ldez/sources/go/src/github.com/containous/dyngo/example/pkg/pkg_test.go:75 +0x13f
testing.tRunner(0xc0001a4500, 0xc000198180)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:878 +0x35c

Pointer affectation inside a closure

The following program sample.go triggers a panic:

package main

import (
	"fmt"
)

type Config struct {
	A string
}

var conf *Config

func SetConfig() func(*Config) {
	return func(cf *Config) {
		conf = cf
	}
}

func main() {
	conf := &Config{
		A: "foo",
	}

	fmt.Println(conf.A)
}

Expected result:

$ go run ./sample.go
foo

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x5eb35a]

goroutine 1 [running]:
github.com/containous/dyngo/interp.(*Type).TypeOf(0x0, 0x1, 0x2)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/type.go:458 +0x3a
github.com/containous/dyngo/interp.isInt(0x0, 0xc000182148)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/type.go:510 +0x2b
github.com/containous/dyngo/interp.(*Interpreter).Cfg.func2(0xc000251560)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:277 +0x4b65
github.com/containous/dyngo/interp.(*Node).Walk(0xc000251560, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:114 +0xa5
github.com/containous/dyngo/interp.(*Node).Walk(0xc000251440, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000250a20, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc000250900, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0002507e0, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001fb9e0, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001fa5a0, 0xc000219d80, 0xc000219d40)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Interpreter).Cfg(0xc000202070, 0xc0001fa5a0, 0x0, 0x0, 0x0, 0x0, 0x4)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/cfg.go:141 +0x1af
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000202070, 0xc00008e200, 0xfd, 0xc9f17f, 0x4, 0xc000202070, 0x0, 0x1157e98)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:208 +0xfb
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

vendor: package in the previous vendor.

  • 1 level max vendor (flat):
.
|_ foo
|_ vendor
  |_ gh
  	|_ org
  	  |_ aaa (use bbb)
  	  |_ bbb

and

  • full gopath
.
|_ foo (use aaa)
|_ aaa (use bbb)
|_ bbb

and

  • fallback to GOPATH:
.
└── src
    ├── github.com
    │   └── foo
    │       └── pkg
    │           └── vendor
    │               └── guthib.com
    │                   └── containous
    │                       └── fromage (use cheese)
    │                           └── couteau
    └── guthib.com
        └── containous
            └── cheese
                └── vin

and

  • recursive vendor :
.
└── src
    └── github.com
        └── foo
            └── pkg (use vin)
                └── vendor
                    └── guthib.com
                        └── containous
                            ├── fromage
                            └── vin (use cheese)
                                └── vendor
                                    └── guthib.com
                                        └── containous
                                            └── cheese (use formage)

Interface conversion: assertion panic

The following program sample.go triggers a panic:

package main

import "fmt"

type Root struct {
	Name string
}

func (r *Root) Hello() {
	fmt.Println("Hello", r.Name)
}

type One Root

type Hi interface {
	Hello()
}

func main() {

	var root interface{} = &Root{Name: "test"}
	var one interface{} = &One{Name: "test"}

	fmt.Println(root.(Hi))
	fmt.Println(one.(Hi)) // panic
}

Expected result:

$ go run ./sample.go
&{test}
panic: interface conversion: *main.One is not main.Hi: missing method Hello

goroutine 1 [running]:
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/_test/type8.go:25 +0x124
exit status 2

Got:

$ dyngo ./sample.go
panic: reflect: call of reflect.Append on struct Value [recovered]
	panic: reflect: call of reflect.Append on struct Value

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc00009dd10)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xbdc840, 0xc00000dd00)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.flag.mustBe(0x199, 0x17)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:207 +0xb4
reflect.Append(0xc000081920, 0xc000146e40, 0x199, 0xc0001e1d10, 0x1, 0x1, 0xc000218040, 0xc000146ed0, 0x16)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:1891 +0x3e
github.com/containous/dyngo/interp.arrayLit.func2(0xc00009dd10, 0xc0002180c0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:944 +0x11d
github.com/containous/dyngo/interp.runCfg(0xc0002179e0, 0xc00009dd10)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0000d0700, 0xc000216ea0, 0xc00009dcc0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0000d0700, 0xc0001ca000, 0x198, 0xca583f, 0x4, 0xc0000d0700, 0x0, 0x115f2e0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

Type is not set in var declaration and assignment

The following program sample.go triggers an error:

package main

type T int

func (t T) foo() { println("foo", t) }

func main() {
    var t T = 2
    t.foo()
}

Expected result:

$ go run ./sample.go
foo 2

Got:

$ dyngo ./sample.go
_test/method10.go:9:2: undefined selector: foo

Use external type without values

package exp02

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestSample(t *testing.T) {
	i := interp.New(interp.Opt{
		GoPath: "./_gopath",
	})
	i.Use(stdlib.Value, stdlib.Type)

	var values = map[string]map[string]reflect.Value{}

	var tp = map[string]map[string]reflect.Type{
		"github.com/containous/dyngo-exp/exp02": {
			reflect.TypeOf(Fromage{}).Name(): reflect.TypeOf(Fromage{}),
		},
	}

	i.Use(values, tp)

	if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
		t.Fatal(err)
	}

	val, err := i.Eval(`bar.New()`)
	if err != nil {
		t.Fatal(err)
	}

	c := reflect.ValueOf(&Fromage{})

	fmt.Println(val.Call([]reflect.Value{c}))
}
package exp02

type Fromage struct {
	Name string
}
.
├── exp_test.go
├── _gopath
│   └── src
│       └── github.com
│           └── foo
│               └── bar
│                   └── foobar.go
└── types.go
package bar

import (
	"fmt"

	"github.com/containous/dyngo-exp/exp02"
)

func New() func(*exp02.Fromage) error {
	// return func(string) error {
	return func(c *exp02.Fromage) error {
		fmt.Println("foo")
		return nil
	}
}

Got:

exp_test.go:34: 1:22: undefined selector: New

Use extenal type

package exp02

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestSample02(t *testing.T) {
	i := interp.New(interp.Opt{
		GoPath: "./_gopath",
	})
	i.Use(stdlib.Value, stdlib.Type)

	var values = map[string]map[string]reflect.Value{
		"github.com/containous/dyngo-exp/exp02": {},
	}

	var tp = map[string]map[string]reflect.Type{
		"github.com/containous/dyngo-exp/exp02": {
			reflect.TypeOf(Fromage{}).Name(): reflect.TypeOf(Fromage{}),
		},
	}

	i.Use(values, tp)

	if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
		t.Fatal(err)
	}

	val, err := i.Eval(`bar.New()`)
	if err != nil {
		t.Fatal(err)
	}

	c := reflect.ValueOf(&Fromage{})

	fmt.Println(val.Call([]reflect.Value{c}))
}
package exp02

type Fromage struct {
	Name string
}
.
├── exp_test.go
├── _gopath
│   └── src
│       └── github.com
│           └── foo
│               └── bar
│                   └── foobar.go
└── types.go
package bar

import (
	"fmt"

	"github.com/containous/dyngo-exp/exp02"
)

// func New() func(string) error {
func New() func(*exp02.Fromage) error {
	// return func(string) error {
	return func(c *exp02.Fromage) error {
		fmt.Println("foo")
		return nil
	}
}

Got:

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x4c1546]

goroutine 35 [running]:
testing.tRunner.func1(0xc000186400)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:792 +0x387
panic(0xb87a60, 0x1283f50)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
reflect.(*rtype).String(0x0, 0xc47ed3, 0x7)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/type.go:761 +0x26
reflect.callReflect(0xc000234150, 0xc0001d5920, 0xc0001d5908)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:553 +0x6c4
reflect.makeFuncStub(0xc000178b60, 0x0, 0x0, 0xc00017ce20, 0xc0001d5c08, 0x4d0c44, 0xc0002340c0, 0xc000234150, 0xc00017ce20, 0x800000018, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/asm_amd64.s:20 +0x42
reflect.Value.call(0xc0001733e0, 0xc000234150, 0x13, 0xc44184, 0x4, 0xc0001d5d80, 0x1, 0x1, 0xba0980, 0xc00020a101, ...)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:447 +0x454
reflect.Value.Call(0xc0001733e0, 0xc000234150, 0x13, 0xc0001d5d80, 0x1, 0x1, 0x0, 0x0, 0x51cd2d)
	/home/ldez/.gvm/gos/go1.11.5/src/reflect/value.go:308 +0xa4
github.com/containous/dyngo-exp/exp02.TestSample02(0xc000186400)
	/home/ldez/sources/go/src/github.com/containous/dyngo-exp/exp02/exp_test.go:41 +0x4e6
testing.tRunner(0xc000186400, 0xc75330)
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
	/home/ldez/.gvm/gos/go1.11.5/src/testing/testing.go:878 +0x35c

Interface used as input argument of function called outside of the interpreter

tree
├── _fninterface
│   └── src
│       └── github.com
│           └── foo
│               └── bar
│                   └── bar.go
└ my_test.go
my_test.go
package sample

import (
	"fmt"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

type Huu struct {
	name string
}

func (h *Huu) Hello() {
	fmt.Println("Hello", h.name)
}

func TestInterfaceIn(t *testing.T) {
	goPath, err := filepath.Abs("./_fninterface/")
	if err != nil {
		t.Fatal(err)
	}

	// Init go interpreter
	i := interp.New(interp.Opt{
		GoPath: goPath,
	})
	i.Use(stdlib.Value, stdlib.Type) // Use binary standard library

	if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
		t.Fatal(err)
	}

	// Bar
	fnCall, err := i.Eval(`bar.Call()`)
	if err != nil {
		t.Fatal(err)
	}

	fnCall.Call([]reflect.Value{reflect.ValueOf(&Huu{name: "test"})})
}
bar.go
package bar

import (
	"fmt"
)

type Foo interface {
	Hello()
}

func Call() func(Foo) {
	return func(foo Foo) {
		fmt.Println("in")
		foo.Hello()
	}
}

Got:

   fninterface_test.go:34: _fninterface/src/github.com/foo/bar/bar.go:14:3: undefined selector: Hello

switch case panic

The following program sample.go triggers a panic:

package main
  
import "fmt"

func f(i int) bool {
    switch i {
    case 0:
        return false
    default:
        println("not nul")
        return true
    }
}

func main() {
    r0 := f(0)
    fmt.Printf("%T %v", r0, r0)
    fmt.Println()
    r1 := f(1)
    fmt.Printf("%T %v", r1, r1)
    fmt.Println()
}

Expected result:

$ go run ./sample.go
bool false
not nul
bool true

Got:

bool false
panic: reflect: call of reflect.Value.Interface on zero Value [recovered]
	panic: reflect: call of reflect.Value.Interface on zero Value [recovered]
	panic: reflect: call of reflect.Value.Interface on zero Value

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc0001764b0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0x17cd300, 0xc000166dc0)
	/usr/local/Cellar/go/1.11.5/libexec/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.runCfg.func1(0xc0001765a0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0x17cd300, 0xc000166dc0)
	/usr/local/Cellar/go/1.11.5/libexec/src/runtime/panic.go:513 +0x1b9
reflect.valueInterface(0x0, 0x0, 0x0, 0xc000000301, 0x17918c0, 0xc000170298)
	/usr/local/Cellar/go/1.11.5/libexec/src/reflect/value.go:983 +0x1a0
reflect.Value.Interface(0x0, 0x0, 0x0, 0x0, 0xc000170298)
	/usr/local/Cellar/go/1.11.5/libexec/src/reflect/value.go:978 +0x44
github.com/containous/dyngo/interp._case.func1(0xc0001765a0, 0xc0001b5a10)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:1096 +0xb9
github.com/containous/dyngo/interp.runCfg(0xc0001e38c0, 0xc0001765a0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.call.func2(0xc0001764b0, 0xc000081080)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:553 +0x84a
github.com/containous/dyngo/interp.runCfg(0xc000238ea0, 0xc0001764b0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0001e6070, 0xc0002385a0, 0xc000176460)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001e6070, 0xc0001ea000, 0x108, 0x18966cf, 0x4, 0xc0001e6070, 0x0, 0x17918c0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

string operations

package main

import "fmt"

func main() {
	a := "hhh"
	a += "fff"
	fmt.Printf("a: %v %T", a, a)
	fmt.Println()

	b := "hhh"
	b -= "fff" // FIXME expect an error
	fmt.Printf("b: %v %T", b, b)
	fmt.Println()

	c := "hhh"
	c *= "fff" // FIXME expect an error
	fmt.Printf("c: %v %T", c, c)
	fmt.Println()

	d := "hhh"
	d /= "fff" // FIXME expect an error
	fmt.Printf("d: %v %T", d, d)
	fmt.Println()

	e := "hhh"
	e %= "fff" // FIXME expect an error
	fmt.Printf("e: %v %T", e, e)
	fmt.Println()
}

Expected result:

$ go run ./sample.go
# command-line-arguments
_test/opstring.go:12:4: invalid operation: b -= "fff" (operator - not defined on string)
_test/opstring.go:17:4: invalid operation: c *= "fff" (operator * not defined on string)
_test/opstring.go:22:4: invalid operation: d /= "fff" (operator / not defined on string)
_test/opstring.go:27:4: invalid operation: e %= "fff" (operator % not defined on string)

Got:

$ dyngo ./sample.go
a: hhhfff string

Rune type

package main

import "fmt"

func main() {
	a := 'r'
	a += 'g'
	fmt.Printf("a: %v %T", a, a)
	fmt.Println()

	b := 'r'
	b -= 'g'
	fmt.Printf("b: %v %T", b, b)
	fmt.Println()

	c := 'r'
	c *= 'g'
	fmt.Printf("c: %v %T", c, c)
	fmt.Println()

	d := 'r'
	d /= 'g'
	fmt.Printf("d: %v %T", d, d)
	fmt.Println()

	e := 'r'
	e %= 'g'
	fmt.Printf("e: %v %T", e, e)
	fmt.Println()
}

Expected result:

$ go run ./sample.go
a: 217 int32
b: 11 int32
c: 11742 int32
d: 1 int32
e: 11 int32

Got:

$ dyngo ./sample.go
a: 217 uint8
b: 11 uint8
c: 222 uint8
d: 1 uint8
e: 11 uint8

Maybe related to #55

Interface conversion: composition

The following program sample.go triggers a panic:

package main

import "fmt"

type Root struct {
	Name string
}

func (r *Root) Hello() {
	fmt.Println("Hello", r.Name)
}

type One struct {
	Root
}
type Hi interface {
	Hello()
}

func main() {
	var root interface{} = &Root{Name: "test"}
	var one interface{} = &One{Root{Name: "test"}}

	fmt.Println(root.(Hi))
	one.(Hi).Hello()
}

// Output:
// &{test}
// Hello test

Expected result:

$ go run ./sample.go
&{test}
Hello test

Got:

$ dyngo ./sample.go
panic: interface conversion: interface {} is *struct { Name string }, not interp.valueInterface [recovered]
	panic: interface conversion: interface {} is *struct { Name string }, not interp.valueInterface

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc000186640)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xbef4a0, 0xc0001c7b30)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.genValueInterfaceValue.func1(0xc000186640, 0x1, 0x1, 0xc00017b060)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/value.go:108 +0xaa
github.com/containous/dyngo/interp.callBin.func4(0xc000186640, 0xc000186550)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:655 +0x100
github.com/containous/dyngo/interp.runCfg(0xc00024a480, 0xc000186640)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc0001f4070, 0xc0002498c0, 0xc0001865f0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001f4070, 0xc0001f8000, 0x174, 0xca583f, 0x4, 0xc0001f4070, 0x0, 0x115f2e0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

Map and implicit type

The following program sample.go triggers an error:

package main

import (
	"fmt"
	"sort"
)

type Foo struct {
	Name string
}

func main() {
	m := map[string]Foo{
		"hello": { Name: "bar"},
		"world": { Name: "machin"},
	}

	var content []string

	for key, value := range m {
		content = append(content, key+value.Name)
	}

	sort.Strings(content)
	fmt.Println(content)
}

Expected result:

$ go run ./sample.go
[hellobar worldmachin]

Got:

$ dyngo ./sample.go
./_test/map8.go:14:13: type definition not implemented: KeyValueExpr

Get global variable by name

package sample

import (
	"fmt"
	"testing"

	"github.com/containous/dyngo/interp"
	"github.com/containous/dyngo/stdlib"
)

func TestSample(t *testing.T) {
    i := interp.New(interp.Opt{
        GoPath: "./_gopath/",
    })
    i.Use(stdlib.Value, stdlib.Type)

    if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
        t.Fatal(err)
    }

    val, err := i.Eval(`bar.Bar`)
    if err != nil {
        t.Fatal(err)
    }

    fmt.Println(val.Call(nil))
}
.
├── exp_test.go
└── _gopath
    └── src
        └── github.com
            └── foo
                └── bar
                    └── foobar.go
package bar

var Bar = "bar"

Got:

<invalid Value>

assign sparse composite literal on binary struct panic

The following program sample.go triggers a panic:

package main
  
import (
    "fmt"
    "net/http"
    "time"
)

func main() {
    fmt.Println(http.DefaultClient.Timeout)
    http.DefaultClient = &http.Client{Timeout: 2 * time.Second}
    fmt.Println(http.DefaultClient.Timeout)
}

Expected result:

$ go run ./sample.go
0s
2s

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x11e814a]

goroutine 1 [running]:
github.com/containous/dyngo/interp.(*Type).TypeOf(0x0, 0x1, 0x1)
	/Users/marc/go/src/github.com/containous/dyngo/interp/type.go:466 +0x3a
github.com/containous/dyngo/interp.arrayLit(0xc00022a7e0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/run.go:927 +0x196
github.com/containous/dyngo/interp.setExec.func1(0xc00022a7e0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1204 +0xb2
github.com/containous/dyngo/interp.setExec.func1(0xc00022ac60)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc00022aea0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc00022b0e0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc00022a900)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc00022a360)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc0001d5680)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc0001d57a0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc0001d5c20)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc0001d5d40)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec.func1(0xc0001d58c0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1193 +0x25d
github.com/containous/dyngo/interp.setExec(0xc0001d58c0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1207 +0xf5
github.com/containous/dyngo/interp.genRun.func1(0xc0001d5320, 0x1)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1015 +0x192
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001d5320, 0xc0001f3db0, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:107 +0xb5
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001d4fc0, 0xc0001f3db0, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.(*Node).Walk(0xc0001d45a0, 0xc0001f3db0, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:111 +0x66
github.com/containous/dyngo/interp.genRun(0xc0001d45a0, 0x0, 0x0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/cfg.go:1000 +0x65
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc0001dc070, 0xc0001e0000, 0xd4, 0x18966cf, 0x4, 0xc0001dc070, 0x0, 0x17918c0)
	/Users/marc/go/src/github.com/containous/dyngo/interp/interp.go:228 +0x34a
main.main()
	/Users/marc/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334

float truncation should not be accepted in assign operations

The following program sample.go does not fail as it should:

package main

func main() {
     var a int = 3
     a += 1.3
}

Expected result:

$ go run ./sample.go
# command-line-arguments
./sample.go:5:4: constant 1.3 truncated to integer

Got:

$ dyngo ./sample.go
4

Interfaces used inside the interpreter

The following program sample.go gives an unexpected result:

package main

import "fmt"

type fii interface {
	Hello()
}

type Boo struct {
	Name string
}

func (b *Boo) Hello() {
	fmt.Println("Hello", b.Name)
}

func inCall(foo fii) {
	fmt.Println("inCall")
	foo.Hello()
}

func main() {
	fmt.Println("in")
	boo := &Boo{}
	inCall(boo)
}

// Output:
// in
// inCall
// Hello

Expected result:

$ go run ./sample.go
in
inCall
Hello

Got:

$ dyngo ./sample.go
_test/sample.go:19:2: undefined selector: Hello

Linked to #69

Mismatched types

The following program sample.go triggers a panic:

package main

import "fmt"

type Foo string
type Bar string

func main() {
	f := Foo("test")
	b := Bar("test")
	fmt.Println(f == b) // Error
}

Expected result:

$ go run ./sample.go
_test/type8.go:11:16: invalid operation: f == b (mismatched types Foo and Bar)

Got:

$ dyngo ./sample.go
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x604c49]

goroutine 1 [running]:
github.com/containous/dyngo/interp.runCfg.func1(0xc0001943c0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:103 +0x134
panic(0xbe9e00, 0x1650f30)
	/home/ldez/.gvm/gos/go1.11.5/src/runtime/panic.go:513 +0x1b9
github.com/containous/dyngo/interp.equal.func8(0xc0001943c0, 0xc0001c9b00)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/op.go:782 +0x49
github.com/containous/dyngo/interp.runCfg(0xc0001f9b00, 0xc0001943c0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:108 +0x62
github.com/containous/dyngo/interp.(*Interpreter).run(0xc000200070, 0xc0001f9200, 0xc000194370)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/run.go:90 +0xa6
github.com/containous/dyngo/interp.(*Interpreter).Eval(0xc000200070, 0xc000204000, 0x8f, 0xca583f, 0x4, 0xc000200070, 0x0, 0x115f2e0)
	/home/ldez/sources/go/src/github.com/containous/dyngo/interp/interp.go:236 +0x4c3
main.main()
	/home/ldez/sources/go/src/github.com/containous/dyngo/dyngo.go:50 +0x334
exit status 2

unary expressions fail

The following program sample.go fails:

package main

func main() {
    a := -1
    println(a)
}

Expected result:

$ go run ./sample.go
-1

Got:

$ dyngo ./sample.go
1:27: type definition not implemented: UnaryExpr

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.