Compare commits

...

16 Commits

Author SHA1 Message Date
Marc Vertes
d494f9e420 interp: support calling goto from sub-scope
As opposed to other symbols, goto labels must be searched in included
scopes, not upper ones. Implement scope.lookdown to perform this,
to allow calls to goto to be embedded in included scopes where label
is defined.

Fixes #953.
2020-11-19 12:48:03 +01:00
Marc Vertes
6da1107c39 fix: do not confuse function call with type conversion
Use node action to better discriminate between function call and type
conversion which have the same pattern at AST level.

Fixes #960.
2020-11-18 14:56:05 +01:00
Marc Vertes
38a7331bf9 interp: fix type check on function signature
Perform function declaration type check from the upper level scope (the scope where the
function is declared), to avoid possible collisions of local variables with package names.

Fixes #957.
2020-11-13 18:02:04 +01:00
Marc Vertes
13783889cb interp: avoid useless interface wrapping
in `callBin`, call arguments are converted to the corresponding
parameter type. In a case of an interface, the original concrete type
should be preserved instead, and only wrapped to an interface type for
internal interpreter types, as runtime values should already implement the
interface.

This change removes the interface wrapping when parameter is a runtime
value (valueT or ptrT to valueT).

This removes some overhead when handling runtime values, and keep a
similar behavior between interpreted and pre-compiled code. For
example, `io.Copy` preserves its internal optimisations when passed a
`bytes.Buffer`.
2020-11-12 10:48:04 +01:00
mpl
ed626f3fb9 interp: support conversion of runtime func into interp func
Conversion of interp func into runtime func already worked, but added a
test anyway to watch out for regressions.

Fixes #941
2020-11-10 00:40:04 +01:00
Marc Vertes
d0a34d467b interp: fix getting unsigned constant value
The function vUint, used to get the unsigned integer value of a value,
variable (frame) or constant, was broken for constant.Value expression.

Fixes #948.
2020-11-09 17:40:04 +01:00
Nicholas Wiersma
83676577ac fix: use the import path for types
When running GTA, the type `path` was set to `rpath`. This equates to the package path (`github.com/traefik/yaegi`) in most cases. In the vendored case the `rpath` is the sub package path `something/vendor/github.com/traefik/yaegi` causing issues in typecheck and likely further down the line. By using the `importPath` it makes this consistent.

**Note:** I have no clue how to test this decently. I am open to options here.

Potentially Fixes #916
2020-11-05 13:42:03 +01:00
mpl
f0fc907269 extract: support building/running yaegi with Go devel
Fixes #928
2020-11-05 11:40:04 +01:00
Marc Vertes
61f4704925 interp: fix CFG in case of for loop with empty init and cond
Refactor `for` variants for clarity. Ensure all possible 8 combinations
are covered.

Fixes #942.
2020-11-05 11:00:04 +01:00
Marc Vertes
b1ccfbf47f interp: apply type conversion on untyped variable at run
Fixes #938.
2020-11-04 18:16:04 +01:00
Marc Vertes
0ed4b362dc interp: implement conversion for interpreter function types
Interpreter function types are represented internally by the AST node
of their definition. The conversion operation creates a new node with
the type field pointing to the target type.

Fixes #936.
2020-11-03 17:48:03 +01:00
Marc Vertes
98807387a4 interp: resolve type for untyped shift expressions
A non-constant shift expression can be untyped, requiring to apply a
type from inherited context. This change insures that such context is
propagated during CFG pre-order walk, to be used if necessary.
    
Fixes #927.
2020-11-02 18:08:04 +01:00
Marc Vertes
c817823ba1 interp: fix incorrect infinite loop on for statement
Add a for statement variant for the case of a "for" with an init, no
condition and no post-increment.

Fixes #933.
2020-11-02 17:52:03 +01:00
mpl
3cb8bca81a interp: on panic, look for node where offending exec originated from
The execution flow is such that a node can end up running several chained exec
funcs, some of which actually originate from other nodes. For example, in:

var m []int // L0
println("hello world") // L1
m[0] = 1 // L2

the offending code is on a node on line 2 (out of range error). However, since
the assignment to m is part of the execution flow of the variable m, we'll get
the panic when running all the chained exec funcs attached to the node for m on
line 0.

Which is why, when that happens, we need to look for the actual node (the one on
L2) where the offending instruction originates from, in order to
properly report the origin of the panic.

