Compare commits

...

49 Commits

Author SHA1 Message Date
Marc Vertes
c7fcfa8534 interp: fix interface wrapper generation
Add early detection of cases where no wrapper is necessary because
the value type already implements the target interface.

It should both increase performances by avoiding the wrapper overhead,
and fix errors due to replacing valid values by incomplete wrappers,
caused by the presence of private methods in the interface definition,
as in #1191.

Fixes #1191.
2021-07-19 15:38:11 +02:00
Ludovic Fernandez
aa012b992e chore: update linter
- update golangci-lint to v1.41.1
- fix GitHub action cache configuration
2021-07-17 12:14:06 +02:00
Marc Vertes
538182e12c interp: fix append of values to an array of interface objects
Interface wrappers were not properly generated.

Fixes #1185
2021-07-15 11:38:12 +02:00
Marc Vertes
13d554acbe interp: fix receiver for exported method objects
When a function variable is assigned from an exported method,
make sure the receiver is updated from the coresponding symbol.

Fixes #1182.
2021-07-13 11:00:14 +02:00
Marc Vertes
4fcf90edae interp: fix swap assign with extra operation
The optimization in unary operaror bypasses the necessary temporary
variable in that case and must be disabled.

Fixes #1181.
2021-07-12 18:00:09 +02:00
Marc Vertes
fc970799a1 interp: add support of interface wrappers to type assertions
Store the interpreter value of the interface object to wrap as
a field called IValue, at offset 0 in wrapper structures.

Update extract to include IValue field.

In typeAssert, detect interface wrapper, and dereference the
interpreter value from IValue wrapper field.

Fixes #1166.
2021-07-12 17:10:13 +02:00
Marc Vertes
78d7e85352 interp: fix method resolution on pointer to binary values
In that case, the value must be derefenced before extracting
the method by index, otherwise an incorrect method is returned.

Fixes #1167.
2021-07-09 12:08:14 +02:00
Marc Vertes
c503855262 interp: fix handling of interface value in forwarding return calls
Special wrapping of interface value at return is no longer necessary and
must be avoided now.

Fixes #1179.
2021-07-08 16:04:08 +02:00
Marc Vertes
77acfb4593 interp: fix type checking of address of multi dimension array
Fixes #1177.
2021-07-08 12:40:09 +02:00
Marc Vertes
f6d0cf95fd interp: fix array declaration with a typed constant size
In parsing array type declaration, The type check of array size was
restricted to `int`. Broaden the test to accept any valid integer
kind.

Fixes #1175.
2021-07-08 12:30:12 +02:00
Marc Vertes
25b570d7e9 interp: fix the detection of builtin calls during parsing
Avoid shortcuts, and apply regular scoping rules for symbol
resolution when checking for builtin calls.

Fixes #1173.
2021-07-08 11:26:05 +02:00
Marc Vertes
297b40d526 interp: improve field and method resolution in presence of collisions.
The resolution method was not compliant with the Go specification which
requires to retain the object where the field or method is the most
shallowed.

The detection of ambiguous fields or methods (same depth in different
objects) has also been added.

Fixes #1163.
2021-07-06 12:12:05 +02:00
Daniel Tomcej
bd2cb06789 Update README.md
This PR:

- Updates the Readme to reflect the current supported Go versions 😄
2021-07-06 08:16:13 +02:00
Ludovic Fernandez
3c5682150d chore: improve issue templates
- use new GitHub issue forms
- update readme badges and links
2021-07-02 11:00:08 +02:00
Marc Vertes
e32b2ab6bd interp: improve handling of interface values
In selector resolution, struct field matching now precedes
method matching. Before struct field matching could be skipped
in case of a matching method, which is incorrect, as demontrated
by _test/issue-1156.go.

Field lookup has been fixed to operate on recursive structures.

Concrete type values are derived when filling a receiver for
interface methods.

LookupBinField has been fixed to skip non struct values.

LookupMethod has been fixed to iterate on interface values as
well as concrete type values.

Fixes #1156.
2021-06-24 16:20:13 +02:00
Ethan Reesor
1df5dc2e93 Update Interpreter.Use API
### Background

#1102 changed how `Interpreter.Use` interprets export paths such that the last path component is stripped and used as the package name. This resulted in #1139 - attempting to Use an export with only one path component, such as `foo`, would result in the import path being `.`.

### Breaking API Change

This PR changes the signature of `Interpreter.Use` from `Use(Exports)` to `Use(Exports) error`.

### Fix for #1139

With this PR, if Use is called with an incomplete export path, such as `foo`, Use will return an error.
2021-06-24 10:00:05 +02:00
Ethan Reesor
36594014c9 Fix handling of ImportUsed packages
Fixes #1151

If I add a package with `Use` and import it with `ImportUsed`, the package is added to the universe scope as `<pkg>`. If I import with `Eval`, the package is added as `<pkg>/_.go`. However, `(*node).isType` (in cfg.go) only checks for `<pkg>/_.go`. Thus, packages imported with `ImportUsed` can be inaccessible.

This MR updates `(*node).isType` to fall back to `<pkg>` if `<pkg>/_.go` does not exist.
2021-06-21 11:24:10 +02:00
Marc Vertes
8f9eccdd61 interp: fix assign of function values with binary methods
In typecheck.go, detect binary methods so we know when to skip the receiver as first parameter when checking function signatures. The signature check is not yet performed, we just avoid a false error.

In cfg.go, take care to label types with isBinMethod field to true whenever a binary method is resolved.

Also, do not attempt to wrap node in functions if the node value is already a binary function.

Fixes #1145.
2021-06-18 12:56:05 +02:00
Marc Vertes
dd03989709 interp: fix handing nil when appending to a slice
Fixes #1147.
2021-06-18 12:44:07 +02:00
Marc Vertes
b2a11eaf2a interp: preserve concrete type when converting type to interface
This allows to fix the reassignment of an non empty interface value.
Before, reassignment was limited to empty interfaces.
    
Fixes #1138.
2021-06-18 10:32:13 +02:00
Ethan Reesor
25c2a435f5 Correctly resolve type aliases when building array literals
Fixes #1150

1. When resolving a selector expression involving an aliased type, resolve the aliased type
2. When building an array literal, resolve the aliased type

Aliases of named array and slice types were the only ones that didn't work, but I added the other test cases for the sake of completeness and through testing.
2021-06-18 10:10:10 +02:00
Ethan Reesor
3d1a21094a Avoid unnecessary calls to FieldByIndex
Fixes #1149

Because of how aliases are handled, `n.gen` is set to `getIndexSeqMethod` or `getIndexSeqPtrMethod` in cases like the one described in #1149. As a result, `FieldByIndex` can be called on a value that is not a struct, which causes a panic. This MR updates those two methods to avoid that call if the index array is empty.
2021-06-18 09:40:13 +02:00
Ethan Reesor
2a0d29a390 Add a newline after src in wrapInMain
Fixes #1142
2021-06-16 15:14:17 +02:00
Marc Vertes
db955e671f interp: fix append a slice on binary slice
Fixes #1128.
2021-06-15 14:34:08 +02:00
Ethan Reesor
ab44c38298 interp: handle binary array literals
This is a small change that allows use of composite array literals, such as:

```go
type Vec3 [3]float32

var foo = []Vec3{
	{1, 0, 0},
	{6, 0, 0},
	{6, 2, 0},
	{2, 2, 0},
	{1, 1, 0},
}
```
2021-06-14 14:48:05 +02:00
Marc Vertes
93e2db7085 interp: fix a wrong control flow in switch
In switch case expressions, the condition on case clause was
not always properly evaluated. Reverse the order of case clause
evaluations (as already done for if-else-if fashion), and fix the
wiring to false-next and true-next nodes.

Fixes #1126.
2021-06-14 12:18:07 +02:00
Marc Vertes
b1ef9251d4 interp: fix detection of binary types implementing interfaces
Fixes #1136.
2021-06-11 17:58:11 +02:00
Marc Vertes
b19afbfe93 interp: avoid panic in output value generation for recursive types
Fixes #1134.
2021-06-11 17:44:12 +02:00
Marc Vertes
a6762d500c interp: fix use of unrestricted symbols
This is fixing a regression introduced by #1102.

Fixes #1129.
2021-06-11 16:34:11 +02:00
Marc Vertes
c4174a7167 interp: fix assign of function call with implicit type assert.
De-optimize a use case to avoid skipping an assign operation with an implicit type assertion at function call return.

Fixes #1122.
2021-05-27 13:38:07 +02:00
Marc Vertes
2f9fe7003a interp: fix relative import path detection on MS-Windows
Fixes #1106.
2021-05-27 12:34:09 +02:00
Marc Vertes
c86436afa6 interp: fix litteral map containing binary functions
The case of assigning a binary function to a funcT object was
solved elsewhere. Factor the case in genDestValue to apply it
at multiple places.

Fixes #1100.
2021-05-27 12:04:11 +02:00
Marc Vertes
29e912e90b interp: fix method lookup on pointers to binary types
This case was missing in the selector expression processing.

Fixes #1083.
2021-05-27 11:54:04 +02:00
Marc Vertes
e29de04513 interp: fix constant types from imported packages
In binary packages, constants are wrapped in constant.Values, to
support arbitrary precision. Their type must therefore be converted
back to a regular type at import.

Fixes #1101.
2021-05-27 11:40:06 +02:00
Marc Vertes
c6945514cb interp: sandbox to preserve type of os.Stdin os.Stdout and os.Stderr
Use YAEGI_SPECIAL_STDIO env boolean to overwrite os.Stdxxx by
non file descriptors io.Writer / io.Reader interfaces. It is set
to true when testing to allow redirection to byte buffers.

The default behaviour is now to preserve the original concrete type
when sandboxing stdio, which maintains compatibility.

Fixes #1092.
2021-05-25 09:36:08 +02:00
Marc Vertes
847cd7ed2b interp: fix calling of variadic binary methods
Fixes #1046.
2021-05-22 11:48:07 +02:00
Marc Vertes
fbf897b047 interp: improve type check of binary methods
Some binary method calls were wrongly rejected. There is still
some ambiguous cases as binary method signature may include or
not the receiver as first argument, depending on how the method
was resolved.

With this fix, `import "golang.org/x/net/html"` doesn't panic
anymore, but not all tests are passing yet, i.e.
`yaegi test golang.org/x/net/html` still has failures, to be
investigated.

Fixes #1107.
2021-05-20 17:12:10 +02:00
Marc Vertes
45c7b8008a interp: fix special range on string
In this range variant "for k, v := range aString", k must
be the byte position of the rune in the byte array, rather than
the index of the rune in the rune array.

Fixes #1088.
2021-05-20 17:02:13 +02:00
Marc Vertes
4788775f8c interp: improve type checking for "+" operator
Fixes #1093.
2021-05-20 15:50:08 +02:00
Marc Vertes
bcb8546e91 interp: fix goto label by not overwriting destination
Fixes #1115
2021-05-20 11:38:04 +02:00
Marc Vertes
befa5a2b54 interp: fix return of function call involving a type conversion
In that case, direct propagation of result can not be attempted,
as the frame types will be different between the source and destination.
Disabling the optimisation and using The regular case involves an intermediate
frame entry, which enables the type conversion.

Fixes #1091.
2021-05-17 15:12:07 +02:00
Dan Kortschak
0ba64fc318 interp: add example to show use of Self
This example clarifies how `interp.Self` can be accessed.

Please take a look.
2021-05-10 14:06:09 +02:00
Marc Vertes
d16bd4bcdb interp: fix package name extraction from import path
The heuristic to generate a package name identifier was incorrect. Now for binary packages, the package identifier is obtained by a symbol, generated by extract, which contains the string argument of package statement in source file. This should ensure an always correct default package identifier. 

Fixes #1095.
2021-05-10 11:20:07 +02:00
Marc Vertes
33a532ee01 interp: fix a bug when assigning to an empty interface
The concrete type was not forwarded propertly in case of a binary
expression involving a valueT. The corresponding part in type.go
has been refactored and the now the multi-assign case should be
handled as well.

Fixes #1094.
2021-05-07 16:30:09 +02:00
Marc Vertes
cdc6b773c2 interp: add ImportUsed method to pre-import compiled packages
This feature was already present, but part of REPL only.
It's now also possible to apply it when evaluating a string
(-e flag). Default package names collision handling is no
longer hard-coded.

With -e flag, the eval result is now printed if valid, allowing
simpler commands:

     yaegi -e 'reflect.TypeOf(fmt.Printf)'

instead of:

     yaegi -e 'println(reflect.TypeOf(fmt.Printf))'

Fixes #1084.
2021-04-30 11:36:05 +02:00
Marc Vertes
17d5f1814a interp: fix support of interpreted functions in map values
Interpreted functions were represented in an inconsistent way in the frame: as a node pointer by default, and wrapped in a function wrapper for maps. 

We now simply use the default (*node) representation, as elsewhere, so values can be assigned, passed and called as for the other types. The alternative (generating a function wrapper) is more complex, costly and reserved for cases where the interpreted function can be called from the runtime.

Test that a map of functions can store both binary functions from used packages and interpreted ones.

Fixes #1090.
2021-04-30 11:26:04 +02:00
Marc Vertes
5f8be70066 interp: fix type string extraction for wrapped constants
Fixes #1089.
2021-04-29 18:08:03 +02:00
Marc Vertes
5530eca17d interp: give a self to the interpreter
The interpreter is exposed to itself through a "Self" var which
is set on "Use" of the interpreter package.

It allows meta-programming features, for example using "Eval" in
the current interpreter context, or enabling self-inspection
capabilities.
2021-04-21 16:26:03 +02:00
Marc Vertes
c8d9e25085 stdlib: add wrapper for testing/fstest package in go1.16 2021-04-19 09:38:03 +02:00
519 changed files with 2860 additions and 1047 deletions

View File

@@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
The following program `sample.go` triggers a panic:
```go
package main
func main() {
// add a sample
}
```
Expected result:
```console
$ go run ./sample.go
// output
```
Got:
```console
$ yaegi ./sample.go
// output
```

