1// +build js
2// +build go1.11.1
3
4package reflect
5
6import (
7	"unsafe"
8
9	"github.com/gopherjs/gopherjs/js"
10)
11
12func methodReceiver(op string, v Value, i int) (_ *rtype, t *funcType, fn unsafe.Pointer) {
13	var prop string
14	if v.typ.Kind() == Interface {
15		tt := (*interfaceType)(unsafe.Pointer(v.typ))
16		if i < 0 || i >= len(tt.methods) {
17			panic("reflect: internal error: invalid method index")
18		}
19		m := &tt.methods[i]
20		if !tt.nameOff(m.name).isExported() {
21			panic("reflect: " + op + " of unexported method")
22		}
23		t = (*funcType)(unsafe.Pointer(tt.typeOff(m.typ)))
24		prop = tt.nameOff(m.name).name()
25	} else {
26		ms := v.typ.exportedMethods()
27		if uint(i) >= uint(len(ms)) {
28			panic("reflect: internal error: invalid method index")
29		}
30		m := ms[i]
31		if !v.typ.nameOff(m.name).isExported() {
32			panic("reflect: " + op + " of unexported method")
33		}
34		t = (*funcType)(unsafe.Pointer(v.typ.typeOff(m.mtyp)))
35		prop = js.Global.Call("$methodSet", jsType(v.typ)).Index(i).Get("prop").String()
36	}
37	rcvr := v.object()
38	if isWrapped(v.typ) {
39		rcvr = jsType(v.typ).New(rcvr)
40	}
41	fn = unsafe.Pointer(rcvr.Get(prop).Unsafe())
42	return
43}
44
45func (v Value) call(op string, in []Value) []Value {
46	var (
47		t    *funcType
48		fn   unsafe.Pointer
49		rcvr *js.Object
50	)
51	if v.flag&flagMethod != 0 {
52		_, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
53		rcvr = v.object()
54		if isWrapped(v.typ) {
55			rcvr = jsType(v.typ).New(rcvr)
56		}
57	} else {
58		t = (*funcType)(unsafe.Pointer(v.typ))
59		fn = unsafe.Pointer(v.object().Unsafe())
60		rcvr = js.Undefined
61	}
62
63	if fn == nil {
64		panic("reflect.Value.Call: call of nil function")
65	}
66
67	isSlice := op == "CallSlice"
68	n := t.NumIn()
69	if isSlice {
70		if !t.IsVariadic() {
71			panic("reflect: CallSlice of non-variadic function")
72		}
73		if len(in) < n {
74			panic("reflect: CallSlice with too few input arguments")
75		}
76		if len(in) > n {
77			panic("reflect: CallSlice with too many input arguments")
78		}
79	} else {
80		if t.IsVariadic() {
81			n--
82		}
83		if len(in) < n {
84			panic("reflect: Call with too few input arguments")
85		}
86		if !t.IsVariadic() && len(in) > n {
87			panic("reflect: Call with too many input arguments")
88		}
89	}
90	for _, x := range in {
91		if x.Kind() == Invalid {
92			panic("reflect: " + op + " using zero Value argument")
93		}
94	}
95	for i := 0; i < n; i++ {
96		if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
97			panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
98		}
99	}
100	if !isSlice && t.IsVariadic() {
101		// prepare slice for remaining values
102		m := len(in) - n
103		slice := MakeSlice(t.In(n), m, m)
104		elem := t.In(n).Elem()
105		for i := 0; i < m; i++ {
106			x := in[n+i]
107			if xt := x.Type(); !xt.AssignableTo(elem) {
108				panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
109			}
110			slice.Index(i).Set(x)
111		}
112		origIn := in
113		in = make([]Value, n+1)
114		copy(in[:n], origIn)
115		in[n] = slice
116	}
117
118	nin := len(in)
119	if nin != t.NumIn() {
120		panic("reflect.Value.Call: wrong argument count")
121	}
122	nout := t.NumOut()
123
124	argsArray := js.Global.Get("Array").New(t.NumIn())
125	for i, arg := range in {
126		argsArray.SetIndex(i, unwrapJsObject(t.In(i), arg.assignTo("reflect.Value.Call", t.In(i).common(), nil).object()))
127	}
128	results := callHelper(js.InternalObject(fn), rcvr, argsArray)
129
130	switch nout {
131	case 0:
132		return nil
133	case 1:
134		return []Value{makeValue(t.Out(0), wrapJsObject(t.Out(0), results), 0)}
135	default:
136		ret := make([]Value, nout)
137		for i := range ret {
138			ret[i] = makeValue(t.Out(i), wrapJsObject(t.Out(i), results.Index(i)), 0)
139		}
140		return ret
141	}
142}
143