Fixes #546
2020-11-02 10:26:04 +01:00
Marc Vertes
a38d19288f interp: fix testing for nil interface values
Fixes #924.
2020-10-30 16:20:04 +01:00
Marc Vertes
7f8ffa6719 interp: handle explicit nil values in literal composite values
Fixes #922.
2020-10-27 11:24:04 +01:00
248 changed files with 782 additions and 328 deletions

15
_test/composite14.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
type T struct {
b []byte
}
func main() {
t := T{nil}
fmt.Println(t)
}
// Output:
// {[]}

21
_test/convert0.go Normal file
View File

@@ -0,0 +1,21 @@
package main
type T struct {
v int
}
type comparator func(T, T) bool
func sort(items []T, comp comparator) {
println("in sort")
}
func compT(t0, t1 T) bool { return t0.v < t1.v }
func main() {
a := []T{}
sort(a, comparator(compT))
}
// Output:
// in sort

17
_test/convert1.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "strconv"
type atoidef func(s string) (int, error)
func main() {
stdatoi := atoidef(strconv.Atoi)
n, err := stdatoi("7")
if err != nil {
panic(err)
}
println(n)
}
// Output:
// 7

19
_test/convert2.go Normal file
View File

@@ -0,0 +1,19 @@
package main
import "bufio"
func fakeSplitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
return 7, nil, nil
}
func main() {
splitfunc := bufio.SplitFunc(fakeSplitFunc)
n, _, err := splitfunc(nil, true)
if err != nil {
panic(err)
}
println(n)
}
// Output:
// 7

16
_test/for15.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func f() int { println("in f"); return 1 }
func main() {
for i := f(); ; {
println("in loop")
if i > 0 {
break
}
}
}
// Output:
// in f
// in loop

16
_test/for16.go Normal file
View File

@@ -0,0 +1,16 @@
package main
func main() {
max := 1
for ; ; max-- {
if max == 0 {
break
}
println("in for")
}
println("bye")
}
// Output:
// in for
// bye

17
_test/fun26.go Normal file
View File

@@ -0,0 +1,17 @@
package main
type F func() (int, error)
func f1() (int, error) { return 3, nil }
func f2(a string, f F) {
c, _ := f()
println(a, c)
}
func main() {
f2("hello", F(f1))
}
// Output:
// hello 3

12
_test/goto1.go Normal file
View File

@@ -0,0 +1,12 @@
package main
func main() {
if true {
goto here
}
here:
println("ok")
}
// Output:
// ok

28
_test/nil3.go Normal file
View File

@@ -0,0 +1,28 @@
package main
type I interface {
Hello()
}
type T struct {
h I
}
func (t *T) Hello() { println("Hello") }
func main() {
t := &T{}
println(t.h != nil)
println(t.h == nil)
t.h = t
println(t.h != nil)
println(t.h == nil)
t.h.Hello()
}
// Output:
// false
// true
// true
// false
// Hello

20
_test/time14.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import (
"fmt"
"time"
)
var t time.Time
func f() time.Time {
time := t
return time
}
func main() {
fmt.Println(f())
}
// Output:
// 0001-01-01 00:00:00 +0000 UTC

View File

@@ -0,0 +1,13 @@
package main
import (
"fmt"
"guthib.com/bat/baz"
)
func main() {
t := baz.NewT()
fmt.Printf("%s", t.A3)
}

View File

@@ -0,0 +1,22 @@
package baz
func NewT() *T {
return &T{
A1: make([]U, 0),
A3: "foobar",
}
}
type T struct {
A1 []U
A3 string
}
type U struct {
B1 V
B2 V
}
type V struct {
C1 string
}

View File

