1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00

Add ability to call struct methods

This fixes #60

This is incompatible with go 1.0.3
This commit is contained in:
Daniel Cannon 2014-03-15 17:51:22 +00:00 committed by Robert Krimen
parent 661a61c5a0
commit 07737f86b9
3 changed files with 91 additions and 5 deletions

View File

@ -14,6 +14,34 @@ type testStruct struct {
Jkl interface{}
}
func (t *testStruct) FuncPointerReciever() string {
return "abc"
}
func (t testStruct) FuncNoArgsNoRet() {
return
}
func (t testStruct) FuncNoArgs() string {
return "abc"
}
func (t testStruct) FuncNoArgsMultRet() (string, error) {
return "def", nil
}
func (t testStruct) FuncOneArgs(a string) string {
return a
}
func (t testStruct) FuncMultArgs(a, b string) string {
return a + b
}
func (t testStruct) FuncVarArgs(as ...string) int {
return len(as)
}
func TestReflect(t *testing.T) {
Terst(t)
@ -35,6 +63,10 @@ func Test_reflectStruct(t *testing.T) {
abc := &testStruct{}
failSet("abc", abc)
test(`
abc.FuncPointerReciever();
`, "abc")
test(`
[ abc.Abc, abc.Ghi ];
`, "false,")
@ -78,6 +110,26 @@ func Test_reflectStruct(t *testing.T) {
[ abc.Def, abc.abc ];
`, "451,")
Is(abc.Def, 451)
test(`
abc.FuncNoArgsNoRet();
`, "undefined")
test(`
abc.FuncNoArgs();
`, "abc")
test(`
abc.FuncOneArgs("abc");
`, "abc")
test(`
abc.FuncMultArgs("abc", "def");
`, "abcdef")
test(`
abc.FuncVarArgs("abc", "def", "ghi");
`, "3")
test(`raise:
abc.FuncNoArgsMultRet();
`, "TypeError")
}
}

View File

@ -322,6 +322,21 @@ func (self *_runtime) toValue(value interface{}) Value {
case reflect.Array:
return toValue_object(self.newGoArray(value))
}
case reflect.Func:
return toValue_object(self.newNativeFunction(func(call FunctionCall) Value {
args := make([]reflect.Value, len(call.ArgumentList))
for i, a := range call.ArgumentList {
args[i] = reflect.ValueOf(a.export())
}
retvals := value.Call(args)
if len(retvals) > 1 {
panic(newTypeError())
} else if len(retvals) == 1 {
return toValue(retvals[0].Interface())
}
return UndefinedValue()
}))
case reflect.Struct:
return toValue_object(self.newGoStructObject(value))
case reflect.Map:

View File

@ -27,13 +27,25 @@ func _newGoStructObject(value reflect.Value) *_goStructObject {
}
func (self _goStructObject) getValue(name string) reflect.Value {
return reflect.Indirect(self.value).FieldByName(name)
if field := reflect.Indirect(self.value).FieldByName(name); (field != reflect.Value{}) {
return field
}
if method := self.value.MethodByName(name); (method != reflect.Value{}) {
return method
}
return reflect.Value{}
}
func (self _goStructObject) field(name string) (reflect.StructField, bool) {
return reflect.Indirect(self.value).Type().FieldByName(name)
}
func (self _goStructObject) method(name string) (reflect.Method, bool) {
return reflect.Indirect(self.value).Type().MethodByName(name)
}
func (self _goStructObject) setValue(name string, value Value) bool {
field, exists := self.field(name)
if !exists {
@ -60,10 +72,17 @@ func goStructGetOwnProperty(self *_object, name string) *_property {
func goStructEnumerate(self *_object, all bool, each func(string) bool) {
object := self.value.(*_goStructObject)
count := object.value.NumField()
type_ := object.value.Type()
for index := 0; index < count; index++ {
if !each(type_.Field(index).Name) {
// Enumerate fields
for index := 0; index < reflect.Indirect(object.value).NumField(); index++ {
if !each(reflect.Indirect(object.value).Type().Field(index).Name) {
return
}
}
// Enumerate methods
for index := 0; index < object.value.NumMethod(); index++ {
if !each(object.value.Type().Method(index).Name) {
return
}
}