Repository: robertkrimen/otto (go)

Issue:
panic - Mixed type array gives panic on export
```Go
package main

import (
	"fmt"
	"github.com/robertkrimen/otto"
)

func main() {

	vm := otto.New()

	_, err := vm.Run(`
var output = [[1,2.1], [3, 4]];
	`)

	if err != nil {
		fmt.Println(err)
		return
	}

	outputValue, err := vm.Get("output")
	if err != nil {
		fmt.Println(err)
		return
	}

	outputInterface, _ := outputValue.Export()

	fmt.Println(outputInterface)
}
```

Panic:

> panic: reflect.Set: value of type []interface {} is not assignable to type []int64
> 
> goroutine 1 [running]:
> reflect.Value.assignTo(0x671a80, 0xc0420fd8c0, 0x97, 0x6bedd6, 0xb, 0x671a00, 0x0, 0x0, 0x671a80, 0xc0420fd8c0)
> 	C:/app/Go/src/reflect/value.go:2181 +0x30e
> reflect.Value.Set(0x671a00, 0xc0420efda0, 0x197, 0x671a80, 0xc0420fd8c0, 0x97)
> 	C:/app/Go/src/reflect/value.go:1351 +0xab
> vendor/github.com/robertkrimen/otto.Value.export(0x5, 0x6b4020, 0xc0420f9aa0, 0x0, 0x0)
> 	C:/Users/username/Documents/Eclipse/src/vendor/github.com/robertkrimen/otto/value.go:718 +0xe9f
> vendor/github.com/robertkrimen/otto.Value.Export(0x5, 0x6b4020, 0xc0420f9aa0, 0x0, 0x0, 0x0, 0x0)
> 	C:/Users/username/Documents/Eclipse/src/vendor/github.com/robertkrimen/otto/value.go:648 +0x6e
> main.main()
> 	C:/Users/username/Documents/Eclipse/src/test/main.go:27 +0x344
> 

Pull request description:
Fix a panic in value export when an array has multiple types of arrays
- I believe this is a more appropriate solution than #377 as it takes
  into account the types of elements in sub arrays, slices, etc.
- This should also fix #279 which was apparently closed although the
  issue still existed.

Patch:
diff --git a/value.go b/value.go
index 8be20ef..576f4c7 100644
--- a/value.go
+++ b/value.go
@@ -662,6 +662,8 @@ func (self Value) export() interface{} {
 			lengthValue := object.get(propertyLength)
 			length := lengthValue.value.(uint32)
 			kind := reflect.Invalid
+			keyKind := reflect.Invalid
+			elemKind := reflect.Invalid
 			state := 0
 			var t reflect.Type
 			for index := uint32(0); index < length; index += 1 {
@@ -673,15 +675,24 @@ func (self Value) export() interface{} {
 
 				t = reflect.TypeOf(value)
 
-				var k reflect.Kind
+				var k, kk, ek reflect.Kind
 				if t != nil {
 					k = t.Kind()
+					switch k {
+					case reflect.Map:
+						kk = t.Key().Kind()
+						fallthrough
+					case reflect.Array, reflect.Chan, reflect.Ptr, reflect.Slice:
+						ek = t.Elem().Kind()
+					}
 				}
 
 				if state == 0 {
 					kind = k
+					keyKind = kk
+					elemKind = ek
 					state = 1
-				} else if state == 1 && kind != k {
+				} else if state == 1 && (kind != k || keyKind != kk || elemKind != ek) {
 					state = 2
 				}
 


Test patch:
diff --git a/value_test.go b/value_test.go
index 88772bc..5d6792d 100644
--- a/value_test.go
+++ b/value_test.go
@@ -245,6 +245,21 @@ func TestExport(t *testing.T) {
 			is(value[1], nil)
 			is(value[1], interface{}(nil))
 		}
+		{
+			value := test(`[[1, 2.1], [3, 4], ["a", "b"], [{c: 5, d: 6}]];`).export().([]interface{})
+			value0 := value[0].([]interface{})
+			is(value0[0], 1)
+			is(value0[1], 2.1)
+			value1 := value[1].([]int64)
+			is(value1[0], 3)
+			is(value1[1], 4)
+			value2 := value[2].([]string)
+			is(value2[0], "a")
+			is(value2[1], "b")
+			value3 := value[3].([]map[string]interface{})
+			is(value3[0]["c"], 5)
+			is(value3[0]["d"], 6)
+		}
 
 		roundtrip := []interface{}{
 			true,