@@ -93,6 +93,12 @@ func TestPackages(t *testing.T) {
expected: "Yo hello",
evalFile: "./_pkg12/src/guthib.com/foo/main.go",
},
{
desc: "eval main with vendor",
goPath: "./_pkg13/",
expected: "foobar",
evalFile: "./_pkg13/src/guthib.com/foo/bar/main.go",
},
}
for _, test := range testCases {

View File

@@ -436,10 +436,12 @@ func GetMinor(part string) string {
return minor
}
const defaultMinorVersion = 15
func genBuildTags() (string, error) {
version := runtime.Version()
if version == "devel" {
return "", nil
if strings.HasPrefix(version, "devel") {
return "", fmt.Errorf("extracting only supported with stable releases of Go, not %v", version)
}
parts := strings.Split(version, ".")
@@ -452,6 +454,11 @@ func genBuildTags() (string, error) {
return "", fmt.Errorf("failed to parse version: %v", err)
}
// Only append an upper bound if we are not on the latest go
if minor >= defaultMinorVersion {
return currentGoVersion, nil
}
nextGoVersion := parts[0] + "." + strconv.Itoa(minor+1)
return currentGoVersion + ",!" + nextGoVersion, nil

View File

@@ -84,11 +84,12 @@ func main() {
oFile = strings.ReplaceAll(importPath, "/", "_") + ".go"
}
prefix := runtime.Version()
if runtime.Version() != "devel" {
parts := strings.Split(runtime.Version(), ".")
prefix = parts[0] + "_" + extract.GetMinor(parts[1])
version := runtime.Version()
if strings.HasPrefix(version, "devel") {
log.Fatalf("extracting only supported with stable releases of Go, not %v", version)
}
parts := strings.Split(version, ".")
prefix := parts[0] + "_" + extract.GetMinor(parts[1])
f, err := os.Create(prefix + "_" + oFile)
if err != nil {

View File

@@ -51,12 +51,14 @@ const (
fieldList
fileStmt
forStmt0 // for {}
forStmt1 // for cond {}
forStmt2 // for init; cond; {}
forStmt3 // for ; cond; post {}
forStmt3a // for init; ; post {}
forStmt4 // for init; cond; post {}
forRangeStmt // for range
forStmt1 // for init; ; {}
forStmt2 // for cond {}
forStmt3 // for init; cond; {}
forStmt4 // for ; ; post {}
forStmt5 // for ; cond; post {}
forStmt6 // for init; ; post {}
forStmt7 // for init; cond; post {}
forRangeStmt // for range {}
funcDecl
funcLit
funcType
@@ -134,8 +136,10 @@ var kinds = [...]string{
forStmt1: "forStmt1",
forStmt2: "forStmt2",
forStmt3: "forStmt3",
forStmt3a: "forStmt3a",
forStmt4: "forStmt4",
forStmt5: "forStmt5",
forStmt6: "forStmt6",
forStmt7: "forStmt7",
forRangeStmt: "forRangeStmt",
funcDecl: "funcDecl",
funcType: "funcType",
@@ -654,23 +658,23 @@ func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error
case *ast.ForStmt:
// Disambiguate variants of FOR statements with a node kind per variant
var kind nkind
if a.Cond == nil {
if a.Init != nil && a.Post != nil {
kind = forStmt3a
} else {
kind = forStmt0
}
} else {
switch {
case a.Init == nil && a.Post == nil:
kind = forStmt1
case a.Init != nil && a.Post == nil:
kind = forStmt2
case a.Init == nil && a.Post != nil:
kind = forStmt3
default:
kind = forStmt4
}
switch {
case a.Cond == nil && a.Init == nil && a.Post == nil:
kind = forStmt0
case a.Cond == nil && a.Init != nil && a.Post == nil:
kind = forStmt1
case a.Cond != nil && a.Init == nil && a.Post == nil:
kind = forStmt2
case a.Cond != nil && a.Init != nil && a.Post == nil:
kind = forStmt3
case a.Cond == nil && a.Init == nil && a.Post != nil:
kind = forStmt4
case a.Cond != nil && a.Init == nil && a.Post != nil:
kind = forStmt5
case a.Cond == nil && a.Init != nil && a.Post != nil:
kind = forStmt6
case a.Cond != nil && a.Init != nil && a.Post != nil:
kind = forStmt7
}
st.push(addChild(&root, anc, pos, kind, aNop), nod)

View File

@@ -66,6 +66,41 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
return false
}
switch n.kind {
case binaryExpr, unaryExpr, parenExpr:
if isBoolAction(n) {
break
}
// Gather assigned type if set, to give context for type propagation at post-order.
switch n.anc.kind {
case assignStmt, defineStmt:
a := n.anc
i := childPos(n) - a.nright
if len(a.child) > a.nright+a.nleft {
i--
}
dest := a.child[i]
if dest.typ != nil && !isInterface(dest.typ) {
// Interface type are not propagated, and will be resolved at post-order.
n.typ = dest.typ
}
case binaryExpr, unaryExpr, parenExpr:
n.typ = n.anc.typ
}
case defineStmt:
// Determine type of variables initialized at declaration, so it can be propagated.
if n.nleft+n.nright == len(n.child) {
// No type was specified on the left hand side, it will resolved at post-order.
break
}
n.typ, err = nodeType(interp, sc, n.child[n.nleft])
if err != nil {
break
}
for i := 0; i < n.nleft; i++ {
n.child[i].typ = n.typ
}
case blockStmt:
if n.anc != nil && n.anc.kind == rangeStmt {
// For range block: ensure that array or map type is propagated to iterators
@@ -159,7 +194,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
case breakStmt, continueStmt, gotoStmt:
if len(n.child) > 0 {
// Handle labeled statements
// Handle labeled statements.
label := n.child[0].ident
if sym, _, ok := sc.lookup(label); ok {
if sym.kind != labelSym {
@@ -176,25 +211,23 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
case labeledStmt:
label := n.child[0].ident
if sym, _, ok := sc.lookup(label); ok {
if sym.kind != labelSym {
err = n.child[0].cfgErrorf("label %s not defined", label)
break
}
// TODO(marc): labels must be stored outside of symbols to avoid collisions
// Used labels are searched in current and sub scopes, not upper ones.
if sym, ok := sc.lookdown(label); ok {
sym.node = n
n.sym = sym
} else {
n.sym = &symbol{kind: labelSym, node: n, index: -1}
sc.sym[label] = n.sym
}
sc.sym[label] = n.sym
case caseClause:
sc = sc.pushBloc()
if sn := n.anc.anc; sn.kind == typeSwitch && sn.child[1].action == aAssign {
// Type switch clause with a var defined in switch guard
// Type switch clause with a var defined in switch guard.
var typ *itype
if len(n.child) == 2 {
// 1 type in clause: define the var with this type in the case clause scope
// 1 type in clause: define the var with this type in the case clause scope.
switch {
case n.child[0].ident == nilIdent:
typ = sc.getType("interface{}")
@@ -204,7 +237,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
typ, err = nodeType(interp, sc, n.child[0])
}
} else {
// define the var with the type in the switch guard expression
// Define the var with the type in the switch guard expression.
typ = sn.child[1].child[1].child[0].typ
}
if err != nil {
@@ -285,11 +318,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
}
case forStmt0, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.child[0]
case forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.lastChild()
@@ -447,7 +476,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
var atyp *itype
if n.nleft+n.nright < len(n.child) {
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
return
break
}
}
@@ -644,7 +673,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
}
switch n.action {
case aRem, aShl, aShr:
case aRem:
n.typ = c0.typ
case aShl, aShr:
if c0.typ.untyped {
break
}
n.typ = c0.typ
case aEqual, aNotEqual:
n.typ = sc.getType("bool")
@@ -860,7 +894,12 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.gen = nop
n.findex = -1
n.typ = c0.typ
n.rval = c1.rval.Convert(c0.typ.rtype)
if c, ok := c1.rval.Interface().(constant.Value); ok {
i, _ := constant.Int64Val(constant.ToInt(c))
n.rval = reflect.ValueOf(i).Convert(c0.typ.rtype)
} else {
n.rval = c1.rval.Convert(c0.typ.rtype)
}
default:
n.gen = convert
n.typ = c0.typ
@@ -1005,7 +1044,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = n.start
sc = sc.pop()
case forStmt1: // for cond {}
case forStmt1: // for init; ; {}
init, body := n.child[0], n.child[1]
n.start = init.start
init.tnext = body.start
body.tnext = n.start
sc = sc.pop()
case forStmt2: // for cond {}
cond, body := n.child[0], n.child[1]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1024,7 +1070,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt2: // for init; cond; {}
case forStmt3: // for init; cond; {}
init, cond, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1046,7 +1092,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
setFNext(cond, n)
sc = sc.pop()
case forStmt3: // for ; cond; post {}
case forStmt4: // for ; ; post {}
post, body := n.child[0], n.child[1]
n.start = body.start
post.tnext = body.start
body.tnext = post.start
sc = sc.pop()
case forStmt5: // for ; cond; post {}
cond, post, body := n.child[0], n.child[1], n.child[2]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1066,7 +1119,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
body.tnext = post.start
sc = sc.pop()
case forStmt3a: // for init; ; post {}
case forStmt6: // for init; ; post {}
init, post, body := n.child[0], n.child[1], n.child[2]
n.start = init.start
init.tnext = body.start
@@ -1074,7 +1127,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
post.tnext = body.start
sc = sc.pop()
case forStmt4: // for init; cond; post {}
case forStmt7: // for init; cond; post {}
init, cond, post, body := n.child[0], n.child[1], n.child[2], n.child[3]
if !isBool(cond.typ) {
err = cond.cfgErrorf("non-bool used as for condition")
@@ -1326,7 +1379,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
n.val = sc.def
for i, c := range n.child {
var typ *itype
typ, err = nodeType(interp, sc, returnSig.child[1].fieldType(i))
typ, err = nodeType(interp, sc.upperLevel(), returnSig.child[1].fieldType(i))
if err != nil {
return
}
@@ -2278,7 +2331,7 @@ func isCall(n *node) bool {
}
func isBinCall(n *node) bool {
return n.kind == callExpr && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
}
func mustReturnValue(n *node) bool {
@@ -2294,7 +2347,7 @@ func mustReturnValue(n *node) bool {
}
func isRegularCall(n *node) bool {
return n.kind == callExpr && n.child[0].typ.cat == funcT
return isCall(n) && n.child[0].typ.cat == funcT
}
func variadicPos(n *node) int {
@@ -2467,3 +2520,12 @@ func isArithmeticAction(n *node) bool {
return false
}
}
func isBoolAction(n *node) bool {
switch n.action {
case aEqual, aGreater, aGreaterEqual, aLand, aLor, aLower, aLowerEqual, aNot, aNotEqual:
return true
default:
return false
}
}

View File

@@ -145,7 +145,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
elementType := sc.getType(typeName)
if elementType == nil {
// Add type if necessary, so method can be registered
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn.child[0], scope: sc}}
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn.child[0], scope: sc}}
elementType = sc.sym[typeName].typ
}
rcvrtype = &itype{cat: ptrT, val: elementType, incomplete: elementType.incomplete, node: rtn, scope: sc}
@@ -154,7 +154,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
rcvrtype = sc.getType(typeName)
if rcvrtype == nil {
// Add type if necessary, so method can be registered
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: rpath, incomplete: true, node: rtn, scope: sc}}
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, path: importPath, incomplete: true, node: rtn, scope: sc}}
rcvrtype = sc.sym[typeName].typ
}
}
@@ -254,12 +254,12 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
}
if n.child[1].kind == identExpr {
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: rpath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
n.typ = &itype{cat: aliasT, val: typ, name: typeName, path: importPath, field: typ.field, incomplete: typ.incomplete, scope: sc, node: n.child[0]}
copy(n.typ.method, typ.method)
} else {
n.typ = typ
n.typ.name = typeName
n.typ.path = rpath
n.typ.path = importPath
}
asImportName := filepath.Join(typeName, baseName)

View File

@@ -71,6 +71,27 @@ func TestEvalArithmetic(t *testing.T) {
})
}
func TestEvalShift(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{
{src: "a, b, m := uint32(1), uint32(2), uint32(0); m = a + (1 << b)", res: "5"},
{src: "c := uint(1); d := uint(+(-(1 << c)))", res: "18446744073709551614"},
{src: "e, f := uint32(0), uint32(0); f = 1 << -(e * 2)", res: "1"},
{src: "p := uint(0xdead); byte((1 << (p & 7)) - 1)", res: "31"},
{pre: func() { eval(t, i, "const k uint = 1 << 17") }, src: "int(k)", res: "131072"},
})
}
func TestOpVarConst(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{
{pre: func() { eval(t, i, "const a uint = 8 + 2") }, src: "a", res: "10"},
{src: "b := uint(5); a+b", res: "15"},
{src: "b := uint(5); b+a", res: "15"},
{src: "b := uint(5); b>a", res: "false"},
})
}
func TestEvalStar(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{

View File

@@ -108,10 +108,53 @@ func (interp *Interpreter) run(n *node, cf *frame) {
runCfg(n.start, f)
}
// originalExecNode looks in the tree of nodes for the node which has exec,
// aside from n, in order to know where n "inherited" that exec from.
func originalExecNode(n *node, exec bltn) *node {
execAddr := reflect.ValueOf(exec).Pointer()
var originalNode *node
seen := make(map[int64]struct{})
root := n
for {
root = root.anc
if root == nil {
break
}
if _, ok := seen[root.index]; ok {
continue
}
root.Walk(func(wn *node) bool {
if _, ok := seen[wn.index]; ok {
return true
}
seen[wn.index] = struct{}{}
if wn.index == n.index {
return true
}
if wn.exec == nil {
return true
}
if reflect.ValueOf(wn.exec).Pointer() == execAddr {
originalNode = wn
return false
}
return true
}, nil)
if originalNode != nil {
break
}
}
return originalNode
}
// Functions set to run during execution of CFG.
// runCfg executes a node AST by walking its CFG and running node builtin at each step.
func runCfg(n *node, f *frame) {
var exec bltn
defer func() {
f.mutex.Lock()
f.recovered = recover()
@@ -119,14 +162,18 @@ func runCfg(n *node, f *frame) {
val[0].Call(val[1:])
}
if f.recovered != nil {
fmt.Println(n.cfgErrorf("panic"))
oNode := originalExecNode(n, exec)
if oNode == nil {
oNode = n
}
fmt.Println(oNode.cfgErrorf("panic"))
f.mutex.Unlock()
panic(f.recovered)
}
f.mutex.Unlock()
}()
for exec := n.exec; exec != nil && f.runid() == n.interp.runid(); {
for exec = n.exec; exec != nil && f.runid() == n.interp.runid(); {
exec = exec(f)
}
}
@@ -343,10 +390,30 @@ func convert(n *node) {
return
}
if n.child[0].typ.cat == funcT && c.typ.cat == funcT {
value := genValue(c)
n.exec = func(f *frame) bltn {
n, ok := value(f).Interface().(*node)
if !ok || !n.typ.convertibleTo(c.typ) {
panic("cannot convert")
}
n1 := *n
n1.typ = c.typ
dest(f).Set(reflect.ValueOf(&n1))
return next
}
return
}
doConvert := true
var value func(*frame) reflect.Value
if c.typ.cat == funcT {
switch {
case c.typ.cat == funcT:
value = genFunctionWrapper(c)
} else {
case n.child[0].typ.cat == funcT && c.typ.cat == valueT:
doConvert = false
value = genValueNode(c)
default:
value = genValue(c)
}
@@ -367,7 +434,11 @@ func convert(n *node) {
}
n.exec = func(f *frame) bltn {
dest(f).Set(value(f).Convert(typ))
if doConvert {
dest(f).Set(value(f).Convert(typ))
} else {
dest(f).Set(value(f))
}
return next
}
}
@@ -1116,6 +1187,7 @@ func callBin(n *node) {
c.val = reflect.Zero(argType)
}
}
switch c.typ.cat {
case funcT:
values = append(values, genFunctionWrapper(c))
@@ -1128,6 +1200,14 @@ func callBin(n *node) {
default:
values = append(values, genInterfaceWrapper(c, defType))
}
case ptrT:
if c.typ.val.cat == valueT {
values = append(values, genValue(c))
} else {
values = append(values, genInterfaceWrapper(c, defType))
}
case valueT:
values = append(values, genValue(c))
default:
values = append(values, genInterfaceWrapper(c, defType))
}
@@ -1719,6 +1799,11 @@ func neg(n *node) {
dest(f).SetInt(-value(f).Int())
return next
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n.exec = func(f *frame) bltn {
dest(f).SetUint(-value(f).Uint())
return next
}
case reflect.Float32, reflect.Float64:
n.exec = func(f *frame) bltn {
dest(f).SetFloat(-value(f).Float())
@@ -2104,16 +2189,20 @@ func doComposite(n *node, hasType bool, keyed bool) {
val = c
fieldIndex = i
}
convertLiteralValue(val, typ.field[fieldIndex].typ.TypeOf())
ft := typ.field[fieldIndex].typ
rft := ft.TypeOf()
convertLiteralValue(val, rft)
switch {
case val.typ.cat == nilT:
values[fieldIndex] = func(*frame) reflect.Value { return reflect.New(rft).Elem() }
case val.typ.cat == funcT:
values[fieldIndex] = genFunctionWrapper(val)
case isArray(val.typ) && val.typ.val != nil && val.typ.val.cat == interfaceT:
values[fieldIndex] = genValueInterfaceArray(val)
case isRecursiveType(typ.field[fieldIndex].typ, typ.field[fieldIndex].typ.rtype):
values[fieldIndex] = genValueRecursiveInterface(val, typ.field[fieldIndex].typ.rtype)
case isInterface(typ.field[fieldIndex].typ):
values[fieldIndex] = genInterfaceWrapper(val, typ.field[fieldIndex].typ.rtype)
case isRecursiveType(ft, rft):
values[fieldIndex] = genValueRecursiveInterface(val, rft)
case isInterface(ft):
values[fieldIndex] = genInterfaceWrapper(val, rft)
default:
values[fieldIndex] = genValue(val)
}
@@ -3087,9 +3176,9 @@ func isNil(n *node) {
fnext := getExec(n.fnext)
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
vi := value(f).Interface().(valueInterface)
if (vi == valueInterface{} ||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
v := value(f)
vi, ok := v.Interface().(valueInterface)
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
dest(f).SetBool(true)
return tnext
}
@@ -3109,7 +3198,12 @@ func isNil(n *node) {
} else {
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
dest(f).SetBool(value(f).Interface().(valueInterface) == valueInterface{})
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT)
} else {
dest(f).SetBool(v.IsNil())
}
return tnext
}
} else {
@@ -3136,9 +3230,9 @@ func isNotNil(n *node) {
fnext := getExec(n.fnext)
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
vi := value(f).Interface().(valueInterface)
if (vi == valueInterface{} ||
vi.node.kind == basicLit && vi.node.typ.cat == nilT) {
v := value(f)
vi, ok := v.Interface().(valueInterface)
if ok && (vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT) || v.IsNil() {
dest(f).SetBool(false)
return fnext
}
@@ -3158,7 +3252,12 @@ func isNotNil(n *node) {
} else {
if c0.typ.cat == interfaceT {
n.exec = func(f *frame) bltn {
dest(f).SetBool(!(value(f).Interface().(valueInterface) == valueInterface{}))
v := value(f)
if vi, ok := v.Interface().(valueInterface); ok {
dest(f).SetBool(!(vi == valueInterface{} || vi.node.kind == basicLit && vi.node.typ.cat == nilT))
} else {
dest(f).SetBool(!v.IsNil())
}
return tnext
}
} else {

View File

@@ -72,26 +72,28 @@ type symbol struct {
// execution to the index in frame, created exactly from the types layout.
//
type scope struct {
anc *scope // Ancestor upper scope
anc *scope // ancestor upper scope
child []*scope // included scopes
def *node // function definition node this scope belongs to, or nil
loop *node // loop exit node for break statement
loopRestart *node // loop restart node for continue statement
pkgID string // unique id of package in which scope is defined
types []reflect.Type // Frame layout, may be shared by same level scopes
level int // Frame level: number of frame indirections to access var during execution
sym map[string]*symbol // Map of symbols defined in this current scope
types []reflect.Type // frame layout, may be shared by same level scopes
level int // frame level: number of frame indirections to access var during execution
sym map[string]*symbol // map of symbols defined in this current scope
global bool // true if scope refers to global space (single frame for universe and package level scopes)
iota int // iota value in this scope
}
// push creates a new scope and chain it to the current one.
// push creates a new child scope and chain it to the current one.
func (s *scope) push(indirect bool) *scope {
sc := scope{anc: s, level: s.level, sym: map[string]*symbol{}}
sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}}
s.child = append(s.child, sc)
if indirect {
sc.types = []reflect.Type{}
sc.level = s.level + 1
} else {
// propagate size, types, def and global as scopes at same level share the same frame
// Propagate size, types, def and global as scopes at same level share the same frame.
sc.types = s.types
sc.def = s.def
sc.global = s.global
@@ -99,7 +101,7 @@ func (s *scope) push(indirect bool) *scope {
}
// inherit loop state and pkgID from ancestor
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
return &sc
return sc
}
func (s *scope) pushBloc() *scope { return s.push(false) }
@@ -107,12 +109,20 @@ func (s *scope) pushFunc() *scope { return s.push(true) }
func (s *scope) pop() *scope {
if s.level == s.anc.level {
// propagate size and types, as scopes at same level share the same frame
// Propagate size and types, as scopes at same level share the same frame.
s.anc.types = s.types
}
return s.anc
}
func (s *scope) upperLevel() *scope {
level := s.level
for s != nil && s.level == level {
s = s.anc
}
return s
}
// lookup searches for a symbol in the current scope, and upper ones if not found
// it returns the symbol, the number of indirections level from the current scope
// and status (false if no result).
@@ -130,6 +140,20 @@ func (s *scope) lookup(ident string) (*symbol, int, bool) {
return nil, 0, false
}
// lookdown searches for a symbol in the current scope and included ones, recursively.
// It returns the first found symbol and true, or nil and false.
func (s *scope) lookdown(ident string) (*symbol, bool) {
if sym, ok := s.sym[ident]; ok {
return sym, true
}
for _, c := range s.child {
if sym, ok := c.lookdown(ident); ok {
return sym, true
}
}
return nil, false
}
func (s *scope) rangeChanType(n *node) *itype {
if sym, _, found := s.lookup(n.child[1].ident); found {
if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {

View File

@@ -217,6 +217,7 @@ var binaryOpPredicates = opPredicates{
// binaryExpr type checks a binary expression.
func (check typecheck) binaryExpr(n *node) error {
c0, c1 := n.child[0], n.child[1]
a := n.action
if isAssignAction(a) {
a--
@@ -226,6 +227,21 @@ func (check typecheck) binaryExpr(n *node) error {
return check.shift(n)
}
switch n.action {
case aRem:
if zeroConst(c1) {
return n.cfgErrorf("invalid operation: division by zero")
}
case aQuo:
if zeroConst(c1) {
return n.cfgErrorf("invalid operation: division by zero")
}
if c0.rval.IsValid() && c1.rval.IsValid() {
// Avoid constant conversions below to ensure correct constant integer quotient.
return nil
}
}
_ = check.convertUntyped(c0, c1.typ)
_ = check.convertUntyped(c1, c0.typ)
@@ -241,16 +257,13 @@ func (check typecheck) binaryExpr(n *node) error {
if err := check.op(binaryOpPredicates, a, n, c0, t0); err != nil {
return err
}
switch n.action {
case aQuo, aRem:
if (c0.typ.untyped || isInt(t0)) && c1.typ.untyped && constant.Sign(c1.rval.Interface().(constant.Value)) == 0 {
return n.cfgErrorf("invalid operation: division by zero")
}
}
return nil
}
func zeroConst(n *node) bool {
return n.typ.untyped && constant.Sign(n.rval.Interface().(constant.Value)) == 0
}
func (check typecheck) index(n *node, max int) error {
if err := check.convertUntyped(n, &itype{cat: intT, name: "int"}); err != nil {
return err
@@ -621,16 +634,13 @@ func (check typecheck) conversion(n *node, typ *itype) error {
if !ok {
return n.cfgErrorf("cannot convert expression of type %s to type %s", n.typ.id(), typ.id())
}
if n.typ.untyped {
if isInterface(typ) || c != nil && !isConstType(typ) {
typ = n.typ.defaultType()
}
if err := check.convertUntyped(n, typ); err != nil {
return err
}
if !n.typ.untyped || c == nil {
return nil
}
return nil
if isInterface(typ) || !isConstType(typ) {
typ = n.typ.defaultType()
}
return check.convertUntyped(n, typ)
}
type param struct {

View File

@@ -342,6 +342,10 @@ func vInt(v reflect.Value) (i int64) {
}
func vUint(v reflect.Value) (i uint64) {
if c := vConstantValue(v); c != nil {
i, _ = constant.Uint64Val(constant.ToInt(c))
return i
}
switch v.Type().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i = uint64(v.Int())

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract archive/tar'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract archive/zip'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract bufio'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract bytes'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/bzip2'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/flate'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/gzip'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/lzw'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract compress/zlib'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/heap'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/list'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract container/ring'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract context'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/aes'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/cipher'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/des'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/dsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/ecdsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/ed25519'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/elliptic'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/hmac'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/md5'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rand'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rc4'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/rsa'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha1'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha256'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/sha512'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/subtle'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/tls'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/x509'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract crypto/x509/pkix'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract database/sql'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract database/sql/driver'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/dwarf'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/elf'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/gosym'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/macho'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/pe'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract debug/plan9obj'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/ascii85'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/asn1'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/base32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/base64'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/binary'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/csv'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/gob'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/hex'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/json'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/pem'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract encoding/xml'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract errors'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract expvar'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract flag'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract fmt'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/ast'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/build'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/constant'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/doc'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/format'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/importer'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/parser'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/printer'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/scanner'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/token'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract go/types'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/adler32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/crc32'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/crc64'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/fnv'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract hash/maphash'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract html'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract html/template'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

View File

@@ -1,6 +1,6 @@
// Code generated by 'yaegi extract image'. DO NOT EDIT.
// +build go1.15,!go1.16
// +build go1.15
package stdlib

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