Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f76db27c77 | ||
|
|
996b1e33c8 | ||
|
|
236a0effaf | ||
|
|
eaeb445e17 | ||
|
|
6933ba2b4e | ||
|
|
a61a7d5bcd | ||
|
|
259f64cfd4 | ||
|
|
6c74ab7bec |
22
_test/issue-1404.go
Normal file
22
_test/issue-1404.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
type I interface {
|
||||
inI()
|
||||
}
|
||||
|
||||
type T struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (t *T) inI() {}
|
||||
|
||||
func main() {
|
||||
var i I = &T{name: "foo"}
|
||||
|
||||
if i, ok := i.(*T); ok {
|
||||
println(i.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
16
_test/issue-1408.go
Normal file
16
_test/issue-1408.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
type (
|
||||
Number = int32
|
||||
Number2 = Number
|
||||
)
|
||||
|
||||
func f(n Number2) { println(n) }
|
||||
|
||||
func main() {
|
||||
var n Number = 5
|
||||
f(n)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
16
_test/issue-1411.go
Normal file
16
_test/issue-1411.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
type Number int32
|
||||
|
||||
func (n Number) IsValid() bool { return true }
|
||||
|
||||
type Number1 = Number
|
||||
|
||||
type Number2 = Number1
|
||||
|
||||
func main() {
|
||||
a := Number2(5)
|
||||
println(a.IsValid())
|
||||
}
|
||||
|
||||
// Output: true
|
||||
25
_test/issue-435.go
Normal file
25
_test/issue-435.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Foo int
|
||||
|
||||
func (f Foo) String() string {
|
||||
return "foo-" + strconv.Itoa(int(f))
|
||||
}
|
||||
|
||||
func print1(arg interface{}) {
|
||||
fmt.Println(arg)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var arg Foo = 3
|
||||
var f = print1
|
||||
f(arg)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo-3
|
||||
@@ -1324,7 +1324,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
|
||||
// retry with the filename, in case ident is a package name.
|
||||
sym, level, found = sc.lookup(filepath.Join(n.ident, baseName))
|
||||
if !found {
|
||||
err = n.cfgErrorf("undefined: %s %d", n.ident, n.index)
|
||||
err = n.cfgErrorf("undefined: %s", n.ident)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -2135,7 +2135,7 @@ func compDefineX(sc *scope, n *node) error {
|
||||
for i, t := range types {
|
||||
var index int
|
||||
id := n.child[i].ident
|
||||
if sym, level, ok := sc.lookup(id); ok && level == n.child[i].level && sym.kind == varSym && sym.typ.equals(t) {
|
||||
if sym, level, ok := sc.lookup(id); ok && level == n.child[i].level && sym.kind == varSym && sym.typ.id() == t.id() {
|
||||
// Reuse symbol in case of a variable redeclaration with the same type.
|
||||
index = sym.index
|
||||
} else {
|
||||
@@ -2700,11 +2700,7 @@ func compositeGenerator(n *node, typ *itype, rtyp reflect.Type) (gen bltnGenerat
|
||||
}
|
||||
case valueT:
|
||||
if rtyp == nil {
|
||||
rtyp = n.typ.rtype
|
||||
}
|
||||
// TODO(mpl): I do not understand where this side-effect is coming from, and why it happens. quickfix for now.
|
||||
if rtyp == nil {
|
||||
rtyp = n.typ.val.rtype
|
||||
rtyp = n.typ.TypeOf()
|
||||
}
|
||||
switch k := rtyp.Kind(); k {
|
||||
case reflect.Struct:
|
||||
|
||||
@@ -204,11 +204,12 @@ type Interpreter struct {
|
||||
|
||||
name string // name of the input source file (or main)
|
||||
|
||||
opt // user settable options
|
||||
cancelChan bool // enables cancellable chan operations
|
||||
fset *token.FileSet // fileset to locate node in source code
|
||||
binPkg Exports // binary packages used in interpreter, indexed by path
|
||||
rdir map[string]bool // for src import cycle detection
|
||||
opt // user settable options
|
||||
cancelChan bool // enables cancellable chan operations
|
||||
fset *token.FileSet // fileset to locate node in source code
|
||||
binPkg Exports // binary packages used in interpreter, indexed by path
|
||||
rdir map[string]bool // for src import cycle detection
|
||||
mapTypes map[reflect.Value][]reflect.Type // special interfaces mapping for wrappers
|
||||
|
||||
mutex sync.RWMutex
|
||||
frame *frame // program data storage during execution
|
||||
@@ -333,6 +334,7 @@ func New(options Options) *Interpreter {
|
||||
universe: initUniverse(),
|
||||
scopes: map[string]*scope{},
|
||||
binPkg: Exports{"": map[string]reflect.Value{"_error": reflect.ValueOf((*_error)(nil))}},
|
||||
mapTypes: map[reflect.Value][]reflect.Type{},
|
||||
srcPkg: imports{},
|
||||
pkgNames: map[string]string{},
|
||||
rdir: map[string]bool{},
|
||||
@@ -675,6 +677,14 @@ func (interp *Interpreter) Use(values Exports) error {
|
||||
importPath := path.Dir(k)
|
||||
packageName := path.Base(k)
|
||||
|
||||
if k == "." && v["MapTypes"].IsValid() {
|
||||
// Use mapping for special interface wrappers.
|
||||
for kk, vv := range v["MapTypes"].Interface().(map[reflect.Value][]reflect.Type) {
|
||||
interp.mapTypes[kk] = vv
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if importPath == "." {
|
||||
return fmt.Errorf("export path %[1]q is missing a package name; did you mean '%[1]s/%[1]s'?", k)
|
||||
}
|
||||
@@ -726,6 +736,14 @@ func fixStdlib(interp *Interpreter) {
|
||||
p["Scanf"] = reflect.ValueOf(func(f string, a ...interface{}) (n int, err error) { return fmt.Fscanf(stdin, f, a...) })
|
||||
p["Scanln"] = reflect.ValueOf(func(a ...interface{}) (n int, err error) { return fmt.Fscanln(stdin, a...) })
|
||||
|
||||
// Update mapTypes to virtualized symbols as well.
|
||||
interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(fmt.Print)]
|
||||
interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(fmt.Printf)]
|
||||
interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(fmt.Println)]
|
||||
interp.mapTypes[p["Scan"]] = interp.mapTypes[reflect.ValueOf(fmt.Scan)]
|
||||
interp.mapTypes[p["Scanf"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanf)]
|
||||
interp.mapTypes[p["Scanln"]] = interp.mapTypes[reflect.ValueOf(fmt.Scanln)]
|
||||
|
||||
if p = interp.binPkg["flag"]; p != nil {
|
||||
c := flag.NewFlagSet(os.Args[0], flag.PanicOnError)
|
||||
c.SetOutput(stderr)
|
||||
@@ -752,6 +770,14 @@ func fixStdlib(interp *Interpreter) {
|
||||
p["SetOutput"] = reflect.ValueOf(l.SetOutput)
|
||||
p["SetPrefix"] = reflect.ValueOf(l.SetPrefix)
|
||||
p["Writer"] = reflect.ValueOf(l.Writer)
|
||||
|
||||
// Update mapTypes to virtualized symbols as well.
|
||||
interp.mapTypes[p["Print"]] = interp.mapTypes[reflect.ValueOf(log.Print)]
|
||||
interp.mapTypes[p["Printf"]] = interp.mapTypes[reflect.ValueOf(log.Printf)]
|
||||
interp.mapTypes[p["Println"]] = interp.mapTypes[reflect.ValueOf(log.Println)]
|
||||
interp.mapTypes[p["Panic"]] = interp.mapTypes[reflect.ValueOf(log.Panic)]
|
||||
interp.mapTypes[p["Panicf"]] = interp.mapTypes[reflect.ValueOf(log.Panicf)]
|
||||
interp.mapTypes[p["Panicln"]] = interp.mapTypes[reflect.ValueOf(log.Panicln)]
|
||||
}
|
||||
|
||||
if p = interp.binPkg["os"]; p != nil {
|
||||
|
||||
@@ -176,7 +176,7 @@ func TestEvalBuiltin(t *testing.T) {
|
||||
{src: `m := complex(3, 2); real(m)`, res: "3"},
|
||||
{src: `m := complex(3, 2); imag(m)`, res: "2"},
|
||||
{src: `m := complex("test", 2)`, err: "1:33: invalid types string and int"},
|
||||
{src: `imag("test")`, err: "1:33: cannot convert \"test\" to complex128"},
|
||||
{src: `imag("test")`, err: "1:33: cannot convert untyped string to untyped complex"},
|
||||
{src: `imag(a)`, err: "1:33: invalid argument type []int for imag"},
|
||||
{src: `real(a)`, err: "1:33: invalid argument type []int for real"},
|
||||
{src: `t := map[int]int{}; t[123]++; t`, res: "map[123:1]"},
|
||||
@@ -184,6 +184,9 @@ func TestEvalBuiltin(t *testing.T) {
|
||||
{src: `t := map[int]int{}; t[123] += 1; t`, res: "map[123:1]"},
|
||||
{src: `t := map[int]int{}; t[123] -= 1; t`, res: "map[123:-1]"},
|
||||
{src: `println("hello", _)`, err: "1:28: cannot use _ as value"},
|
||||
{src: `f := func() complex64 { return complex(0, 0) }()`, res: "(0+0i)"},
|
||||
{src: `f := func() float32 { return real(complex(2, 1)) }()`, res: "2"},
|
||||
{src: `f := func() int8 { return imag(complex(2, 1)) }()`, res: "1"},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -437,7 +440,7 @@ func TestEvalComparison(t *testing.T) {
|
||||
{src: `a, b, c := 1, 1, false; if a == b { c = true }; c`, res: "true"},
|
||||
{src: `a, b, c := 1, 2, false; if a != b { c = true }; c`, res: "true"},
|
||||
{
|
||||
desc: "mismatched types",
|
||||
desc: "mismatched types equality",
|
||||
src: `
|
||||
type Foo string
|
||||
type Bar string
|
||||
@@ -448,6 +451,18 @@ func TestEvalComparison(t *testing.T) {
|
||||
`,
|
||||
err: "7:13: invalid operation: mismatched types main.Foo and main.Bar",
|
||||
},
|
||||
{
|
||||
desc: "mismatched types less than",
|
||||
src: `
|
||||
type Foo string
|
||||
type Bar string
|
||||
|
||||
var a = Foo("test")
|
||||
var b = Bar("test")
|
||||
var c = a < b
|
||||
`,
|
||||
err: "7:13: invalid operation: mismatched types main.Foo and main.Bar",
|
||||
},
|
||||
{src: `1 > _`, err: "1:28: cannot use _ as value"},
|
||||
{src: `(_) > 1`, err: "1:28: cannot use _ as value"},
|
||||
{src: `v := interface{}(2); v == 2`, res: "true"},
|
||||
@@ -706,6 +721,29 @@ func TestEvalBinCall(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalReflect(t *testing.T) {
|
||||
i := interp.New(interp.Options{})
|
||||
if err := i.Use(stdlib.Symbols); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := i.Eval(`
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Encoder interface {
|
||||
EncodeValues(key string, v *url.Values) error
|
||||
}
|
||||
`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
runTests(t, i, []testCase{
|
||||
{src: "reflect.TypeOf(new(Encoder)).Elem()", res: "interp.valueInterface"},
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvalMissingSymbol(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
@@ -1372,7 +1410,7 @@ func testConcurrentComposite(t *testing.T, filePath string) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalScanner(t *testing.T) {
|
||||
func TestEvalREPL(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
@@ -1460,6 +1498,13 @@ func TestEvalScanner(t *testing.T) {
|
||||
},
|
||||
errorLine: -1,
|
||||
},
|
||||
{
|
||||
desc: "define a label",
|
||||
src: []string{
|
||||
`a:`,
|
||||
},
|
||||
errorLine: -1,
|
||||
},
|
||||
}
|
||||
|
||||
runREPL := func(t *testing.T, test testCase) {
|
||||
|
||||
@@ -1479,6 +1479,20 @@ func callBin(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
// getMapType returns a reflect type suitable for interface wrapper for functions
|
||||
// with some special processing in case of interface{} argument, i.e. fmt.Printf.
|
||||
var getMapType func(*itype) reflect.Type
|
||||
if lr, ok := n.interp.mapTypes[c0.rval]; ok {
|
||||
getMapType = func(typ *itype) reflect.Type {
|
||||
for _, rt := range lr {
|
||||
if typ.implements(&itype{cat: valueT, rtype: rt}) {
|
||||
return rt
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if we should use `Call` or `CallSlice` on the function Value.
|
||||
callFn := func(v reflect.Value, in []reflect.Value) []reflect.Value { return v.Call(in) }
|
||||
if n.action == aCallSlice {
|
||||
@@ -1486,13 +1500,6 @@ func callBin(n *node) {
|
||||
}
|
||||
|
||||
for i, c := range child {
|
||||
var defType reflect.Type
|
||||
if variadic >= 0 && i+rcvrOffset >= variadic {
|
||||
defType = funcType.In(variadic)
|
||||
} else {
|
||||
defType = funcType.In(rcvrOffset + i)
|
||||
}
|
||||
|
||||
switch {
|
||||
case isBinCall(c, c.scope):
|
||||
// Handle nested function calls: pass returned values as arguments
|
||||
@@ -1527,6 +1534,19 @@ func callBin(n *node) {
|
||||
break
|
||||
}
|
||||
|
||||
// defType is the target type for a potential interface wrapper.
|
||||
var defType reflect.Type
|
||||
if variadic >= 0 && i+rcvrOffset >= variadic {
|
||||
defType = funcType.In(variadic)
|
||||
} else {
|
||||
defType = funcType.In(rcvrOffset + i)
|
||||
}
|
||||
if getMapType != nil {
|
||||
if rt := getMapType(c.typ); rt != nil {
|
||||
defType = rt
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case isFuncSrc(c.typ):
|
||||
values = append(values, genFunctionWrapper(c))
|
||||
@@ -1565,7 +1585,7 @@ func callBin(n *node) {
|
||||
val := make([]reflect.Value, l+1)
|
||||
val[0] = value(f)
|
||||
for i, v := range values {
|
||||
val[i+1] = v(f)
|
||||
val[i+1] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
f.deferred = append([][]reflect.Value{val}, f.deferred...)
|
||||
return tnext
|
||||
@@ -1575,7 +1595,7 @@ func callBin(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
in[i] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
go callFn(value(f), in)
|
||||
return tnext
|
||||
@@ -1587,7 +1607,7 @@ func callBin(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
in[i] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
res := callFn(value(f), in)
|
||||
b := res[0].Bool()
|
||||
@@ -1619,7 +1639,7 @@ func callBin(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
in[i] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
out := callFn(value(f), in)
|
||||
for i, v := range rvalues {
|
||||
@@ -1636,7 +1656,7 @@ func callBin(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
in[i] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
out := callFn(value(f), in)
|
||||
for i, v := range out {
|
||||
@@ -1652,7 +1672,7 @@ func callBin(n *node) {
|
||||
n.exec = func(f *frame) bltn {
|
||||
in := make([]reflect.Value, l)
|
||||
for i, v := range values {
|
||||
in[i] = v(f)
|
||||
in[i] = getBinValue(getMapType, v, f)
|
||||
}
|
||||
out := callFn(value(f), in)
|
||||
for i := 0; i < len(out); i++ {
|
||||
@@ -3303,11 +3323,20 @@ func _len(n *node) {
|
||||
|
||||
func _new(n *node) {
|
||||
next := getExec(n.tnext)
|
||||
typ := n.child[1].typ.TypeOf()
|
||||
t1 := n.child[1].typ
|
||||
typ := t1.TypeOf()
|
||||
dest := genValueOutput(n, reflect.PtrTo(typ))
|
||||
|
||||
if isInterfaceSrc(t1) && (!isEmptyInterface(t1) || len(t1.method) > 0) {
|
||||
typ = zeroInterfaceValue().Type()
|
||||
}
|
||||
|
||||
n.exec = func(f *frame) bltn {
|
||||
dest(f).Set(reflect.New(typ))
|
||||
v := reflect.New(typ)
|
||||
if vi, ok := v.Interface().(*valueInterface); ok {
|
||||
vi.node = n
|
||||
}
|
||||
dest(f).Set(v)
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,9 +238,6 @@ func namedOf(val *itype, path, name string, opts ...itypeOption) *itype {
|
||||
if path != "" {
|
||||
str = path + "." + name
|
||||
}
|
||||
for val.cat == aliasT {
|
||||
val = val.val
|
||||
}
|
||||
t := &itype{cat: aliasT, val: val, path: path, name: name, str: str}
|
||||
for _, opt := range opts {
|
||||
opt(t)
|
||||
@@ -585,12 +582,12 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype,
|
||||
}
|
||||
if !t.incomplete {
|
||||
switch k := t.TypeOf().Kind(); {
|
||||
case t.untyped && isNumber(t.TypeOf()):
|
||||
t = untypedFloat()
|
||||
case k == reflect.Complex64:
|
||||
t = sc.getType("float32")
|
||||
case k == reflect.Complex128:
|
||||
t = sc.getType("float64")
|
||||
case t.untyped && isNumber(t.TypeOf()):
|
||||
t = valueTOf(floatType, withUntyped(true), withScope(sc))
|
||||
default:
|
||||
err = n.cfgErrorf("invalid complex type %s", k)
|
||||
}
|
||||
@@ -1125,6 +1122,24 @@ func (t *itype) concrete() *itype {
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *itype) underlying() *itype {
|
||||
if t.cat == aliasT {
|
||||
return t.val.underlying()
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// typeDefined returns true if type t1 is defined from type t2 or t2 from t1.
|
||||
func typeDefined(t1, t2 *itype) bool {
|
||||
if t1.cat == aliasT && t1.val == t2 {
|
||||
return true
|
||||
}
|
||||
if t2.cat == aliasT && t2.val == t1 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVariadic returns true if the function type is variadic.
|
||||
// If the type is not a function or is not variadic, it will
|
||||
// return false.
|
||||
@@ -1198,8 +1213,7 @@ func (t *itype) assignableTo(o *itype) bool {
|
||||
if t.equals(o) {
|
||||
return true
|
||||
}
|
||||
if t.cat == aliasT && o.cat == aliasT {
|
||||
// If alias types are not identical, it is not assignable.
|
||||
if t.cat == aliasT && o.cat == aliasT && (t.underlying().id() != o.underlying().id() || !typeDefined(t, o)) {
|
||||
return false
|
||||
}
|
||||
if t.isNil() && o.hasNil() || o.isNil() && t.hasNil() {
|
||||
@@ -1219,6 +1233,11 @@ func (t *itype) assignableTo(o *itype) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if t.untyped && isNumber(t.TypeOf()) && isNumber(o.TypeOf()) {
|
||||
// Assignability depends on constant numeric value (overflow check), to be tested elsewhere.
|
||||
return true
|
||||
}
|
||||
|
||||
n := t.node
|
||||
if n == nil || !n.rval.IsValid() {
|
||||
return false
|
||||
|
||||
@@ -184,23 +184,29 @@ func (check typecheck) shift(n *node) error {
|
||||
|
||||
// comparison type checks a comparison binary expression.
|
||||
func (check typecheck) comparison(n *node) error {
|
||||
c0, c1 := n.child[0], n.child[1]
|
||||
t0, t1 := n.child[0].typ, n.child[1].typ
|
||||
|
||||
if !c0.typ.assignableTo(c1.typ) && !c1.typ.assignableTo(c0.typ) {
|
||||
return n.cfgErrorf("invalid operation: mismatched types %s and %s", c0.typ.id(), c1.typ.id())
|
||||
if !t0.assignableTo(t1) && !t1.assignableTo(t0) {
|
||||
return n.cfgErrorf("invalid operation: mismatched types %s and %s", t0.id(), t1.id())
|
||||
}
|
||||
|
||||
ok := false
|
||||
|
||||
if !isInterface(t0) && !isInterface(t1) && !t0.isNil() && !t1.isNil() && t0.untyped == t1.untyped && t0.id() != t1.id() {
|
||||
// Non interface types must be really equals.
|
||||
return n.cfgErrorf("invalid operation: mismatched types %s and %s", t0.id(), t1.id())
|
||||
}
|
||||
|
||||
switch n.action {
|
||||
case aEqual, aNotEqual:
|
||||
ok = c0.typ.comparable() && c1.typ.comparable() || c0.typ.isNil() && c1.typ.hasNil() || c1.typ.isNil() && c0.typ.hasNil()
|
||||
ok = t0.comparable() && t1.comparable() || t0.isNil() && t1.hasNil() || t1.isNil() && t0.hasNil()
|
||||
case aLower, aLowerEqual, aGreater, aGreaterEqual:
|
||||
ok = c0.typ.ordered() && c1.typ.ordered()
|
||||
ok = t0.ordered() && t1.ordered()
|
||||
}
|
||||
if !ok {
|
||||
typ := c0.typ
|
||||
typ := t0
|
||||
if typ.isNil() {
|
||||
typ = c1.typ
|
||||
typ = t1
|
||||
}
|
||||
return n.cfgErrorf("invalid operation: operator %v not defined on %s", n.action, typ.id())
|
||||
}
|
||||
@@ -815,7 +821,7 @@ func (check typecheck) builtin(name string, n *node, child []*node, ellipsis boo
|
||||
case !typ0.untyped && typ1.untyped:
|
||||
err = check.convertUntyped(p1.nod, typ0)
|
||||
case typ0.untyped && typ1.untyped:
|
||||
fltType := check.scope.getType("float64")
|
||||
fltType := untypedFloat()
|
||||
err = check.convertUntyped(p0.nod, fltType)
|
||||
if err != nil {
|
||||
break
|
||||
@@ -838,7 +844,7 @@ func (check typecheck) builtin(name string, n *node, child []*node, ellipsis boo
|
||||
p := params[0]
|
||||
typ := p.Type()
|
||||
if typ.untyped {
|
||||
if err := check.convertUntyped(p.nod, check.scope.getType("complex128")); err != nil {
|
||||
if err := check.convertUntyped(p.nod, untypedComplex()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ func valueGenerator(n *node, i int) func(*frame) reflect.Value {
|
||||
// because a cancellation prior to any evaluation result may leave
|
||||
// the frame's data empty.
|
||||
func valueOf(data []reflect.Value, i int) reflect.Value {
|
||||
if i < len(data) {
|
||||
return data[i]
|
||||
if i < 0 || i >= len(data) {
|
||||
return reflect.Value{}
|
||||
}
|
||||
return reflect.Value{}
|
||||
return data[i]
|
||||
}
|
||||
|
||||
func genValueBinMethodOnInterface(n *node, defaultGen func(*frame) reflect.Value) func(*frame) reflect.Value {
|
||||
@@ -195,7 +195,7 @@ func genValue(n *node) func(*frame) reflect.Value {
|
||||
}
|
||||
if n.sym != nil {
|
||||
i := n.sym.index
|
||||
if i < 0 {
|
||||
if i < 0 && n != n.sym.node {
|
||||
return genValue(n.sym.node)
|
||||
}
|
||||
if n.sym.global {
|
||||
@@ -392,6 +392,21 @@ func genValueOutput(n *node, t reflect.Type) func(*frame) reflect.Value {
|
||||
return value
|
||||
}
|
||||
|
||||
func getBinValue(getMapType func(*itype) reflect.Type, value func(*frame) reflect.Value, f *frame) reflect.Value {
|
||||
v := value(f)
|
||||
if getMapType == nil {
|
||||
return v
|
||||
}
|
||||
val, ok := v.Interface().(valueInterface)
|
||||
if !ok || val.node == nil {
|
||||
return v
|
||||
}
|
||||
if rt := getMapType(val.node.typ); rt != nil {
|
||||
return genInterfaceWrapper(val.node, rt)(f)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func valueInterfaceValue(v reflect.Value) reflect.Value {
|
||||
for {
|
||||
vv, ok := v.Interface().(valueInterface)
|
||||
|
||||
58
stdlib/maptypes.go
Normal file
58
stdlib/maptypes.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
mt := []reflect.Type{
|
||||
reflect.TypeOf((*fmt.Formatter)(nil)).Elem(),
|
||||
reflect.TypeOf((*fmt.Stringer)(nil)).Elem(),
|
||||
}
|
||||
|
||||
MapTypes[reflect.ValueOf(fmt.Errorf)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Fprint)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Fprintf)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Fprintln)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Print)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Printf)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Println)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Sprint)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Sprintf)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Sprintln)] = mt
|
||||
|
||||
MapTypes[reflect.ValueOf(log.Fatal)] = mt
|
||||
MapTypes[reflect.ValueOf(log.Fatalf)] = mt
|
||||
MapTypes[reflect.ValueOf(log.Fatalln)] = mt
|
||||
MapTypes[reflect.ValueOf(log.Panic)] = mt
|
||||
MapTypes[reflect.ValueOf(log.Panicf)] = mt
|
||||
MapTypes[reflect.ValueOf(log.Panicln)] = mt
|
||||
|
||||
mt = []reflect.Type{reflect.TypeOf((*fmt.Scanner)(nil)).Elem()}
|
||||
|
||||
MapTypes[reflect.ValueOf(fmt.Scan)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Scanf)] = mt
|
||||
MapTypes[reflect.ValueOf(fmt.Scanln)] = mt
|
||||
|
||||
MapTypes[reflect.ValueOf(json.Marshal)] = []reflect.Type{
|
||||
reflect.TypeOf((*json.Marshaler)(nil)).Elem(),
|
||||
reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem(),
|
||||
}
|
||||
MapTypes[reflect.ValueOf(json.Unmarshal)] = []reflect.Type{
|
||||
reflect.TypeOf((*json.Unmarshaler)(nil)).Elem(),
|
||||
reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem(),
|
||||
}
|
||||
MapTypes[reflect.ValueOf(xml.Marshal)] = []reflect.Type{
|
||||
reflect.TypeOf((*xml.Marshaler)(nil)).Elem(),
|
||||
reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem(),
|
||||
}
|
||||
MapTypes[reflect.ValueOf(xml.Unmarshal)] = []reflect.Type{
|
||||
reflect.TypeOf((*xml.Unmarshaler)(nil)).Elem(),
|
||||
reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem(),
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,17 @@ import "reflect"
|
||||
// Symbols variable stores the map of stdlib symbols per package.
|
||||
var Symbols = map[string]map[string]reflect.Value{}
|
||||
|
||||
// MapTypes variable contains a map of functions which have an interface{} as parameter but
|
||||
// do something special if the parameter implements a given interface.
|
||||
var MapTypes = map[reflect.Value][]reflect.Type{}
|
||||
|
||||
func init() {
|
||||
Symbols["github.com/traefik/yaegi/stdlib"] = map[string]reflect.Value{
|
||||
Symbols["github.com/traefik/yaegi/stdlib/stdlib"] = map[string]reflect.Value{
|
||||
"Symbols": reflect.ValueOf(Symbols),
|
||||
}
|
||||
Symbols["."] = map[string]reflect.Value{
|
||||
"MapTypes": reflect.ValueOf(MapTypes),
|
||||
}
|
||||
}
|
||||
|
||||
// Provide access to go standard library (http://golang.org/pkg/)
|
||||
|
||||
Reference in New Issue
Block a user