66
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Bug Report
description: Create a report to help us improve
body:
- type: markdown
attributes:
value: |
⚠️ Make sure to browse the opened and closed issues before submit your issue.
- type: textarea
id: sample
attributes:
label: "The following program `sample.go` triggers an unexpected result"
value: |
package main
func main() {
// add a sample
}
render: go
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected result
description: |-
```console
$ go run ./sample.go
// output
```
placeholder: $ go run ./sample.go
render: console
validations:
required: true
- type: textarea
id: got
attributes:
label: Got
description: |-
```console
$ yaegi ./sample.go
// output
```
placeholder: $ yaegi ./sample.go
render: console
validations:
required: true
- type: input
id: version
attributes:
label: Yaegi Version
description: Can be a tag or a hash.
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional Notes
description: Use [Markdown syntax](https://help.github.com/articles/github-flavored-markdown) if needed.
validations:
required: false

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Questions
url: https://community.traefik.io/c/yaegi
about: If you have a question, or are looking for advice, please post on our discussions forum!
- name: Documentation
url: https://pkg.go.dev/github.com/traefik/yaegi
about: Please take a look to our documenation.

View File

@@ -1,19 +0,0 @@
---
name: Feature request
about: Propose a change to Yaegi!
---
<!-- ⚠️ If you do not respect this template your issue will be closed. -->
<!-- ⚠️ Make sure to browse the opened and closed issues before submit your issue. -->
#### Proposal
<!-- Write your feature request in the form of a proposal to be considered for implementation -->
#### Background
<!-- Describe the background problem or need that led to this feature request -->
#### Workarounds
<!-- Are there any current workarounds that you're using that others in similar positions should know about? -->

View File

@@ -0,0 +1,32 @@
name: Feature request
description: Propose a change to Yaegi
body:
- type: markdown
attributes:
value: |
⚠️ Make sure to browse the opened and closed issues before submit your issue.
- type: textarea
id: proposal
attributes:
label: Proposal
description: Write your feature request in the form of a proposal to be considered for implementation.
validations:
required: true
- type: textarea
id: background
attributes:
label: Background
description: Describe the background problem or need that led to this feature request.
validations:
required: true
- type: textarea
id: workarounds
attributes:
label: Workarounds
description: Are there any current workarounds that you're using that others in similar positions should know about?
validations:
required: true

View File

@@ -45,11 +45,16 @@ jobs:
- name: Cache Go modules
uses: actions/cache@v2
with:
# In order:
# * Module download cache
# * Build cache (Linux)
# * Build cache (Mac)
# * Build cache (Windows)
path: |
~/go/pkg/mod # Module download cache
~/.cache/go-build # Build cache (Linux)
~/Library/Caches/go-build # Build cache (Mac)
'%LocalAppData%\go-build' # Build cache (Windows)
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
%LocalAppData%\go-build
key: ${{ runner.os }}-${{ matrix.go-version }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-${{ matrix.go-version }}-go-

View File

@@ -8,7 +8,7 @@ on:
env:
GO_VERSION: 1.16
GOLANGCI_LINT_VERSION: v1.36.0
GOLANGCI_LINT_VERSION: v1.41.1
jobs:

View File

@@ -23,13 +23,16 @@
[linters]
enable-all = true
disable = [
"maligned",
"golint", # deprecated
"scopelint", # deprecated
"interfacer", # deprecated
"maligned", # deprecated
"lll",
"gas",
"dupl",
"prealloc",
"scopelint",
"gocyclo",
"cyclop",
"gochecknoinits",
"gochecknoglobals",
"wsl",
@@ -49,6 +52,7 @@
"exhaustivestruct",
"forbidigo",
"ifshort",
"forcetypeassert",
"errorlint", # TODO: must be reactivate before fixes
]
@@ -61,6 +65,9 @@
[[issues.exclude-rules]]
path = "interp/.+_test\\.go"
linters = ["goconst"]
[[issues.exclude-rules]]
path = "interp/.+_test\\.go"
text = "var-declaration:"
[[issues.exclude-rules]]
path = "interp/interp.go"

View File

@@ -3,9 +3,9 @@
</p>
[![release](https://img.shields.io/github/tag-date/traefik/yaegi.svg?label=alpha)](https://github.com/traefik/yaegi/releases)
[![Build Status](https://travis-ci.com/traefik/yaegi.svg?branch=master)](https://travis-ci.com/traefik/yaegi)
[![GoDoc](https://godoc.org/github.com/traefik/yaegi?status.svg)](https://godoc.org/github.com/traefik/yaegi)
[![Discourse status](https://img.shields.io/discourse/https/community.containo.us/status?label=Community&style=social)](https://community.containo.us/c/yaegi)
[![Build Status](https://github.com/traefik/yaegi/actions/workflows/main.yml/badge.svg)](https://github.com/traefik/yaegi/actions/workflows/main.yml)
[![GoDoc](https://godoc.org/github.com/traefik/yaegi?status.svg)](https://pkg.go.dev/mod/github.com/traefik/yaegi)
[![Discourse status](https://img.shields.io/discourse/https/community.traefik.io/status?label=Community&style=social)](https://community.traefik.io/c/yaegi)
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.
@@ -18,7 +18,7 @@ It powers executable Go scripts and plugins, in embedded interpreters or interac
* 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 Go 1.13 and Go 1.14 (the latest 2 major releases)
* Support Go 1.15 and Go 1.16 (the latest 2 major releases)
## Install
@@ -186,7 +186,7 @@ Beside the known [bugs] which are supposed to be fixed in the short term, there
[Apache 2.0][License].
[specs]: https://golang.org/ref/spec
[docs]: https://godoc.org/github.com/traefik/yaegi
[docs]: https://pkg.go.dev/github.com/traefik/yaegi
[license]: https://github.com/traefik/yaegi/blob/master/LICENSE
[github]: https://github.com/traefik/yaegi
[bugs]: https://github.com/traefik/yaegi/issues?q=is%3Aissue+is%3Aopen+label%3Abug

View File

@@ -22,6 +22,12 @@ func main() {
var g int = 2
a = 10 + g
println(a.(int))
// multiple assignment
var foo interface{}
foo, a = "hello", 11 + g
println(a.(int))
println(foo.(string))
}
// Output:
@@ -31,3 +37,5 @@ func main() {
// 10
// 11
// 12
// 13
// hello

View File

@@ -57,7 +57,7 @@ func main() {
fmt.Println(err, vvv)
}
// Ouput:
// Output:
// <nil> {work bob@work.com}
// <nil> {work bob@work.com}
// <nil> {work bob@work.com}

View File

@@ -103,7 +103,7 @@ func main() {
intoMap()
}
// Ouput:
// Output:
// 0 : foo
// 1 : bar
// 0 : foo

14
_test/append3.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
a := []int{1, 2}
b := [2]int{3, 4}
fmt.Println(append(a, b[:]...))
fmt.Println(append(a, []int{5, 6}...))
}
// Output:
// [1 2 3 4]
// [1 2 5 6]

12
_test/append4.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
a := []*int{}
a = append(a, nil)
fmt.Println(a)
}
// Output:
// [<nil>]

9
_test/d1/d1.go Normal file
View File

@@ -0,0 +1,9 @@
package d1
type T struct {
Name string
}
func (t *T) F() { println(t.Name) }
func NewT(s string) *T { return &T{s} }

8
_test/d2/d2.go Normal file
View File

@@ -0,0 +1,8 @@
package d2
import "github.com/traefik/yaegi/_test/d1"
var (
X = d1.NewT("test")
F = X.F
)

11
_test/d3.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "github.com/traefik/yaegi/_test/d2"
func main() {
f := d2.F
f()
}
// Output:
// test

17
_test/interface52.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "testing"
func main() {
t := testing.T{}
var tb testing.TB
tb = &t
if tb.TempDir() == "" {
println("FAIL")
return
}
println("PASS")
}
// Output:
// PASS

14
_test/issue-1088.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
func main() {
for i, ch := range "日本語" {
fmt.Printf("%#U starts at byte position %d\n", ch, i)
}
}
// Output:
// U+65E5 '日' starts at byte position 0
// U+672C '本' starts at byte position 3
// U+8A9E '語' starts at byte position 6

13
_test/issue-1089.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(`"` + time.RFC3339Nano + `"`)
}
// Output:
// "2006-01-02T15:04:05.999999999Z07:00"

13
_test/issue-1093.go Normal file
View File

@@ -0,0 +1,13 @@
package main
func b() string {
return "b"
}
func main() {
var x int
x = "a" + b()
}
// Error:
// 9:6: cannot use type string as type int in assignment

12
_test/issue-1094.go Normal file
View File

@@ -0,0 +1,12 @@
package main
import "fmt"
func main() {
var x interface{}
x = "a" + fmt.Sprintf("b")
fmt.Printf("%v %T\n", x, x)
}
// Output:
// ab string

17
_test/issue-1101.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"fmt"
"net/http"
)
func main() {
method := "POST"
switch method {
case http.MethodPost:
fmt.Println("It's a post!")
}
}
// Output:
// It's a post!

24
_test/issue-1115.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import "fmt"
func main() {
outer:
for y := 0; y < 10; y++ {
for x := 0; x < 10; x++ {
if x == 5 && y == 5 {
break outer
}
}
fmt.Println(y)
}
fmt.Println("Yay! I finished!")
}
// Output:
// 0
// 1
// 2
// 3
// 4
// Yay! I finished!

23
_test/issue-1126.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import (
"errors"
"fmt"
"strings"
)
func main() {
err := errors.New("hello there")
switch true {
case err == nil:
break
case strings.Contains(err.Error(), "hello"):
fmt.Println("True!")
default:
fmt.Println("False!")
}
}
// Output:
// True!

10
_test/issue-1128.go Normal file
View File

@@ -0,0 +1,10 @@
package main
import "net"
func main() {
c := append(net.Buffers{}, []byte{})
println(len(c))
}
// Output: 1

20
_test/issue-1134.go Normal file
View File

@@ -0,0 +1,20 @@
package main
type I interface {
Hello()
}
type T struct {
Name string
Child []*T
}
func (t *T) Hello() { println("Hello", t.Name) }
func main() {
var i I = new(T)
i.Hello()
}
// Output:
// Hello

22
_test/issue-1136.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"fmt"
"io"
)
type T struct {
r io.Reader
}
func (t *T) Read(p []byte) (n int, err error) { n, err = t.r.Read(p); return }
func main() {
x := io.LimitedReader{}
y := io.Reader(&x)
y = &T{y}
fmt.Println(y.Read([]byte("")))
}
// Output:
// 0 EOF

14
_test/issue-1145.go Normal file
View File

@@ -0,0 +1,14 @@
package main
import "sync"
type F func()
func main() {
var wg sync.WaitGroup
var f F = wg.Done
println(f != nil)
}
// Output:
// true

25
_test/issue-1156.go Normal file
View File

@@ -0,0 +1,25 @@
package main
type myInterface interface {
myFunc() string
}
type V struct{}
func (v *V) myFunc() string { return "hello" }
type U struct {
v myInterface
}
func (u *U) myFunc() string { return u.v.myFunc() }
func main() {
x := V{}
y := myInterface(&x)
y = &U{y}
println(y.myFunc())
}
// Output:
// hello

41
_test/issue-1163.go Normal file
View File

@@ -0,0 +1,41 @@
package main
import "fmt"
type WidgetEvent struct {
Nothing string
}
type WidgetControl interface {
HandleEvent(e *WidgetEvent)
}
type Button struct{}
func (b *Button) HandleEvent(e *WidgetEvent) {
}
type WindowEvent struct {
Something int
}
type Window struct {
Widget WidgetControl
}
func (w *Window) HandleEvent(e *WindowEvent) {
}
func main() {
window := &Window{
Widget: &Button{},
}
windowevent := &WindowEvent{}
// The next line uses the signature from the wrong method, resulting in an error.
// Renaming one of the clashing method names fixes the problem.
window.HandleEvent(windowevent)
fmt.Println("OK!")
}
// Output:
// OK!

24
_test/issue-1166.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"fmt"
"io"
)
type T []byte
func (t *T) Write(p []byte) (n int, err error) { *t = append(*t, p...); return len(p), nil }
func foo(w io.Writer) {
a := w.(*T)
fmt.Fprint(a, "test")
fmt.Printf("%s\n", *a)
}
func main() {
x := T{}
foo(&x)
}
// Output:
// test

19
_test/issue-1167.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
)
func main() {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(err)
}
pub := key.Public().(*ecdsa.PublicKey)
println(pub.Params().Name)
}
// Output:
// P-256

10
_test/issue-1173.go Normal file
View File

@@ -0,0 +1,10 @@
package main
var real = func() { println("Hello") }
func main() {
real()
}
// Output:
// Hello

18
_test/issue-1175.go Normal file
View File

@@ -0,0 +1,18 @@
package main
type Level int8
const (
a Level = -1
b Level = 5
d = b - a + 1
)
type counters [d]int
func main() {
println(len(counters{}))
}
// Output:
// 7

13
_test/issue-1177.go Normal file
View File

@@ -0,0 +1,13 @@
package main
type counters [3][16]int
func main() {
cs := &counters{}
p := &cs[0][1]
*p = 2
println(cs[0][1])
}
// Output:
// 2

23
_test/issue-1179.go Normal file
View File

@@ -0,0 +1,23 @@
package main
type I interface {
F()
}
type T struct {
Name string
}
func (t *T) F() { println("in F", t.Name) }
func NewI(s string) I { return newT(s) }
func newT(s string) *T { return &T{s} }
func main() {
i := NewI("test")
i.F()
}
// Output:
// in F test

10
_test/issue-1181.go Normal file
View File

@@ -0,0 +1,10 @@
package main
func main() {
a, b := 1, 2
a, b = b, -a
println(a, b)
}
// Output:
// 2 -1

20
_test/issue-1185.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import "io"
type B []byte
func (b B) Write(p []byte) (n int, err error) {
b = p
return len(p), nil
}
func main() {
b := B{}
a := make([]io.Writer, 0)
a = append(a, b)
println(len(a))
}
// Output:
// 1

27
_test/map30.go Normal file
View File

@@ -0,0 +1,27 @@
package main
import "strings"
func f(s string) string { return "hello " + s }
func g(s string) string { return "hi " + s }
var methods = map[string]func(string) string{
"f": f,
"h": strings.ToLower,
}
func main() {
methods["i"] = strings.ToUpper
methods["g"] = g
println(methods["f"]("test"))
println(methods["g"]("test"))
println(methods["i"]("test"))
println(methods["h"]("TEST"))
}
// Output:
// hello test
// hi test
// TEST
// test

19
_test/method37.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import (
"net"
"os"
)
func writeBufs(bufs ...[]byte) error {
b := net.Buffers(bufs)
_, err := b.WriteTo(os.Stdout)
return err
}
func main() {
writeBufs([]byte("hello"))
}
// Output:
// hello

28
_test/ret8.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import "fmt"
type CustomError string
func (s CustomError) Error() string {
return string(s)
}
func NewCustomError(errorText string) CustomError {
return CustomError(errorText)
}
func fail() (err error) {
return NewCustomError("Everything is going wrong!")
}
func main() {
fmt.Println(fail())
var myError error
myError = NewCustomError("ok")
fmt.Println(myError)
}
// Output:
// Everything is going wrong!
// ok

View File

@@ -6,6 +6,7 @@ import (
"go/build"
"io/ioutil"
"os"
"reflect"
"strconv"
"strings"
@@ -18,6 +19,7 @@ import (
func run(arg []string) error {
var interactive bool
var noAutoImport bool
var tags string
var cmd string
var err error
@@ -33,6 +35,7 @@ func run(arg []string) error {
rflag.BoolVar(&useUnrestricted, "unrestricted", useUnrestricted, "include unrestricted symbols")
rflag.StringVar(&tags, "tags", "", "set a list of build tags")
rflag.BoolVar(&useUnsafe, "unsafe", useUnsafe, "include unsafe symbols")
rflag.BoolVar(&noAutoImport, "noautoimport", false, "do not auto import pre-compiled packages. Import names that would result in collisions (e.g. rand from crypto/rand and rand from math/rand) are automatically renamed (crypto_rand and math_rand)")
rflag.StringVar(&cmd, "e", "", "set the command to be executed (instead of script or/and shell)")
rflag.Usage = func() {
fmt.Println("Usage: yaegi run [options] [path] [args]")
@@ -45,48 +48,68 @@ func run(arg []string) error {
args := rflag.Args()
i := interp.New(interp.Options{GoPath: build.Default.GOPATH, BuildTags: strings.Split(tags, ",")})
i.Use(stdlib.Symbols)
i.Use(interp.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
return err
}
if err := i.Use(interp.Symbols); err != nil {
return err
}
if useSyscall {
i.Use(syscall.Symbols)
if err := i.Use(syscall.Symbols); err != nil {
return err
}
// Using a environment var allows a nested interpreter to import the syscall package.
if err := os.Setenv("YAEGI_SYSCALL", "1"); err != nil {
return err
}
}
if useUnsafe {
i.Use(unsafe.Symbols)
if err := i.Use(unsafe.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNSAFE", "1"); err != nil {
return err
}
}
if useUnrestricted {
// Use of unrestricted symbols should always follow stdlib and syscall symbols, to update them.
i.Use(unrestricted.Symbols)
if err := i.Use(unrestricted.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNRESTRICTED", "1"); err != nil {
return err
}
}
if cmd != "" {
_, err = i.Eval(cmd)
if !noAutoImport {
i.ImportUsed()
}
var v reflect.Value
v, err = i.Eval(cmd)
if len(args) == 0 && v.IsValid() {
fmt.Println(v)
}
}
if len(args) == 0 {
if interactive || cmd == "" {
if cmd == "" || interactive {
showError(err)
if !noAutoImport {
i.ImportUsed()
}
_, err = i.REPL()
}
return err
}
// Skip first os arg to set command line as expected by interpreted main
// Skip first os arg to set command line as expected by interpreted main.
path := args[0]
os.Args = arg
flag.CommandLine = flag.NewFlagSet(path, flag.ExitOnError)
if isFile(path) {
err = runFile(i, path)
err = runFile(i, path, noAutoImport)
} else {
_, err = i.EvalPath(path)
}
@@ -106,7 +129,7 @@ func isFile(path string) bool {
return err == nil && fi.Mode().IsRegular()
}
func runFile(i *interp.Interpreter, path string) error {
func runFile(i *interp.Interpreter, path string, noAutoImport bool) error {
b, err := ioutil.ReadFile(path)
if err != nil {
return err
@@ -115,6 +138,9 @@ func runFile(i *interp.Interpreter, path string) error {
if s := string(b); strings.HasPrefix(s, "#!") {
// Allow executable go scripts, Have the same behavior as in interactive mode.
s = strings.Replace(s, "#!", "//", 1)
if !noAutoImport {
i.ImportUsed()
}
_, err = i.Eval(s)
return err
}

View File

@@ -117,23 +117,33 @@ func test(arg []string) (err error) {
}
i := interp.New(interp.Options{GoPath: build.Default.GOPATH, BuildTags: strings.Split(tags, ",")})
i.Use(stdlib.Symbols)
i.Use(interp.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
return err
}
if err := i.Use(interp.Symbols); err != nil {
return err
}
if useSyscall {
i.Use(syscall.Symbols)
if err := i.Use(syscall.Symbols); err != nil {
return err
}
// Using a environment var allows a nested interpreter to import the syscall package.
if err := os.Setenv("YAEGI_SYSCALL", "1"); err != nil {
return err
}
}
if useUnrestricted {
i.Use(unrestricted.Symbols)
if err := i.Use(unrestricted.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNRESTRICTED", "1"); err != nil {
return err
}
}
if useUnsafe {
i.Use(unsafe.Symbols)
if err := i.Use(unsafe.Symbols); err != nil {
return err
}
if err := os.Setenv("YAEGI_UNSAFE", "1"); err != nil {
return err
}

View File

@@ -9,7 +9,9 @@ import (
func TestFunctionCall(t *testing.T) {
i := interp.New(interp.Options{GoPath: "./_pkg"})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
_, err := i.Eval(`import "foo/bar"`)
if err != nil {

View File

@@ -10,7 +10,9 @@ import (
func TestGetFunc(t *testing.T) {
i := interp.New(interp.Options{GoPath: "./_gopath/"})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
if _, err := i.Eval(`import "github.com/foo/bar"`); err != nil {
t.Fatal(err)

View File

@@ -111,7 +111,10 @@ func TestPackages(t *testing.T) {
var stdout, stderr bytes.Buffer
i := interp.New(interp.Options{GoPath: goPath, Stdout: &stdout, Stderr: &stderr})
i.Use(stdlib.Symbols) // Use binary standard library
// Use binary standard library
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
var msg string
if test.evalFile != "" {
@@ -170,7 +173,10 @@ func TestPackagesError(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
// Init go interpreter
i := interp.New(interp.Options{GoPath: test.goPath})
i.Use(stdlib.Symbols) // Use binary standard library
// Use binary standard library
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
// Load pkg from sources
_, err := i.Eval(`import "github.com/foo/pkg"`)

View File

@@ -16,6 +16,7 @@ import (
"io"
"math/big"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
@@ -24,7 +25,7 @@ import (
"text/template"
)
const model = `// Code generated by 'yaegi extract {{.PkgName}}'. DO NOT EDIT.
const model = `// Code generated by 'yaegi extract {{.ImportPath}}'. DO NOT EDIT.
{{.License}}
@@ -38,7 +39,7 @@ import (
"{{$key}}"
{{- end}}
{{- end}}
"{{.PkgName}}"
"{{.ImportPath}}"
"reflect"
)
@@ -73,6 +74,7 @@ func init() {
{{range $key, $value := .Wrap -}}
// {{$value.Name}} is an interface wrapper for {{$key}} type
type {{$value.Name}} struct {
IValue interface{}
{{range $m := $value.Method -}}
W{{$m.Name}} func{{$m.Param}} {{$m.Result}}
{{end}}
@@ -270,14 +272,15 @@ func (e *Extractor) genContent(importPath string, p *types.Package) ([]byte, err
b := new(bytes.Buffer)
data := map[string]interface{}{
"Dest": e.Dest,
"Imports": imports,
"PkgName": importPath,
"Val": val,
"Typ": typ,
"Wrap": wrap,
"BuildTags": buildTags,
"License": e.License,
"Dest": e.Dest,
"Imports": imports,
"ImportPath": importPath,
"PkgName": path.Join(importPath, p.Name()),
"Val": val,
"Typ": typ,
"Wrap": wrap,
"BuildTags": buildTags,
"License": e.License,
}
err = parse.Execute(b, data)
if err != nil {

View File

@@ -18,7 +18,7 @@ import (
)
func init() {
Symbols["guthib.com/baz"] = map[string]reflect.Value{
Symbols["guthib.com/baz/baz"] = map[string]reflect.Value{
// function, constant and variable definitions
"Hello": reflect.ValueOf(baz.Hello),
}
@@ -101,7 +101,7 @@ import (
)
func init() {
Symbols["guthib.com/variadic"] = map[string]reflect.Value{
Symbols["guthib.com/variadic/variadic"] = map[string]reflect.Value{
// type definitions
"Variadic": reflect.ValueOf((*variadic.Variadic)(nil)),
@@ -112,7 +112,8 @@ func init() {
// _guthib_com_variadic_Variadic is an interface wrapper for Variadic type
type _guthib_com_variadic_Variadic struct {
WCall func(method string, args ...[]interface{}) (interface{}, error)
IValue interface{}
WCall func(method string, args ...[]interface{}) (interface{}, error)
}
func (W _guthib_com_variadic_Variadic) Call(method string, args ...[]interface{}) (interface{}, error) {

View File

@@ -357,7 +357,7 @@ func ignoreError(err error, src string) bool {
}
func wrapInMain(src string) string {
return fmt.Sprintf("package main; func main() {%s}", src)
return fmt.Sprintf("package main; func main() {%s\n}", src)
}
// Note: no type analysis is performed at this stage, it is done in pre-order

View File

@@ -7,7 +7,6 @@ import (
"math"
"path/filepath"
"reflect"
"regexp"
"strings"
"unicode"
)
@@ -44,8 +43,6 @@ var constBltn = map[string]func(*node){
bltnReal: realConst,
}
var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
const nilIdent = "nil"
// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
@@ -154,6 +151,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
case reflect.String:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
sc.add(sc.getType("int")) // Add a dummy type to store index for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case reflect.Array, reflect.Slice:
@@ -177,6 +175,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
case stringT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
sc.add(sc.getType("int")) // Add a dummy type to store index for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case arrayT, sliceT, variadicT:
@@ -558,9 +557,6 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.findex = dest.findex
n.level = dest.level
// Propagate type.
// TODO: Check that existing destination type matches source type.
// In the following, we attempt to optimize by skipping the assign
// operation and setting the source location directly to the destination
// location in the frame.
@@ -578,6 +574,10 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
// Setting a struct field of function type requires an extra step. Do not optimize.
case isCall(src) && !isInterfaceSrc(dest.typ) && !isRecursiveField(dest) && n.kind != defineStmt:
// Call action may perform the assignment directly.
if dest.typ.id() != src.typ.id() {
// Skip optimitization if returned type doesn't match assigned one.
break
}
n.gen = nop
src.level = level
src.findex = dest.findex
@@ -864,7 +864,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
case callExpr:
wireChild(n)
switch {
case interp.isBuiltinCall(n):
case isBuiltinCall(n, sc):
c0 := n.child[0]
bname := c0.ident
err = check.builtin(bname, n, n.child[1:], n.action == aCallSlice)
@@ -930,9 +930,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
if !c1.typ.implements(c0.typ) {
err = n.cfgErrorf("type %v does not implement interface %v", c1.typ.id(), c0.typ.id())
}
// Pass value as is
// Convert type to interface while keeping a reference to the original concrete type.
// besides type, the node value remains preserved.
n.gen = nop
n.typ = c1.typ
t := *c0.typ
n.typ = &t
n.typ.val = c1.typ
n.findex = c1.findex
n.level = c1.level
n.val = c1.val
@@ -1007,7 +1010,9 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
if typ := n.child[0].typ; len(typ.ret) > 0 {
n.typ = typ.ret[0]
if n.anc.kind == returnStmt {
if n.anc.kind == returnStmt && n.typ.id() == sc.def.typ.ret[0].id() {
// Store the result directly to the return value area of frame.
// It can be done only if no type conversion at return is involved.
n.findex = childPos(n)
} else {
n.findex = sc.add(n.typ)
@@ -1255,11 +1260,10 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
}
// Found symbol, populate node info
n.typ, n.findex, n.level = sym.typ, sym.index, level
n.sym, n.typ, n.findex, n.level = sym, sym.typ, sym.index, level
if n.findex < 0 {
n.val = sym.node
} else {
n.sym = sym
switch {
case sym.kind == constSym && sym.rval.IsValid():
n.rval = sym.rval
@@ -1469,72 +1473,8 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
err = n.cfgErrorf("undefined type")
break
}
if n.typ.cat == valueT || n.typ.cat == errorT {
// Handle object defined in runtime, try to find field or method
// Search for method first, as it applies both to types T and *T
// Search for field must then be performed on type T only (not *T)
switch method, ok := n.typ.rtype.MethodByName(n.child[1].ident); {
case ok:
hasRecvType := n.typ.rtype.Kind() != reflect.Interface
n.val = method.Index
n.gen = getIndexBinMethod
n.action = aGetMethod
n.recv = &receiver{node: n.child[0]}
n.typ = &itype{cat: valueT, rtype: method.Type, isBinMethod: true}
if hasRecvType {
n.typ.recv = n.typ
}
case n.typ.rtype.Kind() == reflect.Ptr:
if field, ok := n.typ.rtype.Elem().FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getPtrIndexSeq
} else {
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
}
case n.typ.rtype.Kind() == reflect.Struct:
if field, ok := n.typ.rtype.FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getIndexSeq
} else {
// method lookup failed on type, now lookup on pointer to type
pt := reflect.PtrTo(n.typ.rtype)
if m2, ok2 := pt.MethodByName(n.child[1].ident); ok2 {
n.val = m2.Index
n.gen = getIndexBinPtrMethod
n.typ = &itype{cat: valueT, rtype: m2.Type, recv: &itype{cat: valueT, rtype: pt}}
n.recv = &receiver{node: n.child[0]}
n.action = aGetMethod
} else {
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
}
}
default:
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
}
} else if n.typ.cat == ptrT && (n.typ.val.cat == valueT || n.typ.val.cat == errorT) {
// Handle pointer on object defined in runtime
if method, ok := n.typ.val.rtype.MethodByName(n.child[1].ident); ok {
n.val = method.Index
n.typ = &itype{cat: valueT, rtype: method.Type, recv: n.typ}
n.recv = &receiver{node: n.child[0]}
n.gen = getIndexBinMethod
n.action = aGetMethod
} else if method, ok := reflect.PtrTo(n.typ.val.rtype).MethodByName(n.child[1].ident); ok {
n.val = method.Index
n.gen = getIndexBinMethod
n.typ = &itype{cat: valueT, rtype: method.Type, recv: &itype{cat: valueT, rtype: reflect.PtrTo(n.typ.val.rtype)}}
n.recv = &receiver{node: n.child[0]}
n.action = aGetMethod
} else if field, ok := n.typ.val.rtype.FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getPtrIndexSeq
} else {
err = n.cfgErrorf("undefined selector: %s", n.child[1].ident)
}
} else if n.typ.cat == binPkgT {
switch {
case n.typ.cat == binPkgT:
// Resolve binary package symbol: a type or a value
name := n.child[1].ident
pkg := n.child[0].sym.typ.path
@@ -1542,7 +1482,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
if isBinType(s) {
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
} else {
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
n.typ = &itype{cat: valueT, rtype: fixPossibleConstType(s.Type()), untyped: isValueUntyped(s)}
n.rval = s
}
n.action = aGetSym
@@ -1550,7 +1490,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
} else {
err = n.cfgErrorf("package %s \"%s\" has no symbol %s", n.child[0].ident, pkg, name)
}
} else if n.typ.cat == srcPkgT {
case n.typ.cat == srcPkgT:
pkg, name := n.child[0].sym.typ.path, n.child[1].ident
// Resolve source package symbol
if sym, ok := interp.srcPkg[pkg][name]; ok {
@@ -1563,70 +1503,169 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.action = aGetSym
n.typ = sym.typ
n.sym = sym
n.recv = sym.recv
n.rval = sym.rval
} else {
err = n.cfgErrorf("undefined selector: %s.%s", pkg, name)
}
} else if m, lind := n.typ.lookupMethod(n.child[1].ident); m != nil {
n.action = aGetMethod
if n.child[0].isType(sc) {
// Handle method as a function with receiver in 1st argument
n.val = m
n.findex = notInFrame
n.gen = nop
n.typ = &itype{}
*n.typ = *m.typ
n.typ.arg = append([]*itype{n.child[0].typ}, m.typ.arg...)
} else {
// Handle method with receiver
n.gen = getMethod
n.val = m
n.typ = m.typ
case isStruct(n.typ) || isInterfaceSrc(n.typ):
// Find a matching field.
if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
if isStruct(n.typ) {
// If a method of the same name exists, use it if it is shallower than the struct field.
// if method's depth is the same as field's, this is an error.
d := n.typ.methodDepth(n.child[1].ident)
if d >= 0 && d < len(ti) {
goto tryMethods
}
if d == len(ti) {
err = n.cfgErrorf("ambiguous selector: %s", n.child[1].ident)
break
}
}
n.val = ti
switch {
case isInterfaceSrc(n.typ):
n.typ = n.typ.fieldSeq(ti)
n.gen = getMethodByName
n.action = aMethod
case n.typ.cat == ptrT:
n.typ = n.typ.fieldSeq(ti)
n.gen = getPtrIndexSeq
if n.typ.cat == funcT {
// Function in a struct field is always wrapped in reflect.Value.
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
default:
n.gen = getIndexSeq
n.typ = n.typ.fieldSeq(ti)
if n.typ.cat == funcT {
// Function in a struct field is always wrapped in reflect.Value.
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
}
break
}
if s, lind, ok := n.typ.lookupBinField(n.child[1].ident); ok {
// Handle an embedded binary field into a struct field.
n.gen = getIndexSeqField
lind = append(lind, s.Index...)
if isStruct(n.typ) {
// If a method of the same name exists, use it if it is shallower than the struct field.
// if method's depth is the same as field's, this is an error.
d := n.typ.methodDepth(n.child[1].ident)
if d >= 0 && d < len(lind) {
goto tryMethods
}
if d == len(lind) {
err = n.cfgErrorf("ambiguous selector: %s", n.child[1].ident)
break
}
}
n.val = lind
n.typ = &itype{cat: valueT, rtype: s.Type}
break
}
// No field (embedded or not) matched. Try to match a method.
tryMethods:
fallthrough
default:
// Find a matching method.
// TODO (marc): simplify the following if/elseif blocks.
if n.typ.cat == valueT || n.typ.cat == errorT {
switch method, ok := n.typ.rtype.MethodByName(n.child[1].ident); {
case ok:
hasRecvType := n.typ.rtype.Kind() != reflect.Interface
n.val = method.Index
n.gen = getIndexBinMethod
n.action = aGetMethod
n.recv = &receiver{node: n.child[0]}
n.typ = &itype{cat: valueT, rtype: method.Type, isBinMethod: true}
if hasRecvType {
n.typ.recv = n.typ
}
case n.typ.rtype.Kind() == reflect.Ptr:
if field, ok := n.typ.rtype.Elem().FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getPtrIndexSeq
break
}
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
case n.typ.rtype.Kind() == reflect.Struct:
if field, ok := n.typ.rtype.FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getIndexSeq
break
}
fallthrough
default:
// method lookup failed on type, now lookup on pointer to type
pt := reflect.PtrTo(n.typ.rtype)
if m2, ok2 := pt.MethodByName(n.child[1].ident); ok2 {
n.val = m2.Index
n.gen = getIndexBinPtrMethod
n.typ = &itype{cat: valueT, rtype: m2.Type, recv: &itype{cat: valueT, rtype: pt}, isBinMethod: true}
n.recv = &receiver{node: n.child[0]}
n.action = aGetMethod
break
}
err = n.cfgErrorf("undefined field or method: %s", n.child[1].ident)
}
} else if n.typ.cat == ptrT && (n.typ.val.cat == valueT || n.typ.val.cat == errorT) {
// Handle pointer on object defined in runtime
if method, ok := n.typ.val.rtype.MethodByName(n.child[1].ident); ok {
n.val = method.Index
n.typ = &itype{cat: valueT, rtype: method.Type, recv: n.typ, isBinMethod: true}
n.recv = &receiver{node: n.child[0]}
n.gen = getIndexBinElemMethod
n.action = aGetMethod
} else if method, ok := reflect.PtrTo(n.typ.val.rtype).MethodByName(n.child[1].ident); ok {
n.val = method.Index
n.gen = getIndexBinMethod
n.typ = &itype{cat: valueT, rtype: method.Type, recv: &itype{cat: valueT, rtype: reflect.PtrTo(n.typ.val.rtype)}, isBinMethod: true}
n.recv = &receiver{node: n.child[0]}
n.action = aGetMethod
} else if field, ok := n.typ.val.rtype.FieldByName(n.child[1].ident); ok {
n.typ = &itype{cat: valueT, rtype: field.Type}
n.val = field.Index
n.gen = getPtrIndexSeq
} else {
err = n.cfgErrorf("undefined selector: %s", n.child[1].ident)
}
} else if m, lind := n.typ.lookupMethod(n.child[1].ident); m != nil {
n.action = aGetMethod
if n.child[0].isType(sc) {
// Handle method as a function with receiver in 1st argument
n.val = m
n.findex = notInFrame
n.gen = nop
n.typ = &itype{}
*n.typ = *m.typ
n.typ.arg = append([]*itype{n.child[0].typ}, m.typ.arg...)
} else {
// Handle method with receiver
n.gen = getMethod
n.val = m
n.typ = m.typ
n.recv = &receiver{node: n.child[0], index: lind}
}
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
n.action = aGetMethod
if isPtr && n.typ.fieldSeq(lind).cat != ptrT {
n.gen = getIndexSeqPtrMethod
} else {
n.gen = getIndexSeqMethod
}
n.recv = &receiver{node: n.child[0], index: lind}
}
} else if m, lind, isPtr, ok := n.typ.lookupBinMethod(n.child[1].ident); ok {
n.action = aGetMethod
if isPtr && n.typ.fieldSeq(lind).cat != ptrT {
n.gen = getIndexSeqPtrMethod
n.val = append([]int{m.Index}, lind...)
n.typ = &itype{cat: valueT, rtype: m.Type, recv: n.child[0].typ, isBinMethod: true}
} else {
n.gen = getIndexSeqMethod
err = n.cfgErrorf("undefined selector: %s", n.child[1].ident)
}
n.recv = &receiver{node: n.child[0], index: lind}
n.val = append([]int{m.Index}, lind...)
n.typ = &itype{cat: valueT, rtype: m.Type, recv: n.child[0].typ}
} else if ti := n.typ.lookupField(n.child[1].ident); len(ti) > 0 {
// Handle struct field
n.val = ti
switch {
case isInterfaceSrc(n.typ):
n.typ = n.typ.fieldSeq(ti)
n.gen = getMethodByName
n.action = aMethod
case n.typ.cat == ptrT:
n.typ = n.typ.fieldSeq(ti)
n.gen = getPtrIndexSeq
if n.typ.cat == funcT {
// function in a struct field is always wrapped in reflect.Value
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
default:
n.gen = getIndexSeq
n.typ = n.typ.fieldSeq(ti)
if n.typ.cat == funcT {
// function in a struct field is always wrapped in reflect.Value
rtype := n.typ.TypeOf()
n.typ = &itype{cat: valueT, rtype: rtype, val: n.typ}
}
}
} else if s, lind, ok := n.typ.lookupBinField(n.child[1].ident); ok {
// Handle an embedded binary field into a struct field
n.gen = getIndexSeqField
lind = append(lind, s.Index...)
n.val = lind
n.typ = &itype{cat: valueT, rtype: s.Type}
} else {
err = n.cfgErrorf("undefined selector: %s", n.child[1].ident)
}
if err == nil && n.findex != -1 {
n.findex = sc.add(n.typ)
@@ -1735,15 +1774,17 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
break
}
// Chain case clauses.
for i, c := range clauses[:l-1] {
// Chain to next clause.
setFNext(c, clauses[i+1])
for i := l - 1; i >= 0; i-- {
c := clauses[i]
if len(c.child) == 0 {
c.tnext = n // Clause body is empty, exit.
} else {
body := c.lastChild()
c.tnext = body.start
if len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
c.child[0].tnext = c
c.start = c.child[0].start
if i < l-1 && len(body.child) > 0 && body.lastChild().kind == fallthroughtStmt {
if n.kind == typeSwitch {
err = body.lastChild().cfgErrorf("cannot fallthrough in type switch")
}
@@ -1756,15 +1797,16 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = n // Exit switch at end of clause body.
}
}
}
c := clauses[l-1] // Last clause.
c.fnext = n
if len(c.child) == 0 {
c.tnext = n // Clause body is empty, exit.
} else {
body := c.lastChild()
c.tnext = body.start
body.tnext = n
if i == l-1 {
setFNext(clauses[i], n)
continue
}
if len(clauses[i+1].child) > 1 {
setFNext(c, clauses[i+1].start)
} else {
setFNext(c, clauses[i+1])
}
}
n.start = n.child[0].start
n.child[0].tnext = sbn.start
@@ -1886,7 +1928,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
case n.rval.IsValid():
n.gen = nop
n.findex = notInFrame
case n.anc.kind == assignStmt && n.anc.action == aAssign:
case n.anc.kind == assignStmt && n.anc.action == aAssign && n.anc.nright == 1:
dest := n.anc.child[childPos(n)-n.anc.nright]
n.typ = dest.typ
n.findex = dest.findex
@@ -2181,7 +2223,10 @@ func (n *node) isType(sc *scope) bool {
suffixedPkg := filepath.Join(pkg, baseName)
sym, _, ok := sc.lookup(suffixedPkg)
if !ok {
return false
sym, _, ok = sc.lookup(pkg)
if !ok {
return false
}
}
if sym.kind != pkgSym {
return false
@@ -2519,7 +2564,9 @@ func gotoLabel(s *symbol) {
return
}
for _, c := range s.from {
c.tnext = s.node.start
if c.tnext == nil {
c.tnext = s.node.start
}
}
}
@@ -2568,7 +2615,7 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
gen = compositeBinMap
case reflect.Ptr:
gen = compositeGenerator(n, typ, n.typ.val.rtype)
case reflect.Slice:
case reflect.Slice, reflect.Array:
gen = compositeBinSlice
default:
log.Panic(n.cfgErrorf("compositeGenerator not implemented for type kind: %s", k))

View File

@@ -187,11 +187,11 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
}
// Try to import a binary package first, or a source package
var pkgName string
if interp.binPkg[ipath] != nil {
if pkg := interp.binPkg[ipath]; pkg != nil {
switch name {
case "_": // no import of symbols
case ".": // import symbols in current scope
for n, v := range interp.binPkg[ipath] {
for n, v := range pkg {
typ := v.Type()
if isBinType(v) {
typ = typ.Elem()
@@ -200,9 +200,9 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
}
default: // import symbols in package namespace
if name == "" {
name = identifier.FindString(ipath)
name = interp.pkgNames[ipath]
}
// imports of a same package are all mapped in the same scope, so we cannot just
// Imports of a same package are all mapped in the same scope, so we cannot just
// map them by their names, otherwise we could have collisions from same-name
// imports in different source files of the same package. Therefore, we suffix
// the key with the basename of the source file.

View File

@@ -14,6 +14,8 @@ import (
"log"
"os"
"os/signal"
"path"
"path/filepath"
"reflect"
"runtime"
"runtime/debug"
@@ -113,6 +115,8 @@ func (f *frame) clone(fork bool) *frame {
}
// Exports stores the map of binary packages per package path.
// The package path is the path joined from the import path and the package name
// as specified in source files by the "package" statement.
type Exports map[string]map[string]reflect.Value
// imports stores the map of source packages per package path.
@@ -124,13 +128,14 @@ type opt struct {
cfgDot bool // display CFG graph (debug)
// dotCmd is the command to process the dot graph produced when astDot and/or
// cfgDot is enabled. It defaults to 'dot -Tdot -o <filename>.dot'.
dotCmd string
noRun bool // compile, but do not run
fastChan bool // disable cancellable chan operations
context build.Context // build context: GOPATH, build constraints
stdin io.Reader // standard input
stdout io.Writer // standard output
stderr io.Writer // standard error
dotCmd string
noRun bool // compile, but do not run
fastChan bool // disable cancellable chan operations
context build.Context // build context: GOPATH, build constraints
specialStdio bool // Allows os.Stdin, os.Stdout, os.Stderr to not be file descriptors
stdin io.Reader // standard input
stdout io.Writer // standard output
stderr io.Writer // standard error
}
// Interpreter contains global resources and state.
@@ -168,7 +173,7 @@ type Interpreter struct {
const (
mainID = "main"
selfPrefix = "github.com/traefik/yaegi"
selfPath = selfPrefix + "/interp"
selfPath = selfPrefix + "/interp/interp"
// DefaultSourceName is the name used by default when the name of the input
// source file has not been specified for an Eval.
// TODO(mpl): something even more special as a name?
@@ -180,6 +185,9 @@ const (
NoTest = true
)
// Self points to the current interpreter if accessed from within itself, or is nil.
var Self *Interpreter
// Symbols exposes interpreter values.
var Symbols = Exports{
selfPath: map[string]reflect.Value{
@@ -195,6 +203,7 @@ func init() { Symbols[selfPath]["Symbols"] = reflect.ValueOf(Symbols) }
// _error is a wrapper of error interface type.
type _error struct {
IValue interface{}
WError func() string
}
@@ -241,7 +250,7 @@ type Options struct {
BuildTags []string
// Standard input, output and error streams.
// They default to os.Stding, os.Stdout and os.Stderr respectively.
// They default to os.Stdin, os.Stdout and os.Stderr respectively.
Stdin io.Reader
Stdout, Stderr io.Writer
}
@@ -294,6 +303,10 @@ func New(options Options) *Interpreter {
// fastChan disables the cancellable version of channel operations in evalWithContext
i.opt.fastChan, _ = strconv.ParseBool(os.Getenv("YAEGI_FAST_CHAN"))
// specialStdio allows to assign directly io.Writer and io.Reader to os.Stdxxx, even if they are not file descriptors.
i.opt.specialStdio, _ = strconv.ParseBool(os.Getenv("YAEGI_SPECIAL_STDIO"))
return &i
}
@@ -641,33 +654,45 @@ func (interp *Interpreter) getWrapper(t reflect.Type) reflect.Type {
// Use loads binary runtime symbols in the interpreter context so
// they can be used in interpreted code.
func (interp *Interpreter) Use(values Exports) {
func (interp *Interpreter) Use(values Exports) error {
for k, v := range values {
if k == selfPrefix {
importPath := path.Dir(k)
packageName := path.Base(k)
if importPath == "." {
return fmt.Errorf("export path %[1]q is missing a package name; did you mean '%[1]s/%[1]s'?", k)
}
if importPath == selfPrefix {
interp.hooks.Parse(v)
continue
}
if interp.binPkg[k] == nil {
interp.binPkg[k] = make(map[string]reflect.Value)
if interp.binPkg[importPath] == nil {
interp.binPkg[importPath] = make(map[string]reflect.Value)
interp.pkgNames[importPath] = packageName
}
for s, sym := range v {
interp.binPkg[k][s] = sym
interp.binPkg[importPath][s] = sym
}
if k == selfPath {
interp.binPkg[importPath]["Self"] = reflect.ValueOf(interp)
}
}
// Checks if input values correspond to stdlib packages by looking for one
// well known stdlib package path.
if _, ok := values["fmt"]; ok {
if _, ok := values["fmt/fmt"]; ok {
fixStdio(interp)
}
return nil
}
// fixStdio redefines interpreter stdlib symbols to use the standard input,
// output and errror assigned to the interpreter. The changes are limited to
// the interpreter only. Global values os.Stdin, os.Stdout and os.Stderr are
// not changed. Note that it is possible to escape the virtualized stdio by
// the interpreter only.
// Note that it is possible to escape the virtualized stdio by
// read/write directly to file descriptors 0, 1, 2.
func fixStdio(interp *Interpreter) {
p := interp.binPkg["fmt"]
@@ -714,9 +739,23 @@ func fixStdio(interp *Interpreter) {
}
if p = interp.binPkg["os"]; p != nil {
p["Stdin"] = reflect.ValueOf(&stdin).Elem()
p["Stdout"] = reflect.ValueOf(&stdout).Elem()
p["Stderr"] = reflect.ValueOf(&stderr).Elem()
if interp.specialStdio {
// Inherit streams from interpreter even if they do not have a file descriptor.
p["Stdin"] = reflect.ValueOf(&stdin).Elem()
p["Stdout"] = reflect.ValueOf(&stdout).Elem()
p["Stderr"] = reflect.ValueOf(&stderr).Elem()
} else {
// Inherits streams from interpreter only if they have a file descriptor and preserve original type.
if s, ok := stdin.(*os.File); ok {
p["Stdin"] = reflect.ValueOf(&s).Elem()
}
if s, ok := stdout.(*os.File); ok {
p["Stdout"] = reflect.ValueOf(&s).Elem()
}
if s, ok := stderr.(*os.File); ok {
p["Stderr"] = reflect.ValueOf(&s).Elem()
}
}
}
}
@@ -736,24 +775,47 @@ func ignoreScannerError(e *scanner.Error, s string) bool {
return false
}
// ImportUsed automatically imports pre-compiled packages included by Use().
// This is mainly useful for REPLs, or single command lines. In case of an ambiguous default
// package name, for example "rand" for crypto/rand and math/rand, the package name is
// constructed by replacing the last "/" by a "_", producing crypto_rand and math_rand.
// ImportUsed should not be called more than once, and not after a first Eval, as it may
// rename packages.
func (interp *Interpreter) ImportUsed() {
sc := interp.universe
for k := range interp.binPkg {
// By construction, the package name is the last path element of the key.
name := path.Base(k)
if sym, ok := sc.sym[name]; ok {
// Handle collision by renaming old and new entries.
name2 := key2name(fixKey(sym.typ.path))
sc.sym[name2] = sym
if name2 != name {
delete(sc.sym, name)
}
name = key2name(fixKey(k))
}
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}}
}
}
func key2name(name string) string {
return filepath.Join(name, DefaultSourceName)
}
func fixKey(k string) string {
i := strings.LastIndex(k, "/")
if i >= 0 {
k = k[:i] + "_" + k[i+1:]
}
return k
}
// REPL performs a Read-Eval-Print-Loop on input reader.
// Results are printed to the output writer of the Interpreter, provided as option
// at creation time. Errors are printed to the similarly defined errors writer.
// The last interpreter result value and error are returned.
func (interp *Interpreter) REPL() (reflect.Value, error) {
// Preimport used bin packages, to avoid having to import these packages manually
// in REPL mode. These packages are already loaded anyway.
sc := interp.universe
for k := range interp.binPkg {
name := identifier.FindString(k)
if name == "" || name == "rand" || name == "scanner" || name == "template" || name == "pprof" {
// Skip any package with an ambiguous name (i.e crypto/rand vs math/rand).
// Those will have to be imported explicitly.
continue
}
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: k, scope: sc}}
}
in, out, errs := interp.stdin, interp.stdout, interp.stderr
ctx, cancel := context.WithCancel(context.Background())
end := make(chan struct{}) // channel to terminate the REPL

View File

@@ -50,6 +50,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
file.Name() == "import6.go" || // expect error
file.Name() == "init1.go" || // expect error
file.Name() == "io0.go" || // use random number
file.Name() == "issue-1093.go" || // expect error
file.Name() == "op1.go" || // expect error
file.Name() == "op7.go" || // expect error
file.Name() == "op9.go" || // expect error
@@ -114,9 +115,15 @@ func TestInterpConsistencyBuild(t *testing.T) {
os.Stdout = w
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
i.Use(stdlib.Symbols)
i.Use(interp.Symbols)
i.Use(unsafe.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
if err := i.Use(interp.Symbols); err != nil {
t.Fatal(err)
}
if err := i.Use(unsafe.Symbols); err != nil {
t.Fatal(err)
}
_, err = i.EvalPath(filePath)
if err != nil {
@@ -209,6 +216,11 @@ func TestInterpErrorConsistency(t *testing.T) {
expectedInterp: "3:17: too many arguments to return",
expectedExec: "3:17: too many arguments to return",
},
{
fileName: "issue-1093.go",
expectedInterp: "9:6: cannot use type string as type int in assignment",
expectedExec: `9:4: cannot use "a" + b() (type string) as type int in assignment`,
},
{
fileName: "op1.go",
expectedInterp: "5:2: invalid operation: mismatched types int and float64",
@@ -254,7 +266,9 @@ func TestInterpErrorConsistency(t *testing.T) {
filePath := filepath.Join("..", "_test", test.fileName)
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
_, errEval := i.EvalPath(filePath)
if errEval == nil {

View File

@@ -103,11 +103,14 @@ func TestEvalStar(t *testing.T) {
func TestEvalAssign(t *testing.T) {
i := interp.New(interp.Options{})
i.Use(interp.Exports{
"testpkg": {
if err := i.Use(interp.Exports{
"testpkg/testpkg": {
"val": reflect.ValueOf(int64(11)),
},
})
}); err != nil {
t.Fatal(err)
}
_, e := i.Eval(`import "testpkg"`)
if e != nil {
t.Fatal(e)
@@ -205,7 +208,9 @@ func TestEvalFunc(t *testing.T) {
func TestEvalImport(t *testing.T) {
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
runTests(t, i, []testCase{
{pre: func() { eval(t, i, `import "time"`) }, src: "2 * time.Second", res: "2s"},
})
@@ -214,7 +219,9 @@ func TestEvalImport(t *testing.T) {
func TestEvalStdout(t *testing.T) {
var out, err bytes.Buffer
i := interp.New(interp.Options{Stdout: &out, Stderr: &err})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
_, e := i.Eval(`import "fmt"; func main() { fmt.Println("hello") }`)
if e != nil {
t.Fatal(e)
@@ -227,7 +234,9 @@ func TestEvalStdout(t *testing.T) {
func TestEvalNil(t *testing.T) {
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
runTests(t, i, []testCase{
{desc: "assign nil", src: "a := nil", err: "1:33: use of untyped nil"},
{desc: "return nil", pre: func() { eval(t, i, "func getNil() error {return nil}") }, src: "getNil()", res: "<nil>"},
@@ -375,7 +384,9 @@ var a = T{
func TestEvalCompositeBin0(t *testing.T) {
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
eval(t, i, `
import (
"fmt"
@@ -636,7 +647,9 @@ func TestEvalCall(t *testing.T) {
func TestEvalBinCall(t *testing.T) {
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
if _, err := i.Eval(`import "fmt"`); err != nil {
t.Fatal(err)
}
@@ -662,9 +675,11 @@ func TestEvalMissingSymbol(t *testing.T) {
F S2
}
i := interp.New(interp.Options{})
i.Use(interp.Exports{"p": map[string]reflect.Value{
if err := i.Use(interp.Exports{"p/p": map[string]reflect.Value{
"S1": reflect.Zero(reflect.TypeOf(&S1{})),
}})
}}); err != nil {
t.Fatal(err)
}
_, err := i.Eval(`import "p"`)
if err != nil {
t.Fatalf("failed to import package: %v", err)
@@ -733,7 +748,9 @@ func TestEvalWithContext(t *testing.T) {
go func() {
defer close(done)
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Error(err)
}
_, err := i.Eval(`import "sync"`)
if err != nil {
t.Errorf(`failed to import "sync": %v`, err)
@@ -836,8 +853,9 @@ func TestMultiEval(t *testing.T) {
os.Stdout = w
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
var err error
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
f, err := os.Open(filepath.Join("testdata", "multi", "731"))
if err != nil {
@@ -875,8 +893,9 @@ func TestMultiEval(t *testing.T) {
func TestMultiEvalNoName(t *testing.T) {
t.Skip("fail in CI only ?")
i := interp.New(interp.Options{})
i.Use(stdlib.Symbols)
var err error
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
f, err := os.Open(filepath.Join("testdata", "multi", "731"))
if err != nil {
@@ -908,7 +927,9 @@ func TestMultiEvalNoName(t *testing.T) {
func TestImportPathIsKey(t *testing.T) {
// No need to check the results of Eval, as TestFile already does it.
i := interp.New(interp.Options{GoPath: filepath.FromSlash("../_test/testdata/redeclaration-global7")})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
filePath := filepath.Join("..", "_test", "ipp_as_key.go")
if _, err := i.EvalPath(filePath); err != nil {
@@ -961,9 +982,6 @@ func TestImportPathIsKey(t *testing.T) {
}
packages := i.Packages()
if len(packages) != len(wantPackages) {
t.Fatalf("want %d, got %d", len(wantPackages), len(packages))
}
for k, v := range wantPackages {
pkg := packages[k]
if pkg != v {
@@ -990,7 +1008,9 @@ func TestConcurrentEvals(t *testing.T) {
_ = pout.Close()
}()
interpr := interp.New(interp.Options{Stdout: pout})
interpr.Use(stdlib.Symbols)
if err := interpr.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
if _, err := interpr.EvalPath("testdata/concurrent/hello1.go"); err != nil {
t.Fatal(err)
@@ -1049,7 +1069,9 @@ func TestConcurrentEvals2(t *testing.T) {
_ = pout.Close()
}()
interpr := interp.New(interp.Options{Stdout: pout})
interpr.Use(stdlib.Symbols)
if err := interpr.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
done := make(chan error)
go func() {
@@ -1111,7 +1133,9 @@ func TestConcurrentEvals3(t *testing.T) {
pinin, poutin := io.Pipe()
pinout, poutout := io.Pipe()
i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
go func() {
_, _ = i.REPL()
@@ -1190,7 +1214,9 @@ func testConcurrentComposite(t *testing.T, filePath string) {
}
pin, pout := io.Pipe()
i := interp.New(interp.Options{Stdout: pout})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
errc := make(chan error)
var output string
@@ -1400,11 +1426,11 @@ func applyCIMultiplier(timeout time.Duration) time.Duration {
return time.Duration(float64(timeout) * CITimeoutMultiplier)
}
func TestREPLDivision(t *testing.T) {
func TestREPLCommands(t *testing.T) {
if testing.Short() {
return
}
_ = os.Setenv("YAEGI_PROMPT", "1")
_ = os.Setenv("YAEGI_PROMPT", "1") // To force prompts over non-tty streams
defer func() {
_ = os.Setenv("YAEGI_PROMPT", "0")
}()
@@ -1414,7 +1440,9 @@ func TestREPLDivision(t *testing.T) {
pinin, poutin := io.Pipe()
pinout, poutout := io.Pipe()
i := interp.New(interp.Options{Stdin: pinin, Stdout: poutout})
i.Use(stdlib.Symbols)
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
go func() {
_, _ = i.REPL()
@@ -1433,12 +1461,16 @@ func TestREPLDivision(t *testing.T) {
`7/3`,
`16/5`,
`3./2`, // float
`reflect.TypeOf(math_rand.Int)`,
`reflect.TypeOf(crypto_rand.Int)`,
}
output := []string{
`1`,
`2`,
`3`,
`1.5`,
`func() int`,
`func(io.Reader, *big.Int) (*big.Int, error)`,
}
go func() {
@@ -1490,3 +1522,108 @@ func TestREPLDivision(t *testing.T) {
t.Fatal("timeout")
}
}
func TestStdio(t *testing.T) {
i := interp.New(interp.Options{})
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
i.ImportUsed()
if _, err := i.Eval(`var x = os.Stdout`); err != nil {
t.Fatal(err)
}
v, _ := i.Eval(`x`)
if _, ok := v.Interface().(*os.File); !ok {
t.Fatalf("%v not *os.file", v.Interface())
}
}
func TestIssue1142(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{
{src: "a := 1; // foo bar", res: "1"},
})
}
type Issue1149Array [3]float32
func (v Issue1149Array) Foo() string { return "foo" }
func (v *Issue1149Array) Bar() string { return "foo" }
func TestIssue1149(t *testing.T) {
i := interp.New(interp.Options{})
if err := i.Use(interp.Exports{
"pkg/pkg": map[string]reflect.Value{
"Type": reflect.ValueOf((*Issue1149Array)(nil)),
},
}); err != nil {
t.Fatal(err)
}
i.ImportUsed()
_, err := i.Eval(`
type Type = pkg.Type
`)
if err != nil {
t.Fatal(err)
}
runTests(t, i, []testCase{
{src: "Type{1, 2, 3}.Foo()", res: "foo"},
{src: "Type{1, 2, 3}.Bar()", res: "foo"},
})
}
func TestIssue1150(t *testing.T) {
i := interp.New(interp.Options{})
_, err := i.Eval(`
type ArrayT [3]float32
type SliceT []float32
type StructT struct { A, B, C float32 }
type StructT2 struct { A, B, C float32 }
type FooerT interface { Foo() string }
func (v ArrayT) Foo() string { return "foo" }
func (v SliceT) Foo() string { return "foo" }
func (v StructT) Foo() string { return "foo" }
func (v *StructT2) Foo() string { return "foo" }
type Array = ArrayT
type Slice = SliceT
type Struct = StructT
type Struct2 = StructT2
type Fooer = FooerT
`)
if err != nil {
t.Fatal(err)
}
runTests(t, i, []testCase{
{desc: "array", src: "Array{1, 2, 3}.Foo()", res: "foo"},
{desc: "slice", src: "Slice{1, 2, 3}.Foo()", res: "foo"},
{desc: "struct", src: "Struct{1, 2, 3}.Foo()", res: "foo"},
{desc: "*struct", src: "Struct2{1, 2, 3}.Foo()", res: "foo"},
{desc: "interface", src: "v := Fooer(Array{1, 2, 3}); v.Foo()", res: "foo"},
})
}
func TestIssue1151(t *testing.T) {
type pkgStruct struct{ X int }
type pkgArray [1]int
i := interp.New(interp.Options{})
if err := i.Use(interp.Exports{
"pkg/pkg": map[string]reflect.Value{
"Struct": reflect.ValueOf((*pkgStruct)(nil)),
"Array": reflect.ValueOf((*pkgArray)(nil)),
},
}); err != nil {
t.Fatal(err)
}
i.ImportUsed()
runTests(t, i, []testCase{
{src: "x := pkg.Struct{1}", res: "{1}"},
{src: "x := pkg.Array{1}", res: "[1]"},
})
}

View File

@@ -41,14 +41,53 @@ type Wrap struct {
func (w Wrap) Hello() { w.DoHello() }
func TestExportsSemantics(t *testing.T) {
Foo := &struct{}{}
t.Run("Correct", func(t *testing.T) {
t.Skip()
i := interp.New(interp.Options{})
err := i.Use(interp.Exports{
"foo/foo": {"Foo": reflect.ValueOf(Foo)},
})
if err != nil {
t.Fatal(err)
}
i.ImportUsed()
res, err := i.Eval("foo.Foo")
if err != nil {
t.Fatal(err)
}
if res.Interface() != Foo {
t.Fatalf("expected foo.Foo to equal local Foo")
}
})
t.Run("Incorrect", func(t *testing.T) {
i := interp.New(interp.Options{})
err := i.Use(interp.Exports{
"foo": {"Foo": reflect.ValueOf(Foo)},
})
if err == nil {
t.Fatal("expected error for incorrect Use semantics")
}
})
}
func TestInterface(t *testing.T) {
i := interp.New(interp.Options{})
// export the Wrap type to the interpreter under virtual "wrap" package
i.Use(interp.Exports{
"wrap": {
err := i.Use(interp.Exports{
"wrap/wrap": {
"Wrap": reflect.ValueOf((*Wrap)(nil)),
},
})
if err != nil {
t.Fatal(err)
}
eval(t, i, `
import "wrap"
@@ -66,3 +105,29 @@ func NewMyInt(i int) wrap.Wrap {
w := NewMyInt(4)
Hi(w)
}
type T struct{}
func (t T) Bar(s ...string) {}
func TestCallBinVariadicMethod(t *testing.T) {
i := interp.New(interp.Options{})
err := i.Use(interp.Exports{
"mypkg/mypkg": {
"T": reflect.ValueOf((*T)(nil)),
},
})
if err != nil {
t.Fatal(err)
}
eval(t, i, `
package p
import "mypkg"
func Foo(x mypkg.T) { x.Bar("s") }
`)
v := eval(t, i, "p.Foo")
bar := v.Interface().(func(t T))
bar(T{})
}

View File

@@ -20,6 +20,11 @@ func TestFile(t *testing.T) {
filePath := "../_test/str.go"
runCheck(t, filePath)
defer func() {
_ = os.Setenv("YAEGI_SPECIAL_STDIO", "0")
}()
_ = os.Setenv("YAEGI_SPECIAL_STDIO", "1")
baseDir := filepath.Join("..", "_test")
files, err := ioutil.ReadDir(baseDir)
if err != nil {
@@ -50,9 +55,15 @@ func runCheck(t *testing.T, p string) {
}
var stdout, stderr bytes.Buffer
i := interp.New(interp.Options{GoPath: goPath, Stdout: &stdout, Stderr: &stderr})
i.Use(interp.Symbols)
i.Use(stdlib.Symbols)
i.Use(unsafe.Symbols)
if err := i.Use(interp.Symbols); err != nil {
t.Fatal(err)
}
if err := i.Use(stdlib.Symbols); err != nil {
t.Fatal(err)
}
if err := i.Use(unsafe.Symbols); err != nil {
t.Fatal(err)
}
_, err := i.EvalPath(p)
if errWanted {

View File

@@ -421,6 +421,10 @@ func typeAssert(n *node, withResult, withOk bool) {
return next
}
v = valueInterfaceValue(v)
if vt := v.Type(); vt.Kind() == reflect.Struct && vt.Field(0).Name == "IValue" {
// Value is retrieved from an interface wrapper.
v = v.Field(0).Elem()
}
ok = canAssertTypes(v.Type(), rtype)
if !ok {
if !withOk {
@@ -570,7 +574,7 @@ func isRecursiveType(t *itype, rtype reflect.Type) bool {
return true
}
switch t.cat {
case arrayT, mapT, ptrT, sliceT:
case aliasT, arrayT, mapT, ptrT, sliceT:
return isRecursiveType(t.val, t.val.rtype)
default:
return false
@@ -589,34 +593,10 @@ func assign(n *node) {
for i := 0; i < n.nleft; i++ {
dest, src := n.child[i], n.child[sbase+i]
switch {
case isInterfaceSrc(dest.typ):
if len(dest.typ.field) > 0 {
svalue[i] = genValueInterface(src)
break
}
svalue[i] = genValue(src)
case (dest.typ.cat == valueT || dest.typ.cat == errorT) && dest.typ.rtype.Kind() == reflect.Interface:
svalue[i] = genInterfaceWrapper(src, dest.typ.rtype)
case isFuncSrc(src.typ) && dest.typ.cat == valueT:
if isFuncSrc(src.typ) && isField(dest) {
svalue[i] = genFunctionWrapper(src)
case isFuncSrc(src.typ) && isField(dest):
svalue[i] = genFunctionWrapper(src)
case isFuncSrc(dest.typ) && src.typ.cat == valueT:
svalue[i] = genValueNode(src)
case src.kind == basicLit && src.val == nil:
t := dest.typ.TypeOf()
svalue[i] = func(*frame) reflect.Value { return reflect.New(t).Elem() }
case isRecursiveType(dest.typ, dest.typ.rtype):
svalue[i] = genValueRecursiveInterface(src, dest.typ.rtype)
case isRecursiveType(src.typ, src.typ.rtype):
svalue[i] = genValueRecursiveInterfacePtrValue(src)
case src.typ.untyped && isComplex(dest.typ.TypeOf()):
svalue[i] = genValueComplex(src)
case src.typ.untyped && !dest.typ.untyped:
svalue[i] = genValueAs(src, dest.typ.TypeOf())
default:
svalue[i] = genValue(src)
} else {
svalue[i] = genDestValue(dest.typ, src)
}
if isMapEntry(dest) {
if isInterfaceSrc(dest.child[1].typ) { // key
@@ -991,7 +971,8 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
if typ == nil || typ.Kind() != reflect.Interface || typ.NumMethod() == 0 || n.typ.cat == valueT {
return value
}
if nt := n.typ.TypeOf(); nt != nil && nt.Kind() == reflect.Interface {
nt := n.typ.frameType()
if nt != nil && nt.Implements(typ) {
return value
}
mn := typ.NumMethod()
@@ -1010,6 +991,9 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
return func(f *frame) reflect.Value {
v := value(f)
if v.Type().Implements(typ) {
return v
}
vv := v
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
@@ -1021,15 +1005,16 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
}
}
w := reflect.New(wrap).Elem()
w.Field(0).Set(v)
for i, m := range methods {
if m == nil {
if r := v.MethodByName(names[i]); r.IsValid() {
w.Field(i).Set(r)
w.Field(i + 1).Set(r)
continue
}
o := vv.FieldByIndex(indexes[i])
if r := o.MethodByName(names[i]); r.IsValid() {
w.Field(i).Set(r)
w.Field(i + 1).Set(r)
} else {
log.Println(n.cfgErrorf("genInterfaceWrapper error, no method %s", names[i]))
}
@@ -1037,7 +1022,7 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
}
nod := *m
nod.recv = &receiver{n, v, indexes[i]}
w.Field(i).Set(genFunctionWrapper(&nod)(f))
w.Field(i + 1).Set(genFunctionWrapper(&nod)(f))
}
return w
}
@@ -1108,6 +1093,8 @@ func call(n *node) {
values = append(values, genValue(c))
case isInterfaceSrc(arg):
values = append(values, genValueInterface(c))
case isInterfaceBin(arg):
values = append(values, genInterfaceWrapper(c, arg.rtype))
case isRecursiveType(c.typ, c.typ.rtype):
values = append(values, genValueRecursiveInterfacePtrValue(c))
default:
@@ -1136,20 +1123,8 @@ func call(n *node) {
// Function call from a return statement: forward return values (always at frame start).
for i := range rtypes {
j := n.findex + i
ret := n.child[0].typ.ret[i]
callret := n.anc.val.(*node).typ.ret[i]
if isInterfaceSrc(callret) && !isEmptyInterface(callret) && !isInterfaceSrc(ret) {
// Wrap the returned value in a valueInterface in caller frame.
rvalues[i] = func(f *frame) reflect.Value {
v := reflect.New(ret.rtype).Elem()
f.data[j].Set(reflect.ValueOf(valueInterface{n, v}))
return v
}
} else {
// Set the return value location in return value of caller frame.
rvalues[i] = func(f *frame) reflect.Value { return f.data[j] }
}
// Set the return value location in return value of caller frame.
rvalues[i] = func(f *frame) reflect.Value { return f.data[j] }
}
default:
// Multiple return values frame index are indexed from the node frame index.
@@ -1254,6 +1229,14 @@ func call(n *node) {
src = def.recv.val
} else {
src = v(f)
for src.IsValid() {
// traverse interface indirections to find out concrete type
vi, ok := src.Interface().(valueInterface)
if !ok {
break
}
src = vi.value
}
}
if recvIndexLater && def.recv != nil && len(def.recv.index) > 0 {
if src.Kind() == reflect.Ptr {
@@ -1350,7 +1333,7 @@ func callBin(n *node) {
for i, c := range child {
var defType reflect.Type
if variadic >= 0 && i >= variadic {
if variadic >= 0 && i+rcvrOffset >= variadic {
defType = funcType.In(variadic)
} else {
defType = funcType.In(rcvrOffset + i)
@@ -1374,7 +1357,7 @@ func callBin(n *node) {
if c.kind == basicLit || c.rval.IsValid() {
// Convert literal value (untyped) to function argument type (if not an interface{})
var argType reflect.Type
if variadic >= 0 && i >= variadic {
if variadic >= 0 && i+rcvrOffset >= variadic {
argType = funcType.In(variadic).Elem()
} else {
argType = funcType.In(i + rcvrOffset)
@@ -1538,6 +1521,20 @@ func getIndexBinMethod(n *node) {
}
}
func getIndexBinElemMethod(n *node) {
i := n.findex
l := n.level
m := n.val.(int)
value := genValue(n.child[0])
next := getExec(n.tnext)
n.exec = func(f *frame) bltn {
// Can not use .Set() because dest type contains the receiver and source not
getFrame(f, l).data[i] = value(f).Elem().Method(m)
return next
}
}
func getIndexBinPtrMethod(n *node) {
i := n.findex
l := n.level
@@ -1989,14 +1986,28 @@ func getIndexSeqPtrMethod(n *node) {
next := getExec(n.tnext)
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
return next
if len(fi) == 0 {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Method(mi)
return next
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Addr().Method(mi)
return next
}
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
return next
if len(fi) == 0 {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Addr().Method(mi)
return next
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Addr().Method(mi)
return next
}
}
}
}
@@ -2011,14 +2022,28 @@ func getIndexSeqMethod(n *node) {
next := getExec(n.tnext)
if n.child[0].typ.TypeOf().Kind() == reflect.Ptr {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Method(mi)
return next
if len(fi) == 0 {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Elem().Method(mi)
return next
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Elem().FieldByIndex(fi).Method(mi)
return next
}
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Method(mi)
return next
if len(fi) == 0 {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).Method(mi)
return next
}
} else {
n.exec = func(f *frame) bltn {
getFrame(f, l).data[i] = value(f).FieldByIndex(fi).Method(mi)
return next
}
}
}
}
@@ -2259,12 +2284,16 @@ func _return(n *node) {
case 0:
n.exec = nil
case 1:
// This is an optimisation that is applied for binary expressions or function
// calls, but not for (binary) expressions involving const, as the values are not
// stored in the frame in that case.
if !child[0].rval.IsValid() && child[0].kind == binaryExpr || isCall(child[0]) {
switch {
case !child[0].rval.IsValid() && child[0].kind == binaryExpr:
// No additional runtime operation is necessary for constants (not in frame) or
// binary expressions (stored directly at the right location in frame).
n.exec = nil
} else {
case isCall(child[0]) && n.child[0].typ.id() == def.typ.ret[0].id():
// Calls are optmized as long as no type conversion is involved.
n.exec = nil
default:
// Regular return: store the value to return at to start of the frame.
v := values[0]
n.exec = func(f *frame) bltn {
f.data[0].Set(v(f))
@@ -2298,25 +2327,15 @@ func arrayLit(n *node) {
values := make([]func(*frame) reflect.Value, len(child))
index := make([]int, len(child))
rtype := n.typ.val.TypeOf()
var max, prev int
ntyp := n.typ.resolveAlias()
for i, c := range child {
if c.kind == keyValueExpr {
convertLiteralValue(c.child[1], rtype)
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c.child[1])
} else {
values[i] = genValue(c.child[1])
}
values[i] = genDestValue(ntyp.val, c.child[1])
index[i] = int(vInt(c.child[0].rval))
} else {
convertLiteralValue(c, rtype)
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c)
} else {
values[i] = genValue(c)
}
values[i] = genDestValue(ntyp.val, c)
index[i] = prev
}
prev = index[i] + 1
@@ -2349,22 +2368,12 @@ func mapLit(n *node) {
if n.nleft == 1 {
child = n.child[1:]
}
typ := n.typ.TypeOf()
typ := n.typ.frameType()
keys := make([]func(*frame) reflect.Value, len(child))
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
convertLiteralValue(c.child[0], n.typ.key.TypeOf())
convertLiteralValue(c.child[1], n.typ.val.TypeOf())
if isInterfaceSrc(n.typ.key) {
keys[i] = genValueInterface(c.child[0])
} else {
keys[i] = genValue(c.child[0])
}
if isInterfaceSrc(n.typ.val) && !isEmptyInterface(n.typ.val) {
values[i] = genValueInterface(c.child[1])
} else {
values[i] = genValue(c.child[1])
}
keys[i] = genDestValue(n.typ.key, c.child[0])
values[i] = genDestValue(n.typ.val, c.child[1])
}
n.exec = func(f *frame) bltn {
@@ -2384,7 +2393,7 @@ func compositeBinMap(n *node) {
if n.nleft == 1 {
child = n.child[1:]
}
typ := n.typ.TypeOf()
typ := n.typ.frameType()
keys := make([]func(*frame) reflect.Value, len(child))
values := make([]func(*frame) reflect.Value, len(child))
for i, c := range child {
@@ -2615,31 +2624,50 @@ var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type
func _range(n *node) {
index0 := n.child[0].findex // array index location in frame
index2 := index0 - 1 // shallow array for range, always just behind index0
index3 := index2 - 1 // additional location to store string char position
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)
var value func(*frame) reflect.Value
var an *node
if len(n.child) == 4 {
an := n.child[2]
an = n.child[2]
index1 := n.child[1].findex // array value location in frame
if isString(an.typ.TypeOf()) {
// Special variant of "range" for string, where the index indicates the byte position
// of the rune in the string, rather than the index of the rune in array.
stringType := reflect.TypeOf("")
value = genValueAs(an, rat) // range on string iterates over runes
n.exec = func(f *frame) bltn {
a := f.data[index2]
v0 := f.data[index3]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
if i >= a.Len() {
return fnext
}
// Compute byte position of the rune in string
pos := a.Slice(0, i).Convert(stringType).Len()
f.data[index0].SetInt(int64(pos))
f.data[index1].Set(a.Index(i))
return tnext
}
} else {
value = genValueRangeArray(an)
}
n.exec = func(f *frame) bltn {
a := f.data[index2]
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
if i >= a.Len() {
return fnext
n.exec = func(f *frame) bltn {
a := f.data[index2]
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
if i >= a.Len() {
return fnext
}
f.data[index1].Set(a.Index(i))
return tnext
}
f.data[index1].Set(a.Index(i))
return tnext
}
} else {
an := n.child[1]
an = n.child[1]
if isString(an.typ.TypeOf()) {
value = genValueAs(an, rat) // range on string iterates over runes
} else {
@@ -2657,9 +2685,13 @@ func _range(n *node) {
// Init sequence
next := n.exec
index := index0
if isString(an.typ.TypeOf()) && len(n.child) == 4 {
index = index3
}
n.child[0].exec = func(f *frame) bltn {
f.data[index2] = value(f) // set array shallow copy for range
f.data[index0].SetInt(-1) // assing index value
f.data[index].SetInt(-1) // assing index value
return next
}
}
@@ -2935,7 +2967,7 @@ func _append(n *node) {
if len(n.child) == 3 {
c1, c2 := n.child[1], n.child[2]
if (c1.typ.cat == valueT || c2.typ.cat == valueT) && c1.typ.rtype == c2.typ.rtype ||
(c2.typ.cat == arrayT || c2.typ.cat == sliceT || c2.typ.cat == variadicT) && c2.typ.val.id() == n.typ.val.id() ||
isArray(c2.typ) && c2.typ.elem().id() == n.typ.elem().id() ||
isByteArray(c1.typ.TypeOf()) && isString(c2.typ.TypeOf()) {
appendSlice(n)
return
@@ -2956,6 +2988,8 @@ func _append(n *node) {
values[i] = genValue(arg)
case isInterfaceSrc(n.typ.val):
values[i] = genValueInterface(arg)
case isInterfaceBin(n.typ.val):
values[i] = genInterfaceWrapper(arg, n.typ.val.rtype)
case isRecursiveType(n.typ.val, n.typ.val.rtype):
values[i] = genValueRecursiveInterface(arg, n.typ.val.rtype)
case arg.typ.untyped:
@@ -2975,13 +3009,15 @@ func _append(n *node) {
}
} else {
var value0 func(*frame) reflect.Value
switch {
case isEmptyInterface(n.typ.val):
switch elem := n.typ.elem(); {
case isEmptyInterface(elem):
value0 = genValue(n.child[2])
case isInterfaceSrc(n.typ.val):
case isInterfaceSrc(elem):
value0 = genValueInterface(n.child[2])
case isRecursiveType(n.typ.val, n.typ.val.rtype):
value0 = genValueRecursiveInterface(n.child[2], n.typ.val.rtype)
case isInterfaceBin(elem):
value0 = genInterfaceWrapper(n.child[2], elem.rtype)
case isRecursiveType(elem, elem.rtype):
value0 = genValueRecursiveInterface(n.child[2], elem.rtype)
case n.child[2].typ.untyped:
value0 = genValueAs(n.child[2], n.child[1].typ.TypeOf().Elem())
default:
@@ -3423,15 +3459,7 @@ func send(n *node) {
next := getExec(n.tnext)
c0, c1 := n.child[0], n.child[1]
value0 := genValue(c0) // Send channel.
convertLiteralValue(c1, c0.typ.val.TypeOf())
var value1 func(*frame) reflect.Value // Value to send.
switch {
case isInterfaceBin(c0.typ.val):
value1 = genInterfaceWrapper(c1, c0.typ.val.rtype)
default:
value1 = genValue(c1)
}
value1 := genDestValue(c0.typ.val, c1)
if !n.interp.cancelChan {
// Send is non-cancellable, has the least overhead.

View File

@@ -0,0 +1,49 @@
package interp_test
import (
"log"
"github.com/traefik/yaegi/interp"
"github.com/traefik/yaegi/stdlib"
)
func ExampleInterpreter_self() {
i := interp.New(interp.Options{})
if err := i.Use(stdlib.Symbols); err != nil {
log.Fatal(err)
}
if err := i.Use(interp.Symbols); err != nil {
log.Fatal(err)
}
_, err := i.Eval(`import (
"fmt"
"log"
// Import interp to gain access to Self.
"github.com/traefik/yaegi/interp"
)`)
if err != nil {
log.Fatal(err)
}
_, err = i.Eval(`
// Evaluate code directly.
fmt.Println("Hello Yaegi from Go")
// Evaluate code indirectly via the Self access point.
_, err := interp.Self.Eval("fmt.Println(\"Hello Yaegi from Yaegi\")")
if err != nil {
log.Fatal(err)
}
`)
if err != nil {
log.Fatal(err)
}
// Output:
//
// Hello Yaegi from Go
// Hello Yaegi from Yaegi
}

View File

@@ -303,7 +303,7 @@ func effectivePkg(root, path string) string {
}
// isPathRelative returns true if path starts with "./" or "../".
// It is intended for use on import paths, where "/" is always the directory separator.
func isPathRelative(s string) bool {
p := "." + string(filepath.Separator)
return strings.HasPrefix(s, p) || strings.HasPrefix(s, "."+p)
return strings.HasPrefix(s, "./") || strings.HasPrefix(s, "../")
}

View File

@@ -201,19 +201,11 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
if sym.kind != constSym {
return nil, c0.cfgErrorf("non-constant array bound %q", c0.ident)
}
if sym.typ == nil || sym.typ.cat != intT || !sym.rval.IsValid() {
if sym.typ == nil || !isInt(sym.typ.TypeOf()) || !sym.rval.IsValid() {
t.incomplete = true
break
}
if v, ok := sym.rval.Interface().(int); ok {
t.length = v
break
}
if c, ok := sym.rval.Interface().(constant.Value); ok {
t.length = constToInt(c)
break
}
t.incomplete = true
t.length = int(vInt(sym.rval))
default:
// Size is defined by a numeric constant expression.
if _, err = interp.cfg(c0, sc.pkgID); err != nil {
@@ -277,47 +269,33 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
}
}
// Because an empty interface concrete type "mutates" as different values are
// assigned to it, we need to make a new itype from scratch everytime a new
// assignment is made, and not let different nodes (of the same variable) share the
// same itype. Otherwise they would overwrite each other.
if n.anc.kind == assignStmt && isInterface(n.anc.child[0].typ) && len(n.anc.child[0].typ.field) == 0 {
// TODO(mpl): do the indexes properly for multiple assignments on the same line.
// Also, maybe we should use nodeType to figure out dt.cat? but isn't it always
// gonna be an interfaceT anyway?
dt := new(itype)
dt.cat = interfaceT
val := new(itype)
val.cat = t.cat
dt.val = val
// TODO(mpl): do the indexes properly for multiple assignments on the same line.
// Also, maybe we should use nodeType to figure out dt.cat? but isn't it always
// gonna be an interfaceT anyway?
n.anc.child[0].typ = dt
// TODO(mpl): not sure yet whether we should do that last step. It doesn't seem
// to change anything either way though.
// t = dt
break
}
// If the node is to be assigned or returned, the node type is the destination type.
dt := t
switch a := n.anc; {
case a.kind == assignStmt && isEmptyInterface(a.child[0].typ):
// Because an empty interface concrete type "mutates" as different values are
// assigned to it, we need to make a new itype from scratch everytime a new
// assignment is made, and not let different nodes (of the same variable) share the
// same itype. Otherwise they would overwrite each other.
a.child[0].typ = &itype{cat: interfaceT, val: dt}
case a.kind == defineStmt && len(a.child) > a.nleft+a.nright:
if dt, err = nodeType(interp, sc, a.child[a.nleft]); err != nil {
return nil, err
}
case a.kind == returnStmt:
dt = sc.def.typ.ret[childPos(n)]
}
if isInterface(dt) {
dt.val = t
}
t = dt
case callExpr:
if interp.isBuiltinCall(n) {
if isBuiltinCall(n, sc) {
// Builtin types are special and may depend from their input arguments.
t.cat = builtinT
switch n.child[0].ident {
@@ -689,11 +667,16 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
return t, err
}
func (interp *Interpreter) isBuiltinCall(n *node) bool {
func isBuiltinCall(n *node, sc *scope) bool {
if n.kind != callExpr {
return false
}
s := interp.universe.sym[n.child[0].ident]
s := n.child[0].sym
if s == nil {
if sym, _, found := sc.lookup(n.child[0].ident); found {
s = sym
}
}
return s != nil && s.kind == bltnSym
}
@@ -891,6 +874,10 @@ func (t *itype) isRecursive() bool {
return false
}
func (t *itype) isIndirectRecursive() bool {
return t.isRecursive() || t.val != nil && t.val.isIndirectRecursive()
}
// isVariadic returns true if the function type is variadic.
// If the type is not a function or is not variadic, it will
// return false.
@@ -965,7 +952,7 @@ func (t *itype) assignableTo(o *itype) bool {
return true
}
if t.cat == aliasT && o.cat == aliasT {
// if alias types are not identical, it is not assignable.
// If alias types are not identical, it is not assignable.
return false
}
if t.isNil() && o.hasNil() || o.isNil() && t.hasNil() {
@@ -980,6 +967,11 @@ func (t *itype) assignableTo(o *itype) bool {
return true
}
if t.isBinMethod && isFunc(o) {
// TODO (marc): check that t without receiver as first parameter is equivalent to o.
return true
}
n := t.node
if n == nil || !n.rval.IsValid() {
return false
@@ -1172,6 +1164,10 @@ func (t *itype) id() (res string) {
}
res += "}"
case valueT:
if isConstantValue(t.rtype) {
res = fixPossibleConstType(t.rtype).String()
break
}
res = ""
if t.rtype.PkgPath() != "" {
res += t.rtype.PkgPath() + "."
@@ -1180,9 +1176,35 @@ func (t *itype) id() (res string) {
case variadicT:
res = "..." + t.val.id()
}
if res == "" {
res = t.TypeOf().String()
}
return res
}
// fixPossibleConstType returns the input type if it not a constant value,
// otherwise, it returns the default Go type corresponding to the
// constant.Value.
func fixPossibleConstType(t reflect.Type) (r reflect.Type) {
cv, ok := reflect.New(t).Elem().Interface().(constant.Value)
if !ok {
return t
}
switch cv.Kind() {
case constant.Bool:
r = reflect.TypeOf(true)
case constant.Int:
r = reflect.TypeOf(0)
case constant.String:
r = reflect.TypeOf("")
case constant.Float:
r = reflect.TypeOf(float64(0))
case constant.Complex:
r = reflect.TypeOf(complex128(0))
}
return r
}
// zero instantiates and return a zero value object for the given type during execution.
func (t *itype) zero() (v reflect.Value, err error) {
if t, err = t.finalize(); err != nil {
@@ -1232,24 +1254,36 @@ func (t *itype) fieldSeq(seq []int) *itype {
// lookupField returns a list of indices, i.e. a path to access a field in a struct object.
func (t *itype) lookupField(name string) []int {
switch t.cat {
case aliasT, ptrT:
return t.val.lookupField(name)
}
if fi := t.fieldIndex(name); fi >= 0 {
return []int{fi}
}
seen := map[*itype]bool{}
var lookup func(*itype) []int
for i, f := range t.field {
switch f.typ.cat {
case ptrT, structT, interfaceT, aliasT:
if index2 := f.typ.lookupField(name); len(index2) > 0 {
return append([]int{i}, index2...)
lookup = func(typ *itype) []int {
if seen[typ] {
return nil
}
seen[typ] = true
switch typ.cat {
case aliasT, ptrT:
return lookup(typ.val)
}
if fi := typ.fieldIndex(name); fi >= 0 {
return []int{fi}
}
for i, f := range typ.field {
switch f.typ.cat {
case ptrT, structT, interfaceT, aliasT:
if index2 := lookup(f.typ); len(index2) > 0 {
return append([]int{i}, index2...)
}
}
}
return nil
}
return nil
return lookup(t)
}
// lookupBinField returns a structfield and a path to access an embedded binary field in a struct object.
@@ -1260,10 +1294,13 @@ func (t *itype) lookupBinField(name string) (s reflect.StructField, index []int,
if !isStruct(t) {
return
}
rt := t.rtype
if t.cat == valueT && rt.Kind() == reflect.Ptr {
rt := t.TypeOf()
for t.cat == valueT && rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
return
}
s, ok = rt.FieldByName(name)
if !ok {
for i, f := range t.field {
@@ -1294,6 +1331,13 @@ func (t *itype) methodCallType() reflect.Type {
return reflect.FuncOf(it, ot, t.rtype.IsVariadic())
}
func (t *itype) resolveAlias() *itype {
for t.cat == aliasT {
t = t.val
}
return t
}
// GetMethod returns a pointer to the method definition.
func (t *itype) getMethod(name string) *node {
for _, m := range t.method {
@@ -1321,10 +1365,24 @@ func (t *itype) lookupMethod(name string) (*node, []int) {
}
}
}
if t.cat == aliasT || isInterfaceSrc(t) && t.val != nil {
return t.val.lookupMethod(name)
}
}
return m, index
}
// methodDepth returns a depth greater or equal to 0, or -1 if no match.
func (t *itype) methodDepth(name string) int {
if m, lint := t.lookupMethod(name); m != nil {
return len(lint)
}
if _, lint, _, ok := t.lookupBinMethod(name); ok {
return len(lint)
}
return -1
}
// LookupBinMethod returns a method and a path to access a field in a struct object (the receiver).
func (t *itype) lookupBinMethod(name string) (m reflect.Method, index []int, isPtr, ok bool) {
if t.cat == ptrT {
@@ -1530,6 +1588,8 @@ func (t *itype) frameType() (r reflect.Type) {
break
}
r = reflect.TypeOf((*valueInterface)(nil)).Elem()
case mapT:
r = reflect.MapOf(t.key.frameType(), t.val.frameType())
case ptrT:
r = reflect.PtrTo(t.val.frameType())
default:
@@ -1539,7 +1599,7 @@ func (t *itype) frameType() (r reflect.Type) {
}
func (t *itype) implements(it *itype) bool {
if t.cat == valueT {
if isBin(t) {
return t.TypeOf().Implements(it.TypeOf())
}
return t.methods().contains(it.methods())
@@ -1582,6 +1642,13 @@ func (t *itype) hasNil() bool {
return false
}
func (t *itype) elem() *itype {
if t.cat == valueT {
return &itype{cat: valueT, rtype: t.rtype.Elem()}
}
return t.val
}
func copyDefined(m map[string]*itype) map[string]*itype {
n := make(map[string]*itype, len(m))
for k, v := range m {
@@ -1695,6 +1762,9 @@ func isSendChan(t *itype) bool {
}
func isArray(t *itype) bool {
if t.cat == nilT {
return false
}
k := t.TypeOf().Kind()
return k == reflect.Array || k == reflect.Slice
}
@@ -1704,13 +1774,24 @@ func isInterfaceSrc(t *itype) bool {
}
func isInterfaceBin(t *itype) bool {
return t.cat == valueT && t.rtype.Kind() == reflect.Interface
return t.cat == valueT && t.rtype.Kind() == reflect.Interface || t.cat == errorT
}
func isInterface(t *itype) bool {
return isInterfaceSrc(t) || t.TypeOf() != nil && t.TypeOf().Kind() == reflect.Interface
}
func isBin(t *itype) bool {
switch t.cat {
case valueT:
return true
case aliasT, ptrT:
return isBin(t.val)
default:
return false
}
}
func isStruct(t *itype) bool {
// Test first for a struct category, because a recursive interpreter struct may be
// represented by an interface{} at reflect level.

View File

@@ -32,6 +32,9 @@ func (check typecheck) op(p opPredicates, a action, n, c *node, t reflect.Type)
//
// Use typ == nil to indicate assignment to an untyped blank identifier.
func (check typecheck) assignment(n *node, typ *itype, context string) error {
if n.typ == nil {
return n.cfgErrorf("invalid type in %s", context)
}
if n.typ.untyped {
if typ == nil || isInterface(typ) {
if typ == nil && n.typ.cat == nilT {
@@ -48,7 +51,7 @@ func (check typecheck) assignment(n *node, typ *itype, context string) error {
return nil
}
if typ.isRecursive() || typ.val != nil && typ.val.isRecursive() {
if typ.isIndirectRecursive() || n.typ.isIndirectRecursive() {
return nil
}
@@ -102,6 +105,7 @@ func (check typecheck) addressExpr(n *node) error {
c := c0.child[0]
if isArray(c.typ) || isMap(c.typ) {
c0 = c
found = true
continue
}
case compositeLitExpr, identExpr:
@@ -143,10 +147,7 @@ func (check typecheck) unaryExpr(n *node) error {
return nil
}
if err := check.op(unaryOpPredicates, n.action, n, c0, t0); err != nil {
return err
}
return nil
return check.op(unaryOpPredicates, n.action, n, c0, t0)
}
// shift type checks a shift binary expression.
@@ -232,6 +233,15 @@ func (check typecheck) binaryExpr(n *node) error {
}
switch n.action {
case aAdd:
if n.typ == nil {
break
}
// Catch mixing string and number for "+" operator use.
k, k0, k1 := isNumber(n.typ.TypeOf()), isNumber(c0.typ.TypeOf()), isNumber(c1.typ.TypeOf())
if k != k0 || k != k1 {
return n.cfgErrorf("cannot use type %s as type %s in assignment", c0.typ.id(), n.typ.id())
}
case aRem:
if zeroConst(c1) {
return n.cfgErrorf("invalid operation: division by zero")
@@ -258,10 +268,8 @@ func (check typecheck) binaryExpr(n *node) error {
}
t0 := c0.typ.TypeOf()
if err := check.op(binaryOpPredicates, a, n, c0, t0); err != nil {
return err
}
return nil
return check.op(binaryOpPredicates, a, n, c0, t0)
}
func zeroConst(n *node) bool {
@@ -985,6 +993,8 @@ func getArg(ftyp *itype, i int) *itype {
return arg
case i < l:
return ftyp.in(i)
case ftyp.cat == valueT && i < ftyp.rtype.NumIn():
return &itype{cat: valueT, rtype: ftyp.rtype.In(i)}
default:
return nil
}

View File

@@ -157,14 +157,27 @@ func genValueAsFunctionWrapper(n *node) func(*frame) reflect.Value {
if v.IsNil() {
return reflect.New(typ).Elem()
}
return genFunctionWrapper(v.Interface().(*node))(f)
vn, ok := v.Interface().(*node)
if ok && vn.rval.IsValid() && vn.rval.Type().Kind() == reflect.Func {
// The node value is already a callable func, no need to wrap it.
return vn.rval
}
return genFunctionWrapper(vn)(f)
}
}
func genValueAs(n *node, t reflect.Type) func(*frame) reflect.Value {
v := genValue(n)
value := genValue(n)
return func(f *frame) reflect.Value {
return v(f).Convert(t)
v := value(f)
switch v.Type().Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice, reflect.UnsafePointer:
if v.IsNil() {
return reflect.New(t).Elem()
}
}
return v.Convert(t)
}
}
@@ -214,6 +227,31 @@ func genValue(n *node) func(*frame) reflect.Value {
}
}
func genDestValue(typ *itype, n *node) func(*frame) reflect.Value {
convertLiteralValue(n, typ.TypeOf())
switch {
case isInterfaceSrc(typ) && !isEmptyInterface(typ):
return genValueInterface(n)
case isFuncSrc(typ) && n.typ.cat == valueT:
return genValueNode(n)
case typ.cat == valueT && isFuncSrc(n.typ):
return genFunctionWrapper(n)
case isInterfaceBin(typ):
return genInterfaceWrapper(n, typ.rtype)
case n.kind == basicLit && n.val == nil:
return func(*frame) reflect.Value { return reflect.New(typ.rtype).Elem() }
case isRecursiveType(typ, typ.rtype):
return genValueRecursiveInterface(n, typ.rtype)
case isRecursiveType(n.typ, n.typ.rtype):
return genValueRecursiveInterfacePtrValue(n)
case n.typ.untyped && isComplex(typ.TypeOf()):
return genValueComplex(n)
case n.typ.untyped && !typ.untyped:
return genValueAs(n, typ.TypeOf())
}
return genValue(n)
}
func genValueArray(n *node) func(*frame) reflect.Value {
value := genValue(n)
// dereference array pointer, to support array operations on array pointer
@@ -310,7 +348,7 @@ func zeroInterfaceValue() reflect.Value {
}
func wantEmptyInterface(n *node) bool {
return n.typ.cat == interfaceT && len(n.typ.field) == 0 ||
return isEmptyInterface(n.typ) ||
n.anc.action == aAssign && n.anc.typ.cat == interfaceT && len(n.anc.typ.field) == 0 ||
n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT && len(n.anc.val.(*node).typ.ret[0].field) == 0
}
@@ -325,7 +363,7 @@ func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
}
fallthrough
case n.anc.kind == returnStmt && n.anc.val.(*node).typ.ret[0].cat == interfaceT:
if len(n.anc.val.(*node).typ.ret[0].field) == 0 {
if nod, ok := n.anc.val.(*node); !ok || len(nod.typ.ret[0].field) == 0 {
// empty interface, do not wrap
return value
}

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["archive/tar"] = map[string]reflect.Value{
Symbols["archive/tar/tar"] = map[string]reflect.Value{
// function, constant and variable definitions
"ErrFieldTooLong": reflect.ValueOf(&tar.ErrFieldTooLong).Elem(),
"ErrHeader": reflect.ValueOf(&tar.ErrHeader).Elem(),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["archive/zip"] = map[string]reflect.Value{
Symbols["archive/zip/zip"] = map[string]reflect.Value{
// function, constant and variable definitions
"Deflate": reflect.ValueOf(zip.Deflate),
"ErrAlgorithm": reflect.ValueOf(&zip.ErrAlgorithm).Elem(),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["bufio"] = map[string]reflect.Value{
Symbols["bufio/bufio"] = map[string]reflect.Value{
// function, constant and variable definitions
"ErrAdvanceTooFar": reflect.ValueOf(&bufio.ErrAdvanceTooFar).Elem(),
"ErrBadReadCount": reflect.ValueOf(&bufio.ErrBadReadCount).Elem(),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["bytes"] = map[string]reflect.Value{
Symbols["bytes/bytes"] = map[string]reflect.Value{
// function, constant and variable definitions
"Compare": reflect.ValueOf(bytes.Compare),
"Contains": reflect.ValueOf(bytes.Contains),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["compress/bzip2"] = map[string]reflect.Value{
Symbols["compress/bzip2/bzip2"] = map[string]reflect.Value{
// function, constant and variable definitions
"NewReader": reflect.ValueOf(bzip2.NewReader),

View File

@@ -13,7 +13,7 @@ import (
)
func init() {
Symbols["compress/flate"] = map[string]reflect.Value{
Symbols["compress/flate/flate"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(constant.MakeFromLiteral("9", token.INT, 0)),
"BestSpeed": reflect.ValueOf(constant.MakeFromLiteral("1", token.INT, 0)),
@@ -42,6 +42,7 @@ func init() {
// _compress_flate_Reader is an interface wrapper for Reader type
type _compress_flate_Reader struct {
IValue interface{}
WRead func(p []byte) (n int, err error)
WReadByte func() (byte, error)
}
@@ -51,6 +52,7 @@ func (W _compress_flate_Reader) ReadByte() (byte, error) { return W.WRe
// _compress_flate_Resetter is an interface wrapper for Resetter type
type _compress_flate_Resetter struct {
IValue interface{}
WReset func(r io.Reader, dict []byte) error
}

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["compress/gzip"] = map[string]reflect.Value{
Symbols["compress/gzip/gzip"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(constant.MakeFromLiteral("9", token.INT, 0)),
"BestSpeed": reflect.ValueOf(constant.MakeFromLiteral("1", token.INT, 0)),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["compress/lzw"] = map[string]reflect.Value{
Symbols["compress/lzw/lzw"] = map[string]reflect.Value{
// function, constant and variable definitions
"LSB": reflect.ValueOf(lzw.LSB),
"MSB": reflect.ValueOf(lzw.MSB),

View File

@@ -13,7 +13,7 @@ import (
)
func init() {
Symbols["compress/zlib"] = map[string]reflect.Value{
Symbols["compress/zlib/zlib"] = map[string]reflect.Value{
// function, constant and variable definitions
"BestCompression": reflect.ValueOf(constant.MakeFromLiteral("9", token.INT, 0)),
"BestSpeed": reflect.ValueOf(constant.MakeFromLiteral("1", token.INT, 0)),
@@ -40,6 +40,7 @@ func init() {
// _compress_zlib_Resetter is an interface wrapper for Resetter type
type _compress_zlib_Resetter struct {
IValue interface{}
WReset func(r io.Reader, dict []byte) error
}

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["container/heap"] = map[string]reflect.Value{
Symbols["container/heap/heap"] = map[string]reflect.Value{
// function, constant and variable definitions
"Fix": reflect.ValueOf(heap.Fix),
"Init": reflect.ValueOf(heap.Init),
@@ -28,11 +28,12 @@ func init() {
// _container_heap_Interface is an interface wrapper for Interface type
type _container_heap_Interface struct {
WLen func() int
WLess func(i int, j int) bool
WPop func() interface{}
WPush func(x interface{})
WSwap func(i int, j int)
IValue interface{}
WLen func() int
WLess func(i int, j int) bool
WPop func() interface{}
WPush func(x interface{})
WSwap func(i int, j int)
}
func (W _container_heap_Interface) Len() int { return W.WLen() }

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["container/list"] = map[string]reflect.Value{
Symbols["container/list/list"] = map[string]reflect.Value{
// function, constant and variable definitions
"New": reflect.ValueOf(list.New),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["container/ring"] = map[string]reflect.Value{
Symbols["container/ring/ring"] = map[string]reflect.Value{
// function, constant and variable definitions
"New": reflect.ValueOf(ring.New),

View File

@@ -11,7 +11,7 @@ import (
)
func init() {
Symbols["context"] = map[string]reflect.Value{
Symbols["context/context"] = map[string]reflect.Value{
// function, constant and variable definitions
"Background": reflect.ValueOf(context.Background),
"Canceled": reflect.ValueOf(&context.Canceled).Elem(),
@@ -33,6 +33,7 @@ func init() {
// _context_Context is an interface wrapper for Context type
type _context_Context struct {
IValue interface{}
WDeadline func() (deadline time.Time, ok bool)
WDone func() <-chan struct{}
WErr func() error

View File

@@ -11,7 +11,7 @@ import (
)
func init() {
Symbols["crypto"] = map[string]reflect.Value{
Symbols["crypto/crypto"] = map[string]reflect.Value{
// function, constant and variable definitions
"BLAKE2b_256": reflect.ValueOf(crypto.BLAKE2b_256),
"BLAKE2b_384": reflect.ValueOf(crypto.BLAKE2b_384),
@@ -55,6 +55,7 @@ func init() {
// _crypto_Decrypter is an interface wrapper for Decrypter type
type _crypto_Decrypter struct {
IValue interface{}
WDecrypt func(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error)
WPublic func() crypto.PublicKey
}
@@ -66,18 +67,22 @@ func (W _crypto_Decrypter) Public() crypto.PublicKey { return W.WPublic() }
// _crypto_DecrypterOpts is an interface wrapper for DecrypterOpts type
type _crypto_DecrypterOpts struct {
IValue interface{}
}
// _crypto_PrivateKey is an interface wrapper for PrivateKey type
type _crypto_PrivateKey struct {
IValue interface{}
}
// _crypto_PublicKey is an interface wrapper for PublicKey type
type _crypto_PublicKey struct {
IValue interface{}
}
// _crypto_Signer is an interface wrapper for Signer type
type _crypto_Signer struct {
IValue interface{}
WPublic func() crypto.PublicKey
WSign func(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error)
}
@@ -89,6 +94,7 @@ func (W _crypto_Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOp
// _crypto_SignerOpts is an interface wrapper for SignerOpts type
type _crypto_SignerOpts struct {
IValue interface{}
WHashFunc func() crypto.Hash
}

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/aes"] = map[string]reflect.Value{
Symbols["crypto/aes/aes"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("16", token.INT, 0)),
"NewCipher": reflect.ValueOf(aes.NewCipher),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/cipher"] = map[string]reflect.Value{
Symbols["crypto/cipher/cipher"] = map[string]reflect.Value{
// function, constant and variable definitions
"NewCBCDecrypter": reflect.ValueOf(cipher.NewCBCDecrypter),
"NewCBCEncrypter": reflect.ValueOf(cipher.NewCBCEncrypter),
@@ -40,6 +40,7 @@ func init() {
// _crypto_cipher_AEAD is an interface wrapper for AEAD type
type _crypto_cipher_AEAD struct {
IValue interface{}
WNonceSize func() int
WOpen func(dst []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error)
WOverhead func() int
@@ -57,6 +58,7 @@ func (W _crypto_cipher_AEAD) Seal(dst []byte, nonce []byte, plaintext []byte, ad
// _crypto_cipher_Block is an interface wrapper for Block type
type _crypto_cipher_Block struct {
IValue interface{}
WBlockSize func() int
WDecrypt func(dst []byte, src []byte)
WEncrypt func(dst []byte, src []byte)
@@ -68,6 +70,7 @@ func (W _crypto_cipher_Block) Encrypt(dst []byte, src []byte) { W.WEncrypt(dst,
// _crypto_cipher_BlockMode is an interface wrapper for BlockMode type
type _crypto_cipher_BlockMode struct {
IValue interface{}
WBlockSize func() int
WCryptBlocks func(dst []byte, src []byte)
}
@@ -77,6 +80,7 @@ func (W _crypto_cipher_BlockMode) CryptBlocks(dst []byte, src []byte) { W.WCrypt
// _crypto_cipher_Stream is an interface wrapper for Stream type
type _crypto_cipher_Stream struct {
IValue interface{}
WXORKeyStream func(dst []byte, src []byte)
}

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/des"] = map[string]reflect.Value{
Symbols["crypto/des/des"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("8", token.INT, 0)),
"NewCipher": reflect.ValueOf(des.NewCipher),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/dsa"] = map[string]reflect.Value{
Symbols["crypto/dsa/dsa"] = map[string]reflect.Value{
// function, constant and variable definitions
"ErrInvalidPublicKey": reflect.ValueOf(&dsa.ErrInvalidPublicKey).Elem(),
"GenerateKey": reflect.ValueOf(dsa.GenerateKey),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/ecdsa"] = map[string]reflect.Value{
Symbols["crypto/ecdsa/ecdsa"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(ecdsa.GenerateKey),
"Sign": reflect.ValueOf(ecdsa.Sign),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/ed25519"] = map[string]reflect.Value{
Symbols["crypto/ed25519/ed25519"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(ed25519.GenerateKey),
"NewKeyFromSeed": reflect.ValueOf(ed25519.NewKeyFromSeed),

View File

@@ -11,7 +11,7 @@ import (
)
func init() {
Symbols["crypto/elliptic"] = map[string]reflect.Value{
Symbols["crypto/elliptic/elliptic"] = map[string]reflect.Value{
// function, constant and variable definitions
"GenerateKey": reflect.ValueOf(elliptic.GenerateKey),
"Marshal": reflect.ValueOf(elliptic.Marshal),
@@ -34,6 +34,7 @@ func init() {
// _crypto_elliptic_Curve is an interface wrapper for Curve type
type _crypto_elliptic_Curve struct {
IValue interface{}
WAdd func(x1 *big.Int, y1 *big.Int, x2 *big.Int, y2 *big.Int) (x *big.Int, y *big.Int)
WDouble func(x1 *big.Int, y1 *big.Int) (x *big.Int, y *big.Int)
WIsOnCurve func(x *big.Int, y *big.Int) bool

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/hmac"] = map[string]reflect.Value{
Symbols["crypto/hmac/hmac"] = map[string]reflect.Value{
// function, constant and variable definitions
"Equal": reflect.ValueOf(hmac.Equal),
"New": reflect.ValueOf(hmac.New),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/md5"] = map[string]reflect.Value{
Symbols["crypto/md5/md5"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"New": reflect.ValueOf(md5.New),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/rand"] = map[string]reflect.Value{
Symbols["crypto/rand/rand"] = map[string]reflect.Value{
// function, constant and variable definitions
"Int": reflect.ValueOf(rand.Int),
"Prime": reflect.ValueOf(rand.Prime),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/rc4"] = map[string]reflect.Value{
Symbols["crypto/rc4/rc4"] = map[string]reflect.Value{
// function, constant and variable definitions
"NewCipher": reflect.ValueOf(rc4.NewCipher),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/rsa"] = map[string]reflect.Value{
Symbols["crypto/rsa/rsa"] = map[string]reflect.Value{
// function, constant and variable definitions
"DecryptOAEP": reflect.ValueOf(rsa.DecryptOAEP),
"DecryptPKCS1v15": reflect.ValueOf(rsa.DecryptPKCS1v15),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/sha1"] = map[string]reflect.Value{
Symbols["crypto/sha1/sha1"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"New": reflect.ValueOf(sha1.New),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/sha256"] = map[string]reflect.Value{
Symbols["crypto/sha256/sha256"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("64", token.INT, 0)),
"New": reflect.ValueOf(sha256.New),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/sha512"] = map[string]reflect.Value{
Symbols["crypto/sha512/sha512"] = map[string]reflect.Value{
// function, constant and variable definitions
"BlockSize": reflect.ValueOf(constant.MakeFromLiteral("128", token.INT, 0)),
"New": reflect.ValueOf(sha512.New),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/subtle"] = map[string]reflect.Value{
Symbols["crypto/subtle/subtle"] = map[string]reflect.Value{
// function, constant and variable definitions
"ConstantTimeByteEq": reflect.ValueOf(subtle.ConstantTimeByteEq),
"ConstantTimeCompare": reflect.ValueOf(subtle.ConstantTimeCompare),

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["crypto/tls"] = map[string]reflect.Value{
Symbols["crypto/tls/tls"] = map[string]reflect.Value{
// function, constant and variable definitions
"CipherSuiteName": reflect.ValueOf(tls.CipherSuiteName),
"CipherSuites": reflect.ValueOf(tls.CipherSuites),
@@ -108,8 +108,9 @@ func init() {
// _crypto_tls_ClientSessionCache is an interface wrapper for ClientSessionCache type
type _crypto_tls_ClientSessionCache struct {
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
WPut func(sessionKey string, cs *tls.ClientSessionState)
IValue interface{}
WGet func(sessionKey string) (session *tls.ClientSessionState, ok bool)
WPut func(sessionKey string, cs *tls.ClientSessionState)
}
func (W _crypto_tls_ClientSessionCache) Get(sessionKey string) (session *tls.ClientSessionState, ok bool) {

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/x509"] = map[string]reflect.Value{
Symbols["crypto/x509/x509"] = map[string]reflect.Value{
// function, constant and variable definitions
"CANotAuthorizedForExtKeyUsage": reflect.ValueOf(x509.CANotAuthorizedForExtKeyUsage),
"CANotAuthorizedForThisName": reflect.ValueOf(x509.CANotAuthorizedForThisName),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["crypto/x509/pkix"] = map[string]reflect.Value{
Symbols["crypto/x509/pkix/pkix"] = map[string]reflect.Value{
// type definitions
"AlgorithmIdentifier": reflect.ValueOf((*pkix.AlgorithmIdentifier)(nil)),
"AttributeTypeAndValue": reflect.ValueOf((*pkix.AttributeTypeAndValue)(nil)),

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["database/sql"] = map[string]reflect.Value{
Symbols["database/sql/sql"] = map[string]reflect.Value{
// function, constant and variable definitions
"Drivers": reflect.ValueOf(sql.Drivers),
"ErrConnDone": reflect.ValueOf(&sql.ErrConnDone).Elem(),
@@ -60,6 +60,7 @@ func init() {
// _database_sql_Result is an interface wrapper for Result type
type _database_sql_Result struct {
IValue interface{}
WLastInsertId func() (int64, error)
WRowsAffected func() (int64, error)
}
@@ -69,7 +70,8 @@ func (W _database_sql_Result) RowsAffected() (int64, error) { return W.WRowsAffe
// _database_sql_Scanner is an interface wrapper for Scanner type
type _database_sql_Scanner struct {
WScan func(src interface{}) error
IValue interface{}
WScan func(src interface{}) error
}
func (W _database_sql_Scanner) Scan(src interface{}) error { return W.WScan(src) }

View File

@@ -11,7 +11,7 @@ import (
)
func init() {
Symbols["database/sql/driver"] = map[string]reflect.Value{
Symbols["database/sql/driver/driver"] = map[string]reflect.Value{
// function, constant and variable definitions
"Bool": reflect.ValueOf(&driver.Bool).Elem(),
"DefaultParameterConverter": reflect.ValueOf(&driver.DefaultParameterConverter).Elem(),
@@ -98,6 +98,7 @@ func init() {
// _database_sql_driver_ColumnConverter is an interface wrapper for ColumnConverter type
type _database_sql_driver_ColumnConverter struct {
IValue interface{}
WColumnConverter func(idx int) driver.ValueConverter
}
@@ -107,6 +108,7 @@ func (W _database_sql_driver_ColumnConverter) ColumnConverter(idx int) driver.Va
// _database_sql_driver_Conn is an interface wrapper for Conn type
type _database_sql_driver_Conn struct {
IValue interface{}
WBegin func() (driver.Tx, error)
WClose func() error
WPrepare func(query string) (driver.Stmt, error)
@@ -120,6 +122,7 @@ func (W _database_sql_driver_Conn) Prepare(query string) (driver.Stmt, error) {
// _database_sql_driver_ConnBeginTx is an interface wrapper for ConnBeginTx type
type _database_sql_driver_ConnBeginTx struct {
IValue interface{}
WBeginTx func(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)
}
@@ -129,6 +132,7 @@ func (W _database_sql_driver_ConnBeginTx) BeginTx(ctx context.Context, opts driv
// _database_sql_driver_ConnPrepareContext is an interface wrapper for ConnPrepareContext type
type _database_sql_driver_ConnPrepareContext struct {
IValue interface{}
WPrepareContext func(ctx context.Context, query string) (driver.Stmt, error)
}
@@ -138,6 +142,7 @@ func (W _database_sql_driver_ConnPrepareContext) PrepareContext(ctx context.Cont
// _database_sql_driver_Connector is an interface wrapper for Connector type
type _database_sql_driver_Connector struct {
IValue interface{}
WConnect func(a0 context.Context) (driver.Conn, error)
WDriver func() driver.Driver
}
@@ -149,13 +154,15 @@ func (W _database_sql_driver_Connector) Driver() driver.Driver { return W.WDrive
// _database_sql_driver_Driver is an interface wrapper for Driver type
type _database_sql_driver_Driver struct {
WOpen func(name string) (driver.Conn, error)
IValue interface{}
WOpen func(name string) (driver.Conn, error)
}
func (W _database_sql_driver_Driver) Open(name string) (driver.Conn, error) { return W.WOpen(name) }
// _database_sql_driver_DriverContext is an interface wrapper for DriverContext type
type _database_sql_driver_DriverContext struct {
IValue interface{}
WOpenConnector func(name string) (driver.Connector, error)
}
@@ -165,7 +172,8 @@ func (W _database_sql_driver_DriverContext) OpenConnector(name string) (driver.C
// _database_sql_driver_Execer is an interface wrapper for Execer type
type _database_sql_driver_Execer struct {
WExec func(query string, args []driver.Value) (driver.Result, error)
IValue interface{}
WExec func(query string, args []driver.Value) (driver.Result, error)
}
func (W _database_sql_driver_Execer) Exec(query string, args []driver.Value) (driver.Result, error) {
@@ -174,6 +182,7 @@ func (W _database_sql_driver_Execer) Exec(query string, args []driver.Value) (dr
// _database_sql_driver_ExecerContext is an interface wrapper for ExecerContext type
type _database_sql_driver_ExecerContext struct {
IValue interface{}
WExecContext func(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)
}
@@ -183,6 +192,7 @@ func (W _database_sql_driver_ExecerContext) ExecContext(ctx context.Context, que
// _database_sql_driver_NamedValueChecker is an interface wrapper for NamedValueChecker type
type _database_sql_driver_NamedValueChecker struct {
IValue interface{}
WCheckNamedValue func(a0 *driver.NamedValue) error
}
@@ -192,13 +202,15 @@ func (W _database_sql_driver_NamedValueChecker) CheckNamedValue(a0 *driver.Named
// _database_sql_driver_Pinger is an interface wrapper for Pinger type
type _database_sql_driver_Pinger struct {
WPing func(ctx context.Context) error
IValue interface{}
WPing func(ctx context.Context) error
}
func (W _database_sql_driver_Pinger) Ping(ctx context.Context) error { return W.WPing(ctx) }
// _database_sql_driver_Queryer is an interface wrapper for Queryer type
type _database_sql_driver_Queryer struct {
IValue interface{}
WQuery func(query string, args []driver.Value) (driver.Rows, error)
}
@@ -208,6 +220,7 @@ func (W _database_sql_driver_Queryer) Query(query string, args []driver.Value) (
// _database_sql_driver_QueryerContext is an interface wrapper for QueryerContext type
type _database_sql_driver_QueryerContext struct {
IValue interface{}
WQueryContext func(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)
}
@@ -217,6 +230,7 @@ func (W _database_sql_driver_QueryerContext) QueryContext(ctx context.Context, q
// _database_sql_driver_Result is an interface wrapper for Result type
type _database_sql_driver_Result struct {
IValue interface{}
WLastInsertId func() (int64, error)
WRowsAffected func() (int64, error)
}
@@ -226,6 +240,7 @@ func (W _database_sql_driver_Result) RowsAffected() (int64, error) { return W.WR
// _database_sql_driver_Rows is an interface wrapper for Rows type
type _database_sql_driver_Rows struct {
IValue interface{}
WClose func() error
WColumns func() []string
WNext func(dest []driver.Value) error
@@ -237,6 +252,7 @@ func (W _database_sql_driver_Rows) Next(dest []driver.Value) error { return W.WN
// _database_sql_driver_RowsColumnTypeDatabaseTypeName is an interface wrapper for RowsColumnTypeDatabaseTypeName type
type _database_sql_driver_RowsColumnTypeDatabaseTypeName struct {
IValue interface{}
WClose func() error
WColumnTypeDatabaseTypeName func(index int) string
WColumns func() []string
@@ -254,6 +270,7 @@ func (W _database_sql_driver_RowsColumnTypeDatabaseTypeName) Next(dest []driver.
// _database_sql_driver_RowsColumnTypeLength is an interface wrapper for RowsColumnTypeLength type
type _database_sql_driver_RowsColumnTypeLength struct {
IValue interface{}
WClose func() error
WColumnTypeLength func(index int) (length int64, ok bool)
WColumns func() []string
@@ -271,6 +288,7 @@ func (W _database_sql_driver_RowsColumnTypeLength) Next(dest []driver.Value) err
// _database_sql_driver_RowsColumnTypeNullable is an interface wrapper for RowsColumnTypeNullable type
type _database_sql_driver_RowsColumnTypeNullable struct {
IValue interface{}
WClose func() error
WColumnTypeNullable func(index int) (nullable bool, ok bool)
WColumns func() []string
@@ -288,6 +306,7 @@ func (W _database_sql_driver_RowsColumnTypeNullable) Next(dest []driver.Value) e
// _database_sql_driver_RowsColumnTypePrecisionScale is an interface wrapper for RowsColumnTypePrecisionScale type
type _database_sql_driver_RowsColumnTypePrecisionScale struct {
IValue interface{}
WClose func() error
WColumnTypePrecisionScale func(index int) (precision int64, scale int64, ok bool)
WColumns func() []string
@@ -305,6 +324,7 @@ func (W _database_sql_driver_RowsColumnTypePrecisionScale) Next(dest []driver.Va
// _database_sql_driver_RowsColumnTypeScanType is an interface wrapper for RowsColumnTypeScanType type
type _database_sql_driver_RowsColumnTypeScanType struct {
IValue interface{}
WClose func() error
WColumnTypeScanType func(index int) reflect.Type
WColumns func() []string
@@ -322,6 +342,7 @@ func (W _database_sql_driver_RowsColumnTypeScanType) Next(dest []driver.Value) e
// _database_sql_driver_RowsNextResultSet is an interface wrapper for RowsNextResultSet type
type _database_sql_driver_RowsNextResultSet struct {
IValue interface{}
WClose func() error
WColumns func() []string
WHasNextResultSet func() bool
@@ -337,6 +358,7 @@ func (W _database_sql_driver_RowsNextResultSet) NextResultSet() error
// _database_sql_driver_SessionResetter is an interface wrapper for SessionResetter type
type _database_sql_driver_SessionResetter struct {
IValue interface{}
WResetSession func(ctx context.Context) error
}
@@ -346,6 +368,7 @@ func (W _database_sql_driver_SessionResetter) ResetSession(ctx context.Context)
// _database_sql_driver_Stmt is an interface wrapper for Stmt type
type _database_sql_driver_Stmt struct {
IValue interface{}
WClose func() error
WExec func(args []driver.Value) (driver.Result, error)
WNumInput func() int
@@ -363,6 +386,7 @@ func (W _database_sql_driver_Stmt) Query(args []driver.Value) (driver.Rows, erro
// _database_sql_driver_StmtExecContext is an interface wrapper for StmtExecContext type
type _database_sql_driver_StmtExecContext struct {
IValue interface{}
WExecContext func(ctx context.Context, args []driver.NamedValue) (driver.Result, error)
}
@@ -372,6 +396,7 @@ func (W _database_sql_driver_StmtExecContext) ExecContext(ctx context.Context, a
// _database_sql_driver_StmtQueryContext is an interface wrapper for StmtQueryContext type
type _database_sql_driver_StmtQueryContext struct {
IValue interface{}
WQueryContext func(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)
}
@@ -381,6 +406,7 @@ func (W _database_sql_driver_StmtQueryContext) QueryContext(ctx context.Context,
// _database_sql_driver_Tx is an interface wrapper for Tx type
type _database_sql_driver_Tx struct {
IValue interface{}
WCommit func() error
WRollback func() error
}
@@ -390,6 +416,7 @@ func (W _database_sql_driver_Tx) Rollback() error { return W.WRollback() }
// _database_sql_driver_Validator is an interface wrapper for Validator type
type _database_sql_driver_Validator struct {
IValue interface{}
WIsValid func() bool
}
@@ -397,10 +424,12 @@ func (W _database_sql_driver_Validator) IsValid() bool { return W.WIsValid() }
// _database_sql_driver_Value is an interface wrapper for Value type
type _database_sql_driver_Value struct {
IValue interface{}
}
// _database_sql_driver_ValueConverter is an interface wrapper for ValueConverter type
type _database_sql_driver_ValueConverter struct {
IValue interface{}
WConvertValue func(v interface{}) (driver.Value, error)
}
@@ -410,6 +439,7 @@ func (W _database_sql_driver_ValueConverter) ConvertValue(v interface{}) (driver
// _database_sql_driver_Valuer is an interface wrapper for Valuer type
type _database_sql_driver_Valuer struct {
IValue interface{}
WValue func() (driver.Value, error)
}

View File

@@ -10,7 +10,7 @@ import (
)
func init() {
Symbols["debug/dwarf"] = map[string]reflect.Value{
Symbols["debug/dwarf/dwarf"] = map[string]reflect.Value{
// function, constant and variable definitions
"AttrAbstractOrigin": reflect.ValueOf(dwarf.AttrAbstractOrigin),
"AttrAccessibility": reflect.ValueOf(dwarf.AttrAccessibility),
@@ -271,6 +271,7 @@ func init() {
// _debug_dwarf_Type is an interface wrapper for Type type
type _debug_dwarf_Type struct {
IValue interface{}
WCommon func() *dwarf.CommonType
WSize func() int64
WString func() string

View File

@@ -12,7 +12,7 @@ import (
)
func init() {
Symbols["debug/elf"] = map[string]reflect.Value{
Symbols["debug/elf/elf"] = map[string]reflect.Value{
// function, constant and variable definitions
"ARM_MAGIC_TRAMP_NUMBER": reflect.ValueOf(constant.MakeFromLiteral("1543503875", token.INT, 0)),
"COMPRESS_HIOS": reflect.ValueOf(elf.COMPRESS_HIOS),

Some files were not shown because too many files have changed in this diff Show More