github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/reflect.go (about)

     1  package reflect
     2  
     3  import (
     4  	"reflect"
     5  	"sync"
     6  	"unsafe"
     7  
     8  	"github.com/hirochachacha/plua/object"
     9  )
    10  
    11  // interface{} (Go) -> Value (Lua)
    12  func ValueOf(x interface{}) object.Value {
    13  	switch x := x.(type) {
    14  	case nil:
    15  		return nil
    16  	case bool:
    17  		return object.Boolean(x)
    18  	case int:
    19  		return object.Integer(x)
    20  	case int8:
    21  		return object.Integer(x)
    22  	case int32:
    23  		return object.Integer(x)
    24  	case int64:
    25  		return object.Integer(x)
    26  	case float32:
    27  		return object.Number(x)
    28  	case float64:
    29  		return object.Number(x)
    30  	case string:
    31  		return object.String(x)
    32  	case unsafe.Pointer:
    33  		return object.LightUserdata{Pointer: x}
    34  	case object.Integer:
    35  		return x
    36  	case object.Number:
    37  		return x
    38  	case object.String:
    39  		return x
    40  	case object.Boolean:
    41  		return x
    42  	case object.LightUserdata:
    43  		return x
    44  	case object.GoFunction:
    45  		return x
    46  	case *object.Userdata:
    47  		return x
    48  	case object.Table:
    49  		return x
    50  	case object.Closure:
    51  		return x
    52  	case object.Thread:
    53  		return x
    54  	}
    55  
    56  	return valueOfReflect(reflect.ValueOf(x), true)
    57  }
    58  
    59  var (
    60  	tGoBool    = reflect.TypeOf(false)
    61  	tGoInt     = reflect.TypeOf(int(0))
    62  	tGoInt8    = reflect.TypeOf(int8(0))
    63  	tGoInt16   = reflect.TypeOf(int16(0))
    64  	tGoInt32   = reflect.TypeOf(int32(0))
    65  	tGoInt64   = reflect.TypeOf(int64(0))
    66  	tGoFloat32 = reflect.TypeOf(float32(0))
    67  	tGoFloat64 = reflect.TypeOf(float64(0))
    68  	tGoString  = reflect.TypeOf("")
    69  	tGoPointer = reflect.TypeOf(unsafe.Pointer(nil))
    70  
    71  	tValue = reflect.TypeOf((*object.Value)(nil)).Elem()
    72  
    73  	tBoolean       = reflect.TypeOf(object.False)
    74  	tInteger       = reflect.TypeOf(object.Integer(0))
    75  	tNumber        = reflect.TypeOf(object.Number(0))
    76  	tString        = reflect.TypeOf(object.String(""))
    77  	tLightUserdata = reflect.TypeOf(object.LightUserdata{})
    78  	tGoFunction    = reflect.TypeOf(object.GoFunction(nil))
    79  	tUserdataPtr   = reflect.TypeOf((*object.Userdata)(nil))
    80  
    81  	tTable   = reflect.TypeOf((*object.Table)(nil)).Elem()
    82  	tClosure = reflect.TypeOf((*object.Closure)(nil)).Elem()
    83  	tThread  = reflect.TypeOf((*object.Thread)(nil)).Elem()
    84  )
    85  
    86  var (
    87  	boolMT    object.Table
    88  	intMT     object.Table
    89  	floatMT   object.Table
    90  	stringMT  object.Table
    91  	uintMT    object.Table
    92  	complexMT object.Table
    93  	arrayMT   object.Table
    94  	chanMT    object.Table
    95  	funcMT    object.Table
    96  	ifaceMT   object.Table
    97  	mapMT     object.Table
    98  	ptrMT     object.Table
    99  	sliceMT   object.Table
   100  	structMT  object.Table
   101  )
   102  
   103  var (
   104  	boolOnce    sync.Once
   105  	intOnce     sync.Once
   106  	floatOnce   sync.Once
   107  	stringOnce  sync.Once
   108  	uintOnce    sync.Once
   109  	complexOnce sync.Once
   110  	arrayOnce   sync.Once
   111  	chanOnce    sync.Once
   112  	funcOnce    sync.Once
   113  	ifaceOnce   sync.Once
   114  	mapOnce     sync.Once
   115  	ptrOnce     sync.Once
   116  	sliceOnce   sync.Once
   117  	structOnce  sync.Once
   118  )
   119  
   120  // reflect.Value (Go) -> Value (Lua)
   121  func valueOfReflect(rval reflect.Value, skipPrimitive bool) object.Value {
   122  	if !skipPrimitive {
   123  		typ := rval.Type()
   124  		if typ == tValue {
   125  			if rval.IsNil() {
   126  				return nil
   127  			}
   128  
   129  			rval = rval.Elem()
   130  			typ = rval.Type()
   131  		}
   132  
   133  		switch typ {
   134  		case tGoBool:
   135  			return object.Boolean(rval.Bool())
   136  		case tGoInt, tGoInt8, tGoInt16, tGoInt32, tGoInt32:
   137  			return object.Integer(rval.Int())
   138  		case tGoFloat32, tGoFloat64:
   139  			return object.Number(rval.Float())
   140  		case tGoString:
   141  			return object.String(rval.String())
   142  		case tGoPointer:
   143  			return object.LightUserdata{Pointer: unsafe.Pointer(rval.Pointer())}
   144  		case tBoolean:
   145  			return rval.Interface().(object.Boolean)
   146  		case tInteger:
   147  			return rval.Interface().(object.Integer)
   148  		case tNumber:
   149  			return rval.Interface().(object.Number)
   150  		case tString:
   151  			return rval.Interface().(object.String)
   152  		case tLightUserdata:
   153  			return rval.Interface().(object.LightUserdata)
   154  		case tGoFunction:
   155  			return rval.Interface().(object.GoFunction)
   156  		case tUserdataPtr:
   157  			return rval.Interface().(*object.Userdata)
   158  		default:
   159  			switch {
   160  			case typ.Implements(tTable):
   161  				return rval.Interface().(object.Table)
   162  			case typ.Implements(tClosure):
   163  				return rval.Interface().(object.Closure)
   164  			case typ.Implements(tThread):
   165  				return rval.Interface().(object.Thread)
   166  			}
   167  		}
   168  	}
   169  
   170  	ud := &object.Userdata{Value: rval}
   171  
   172  	switch kind := rval.Kind(); kind {
   173  	case reflect.Bool:
   174  		boolOnce.Do(buildBoolMT)
   175  
   176  		ud.Metatable = boolMT
   177  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   178  		intOnce.Do(buildIntMT)
   179  
   180  		ud.Metatable = intMT
   181  	case reflect.Float32, reflect.Float64:
   182  		floatOnce.Do(buildFloatMT)
   183  
   184  		ud.Metatable = floatMT
   185  	case reflect.String:
   186  		stringOnce.Do(buildStringMT)
   187  
   188  		ud.Metatable = stringMT
   189  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   190  		uintOnce.Do(buildUintMT)
   191  
   192  		ud.Metatable = uintMT
   193  	case reflect.Complex64, reflect.Complex128:
   194  		complexOnce.Do(buildComplexMT)
   195  
   196  		ud.Metatable = complexMT
   197  	case reflect.Array:
   198  		arrayOnce.Do(buildArrayMT)
   199  
   200  		ud.Metatable = arrayMT
   201  	case reflect.Chan:
   202  		if rval.IsNil() {
   203  			return nil
   204  		}
   205  
   206  		chanOnce.Do(buildChanMT)
   207  
   208  		ud.Metatable = chanMT
   209  	case reflect.Func:
   210  		if rval.IsNil() {
   211  			return nil
   212  		}
   213  
   214  		funcOnce.Do(buildFuncMT)
   215  
   216  		ud.Metatable = funcMT
   217  	case reflect.Interface:
   218  		if rval.IsNil() {
   219  			return nil
   220  		}
   221  
   222  		ifaceOnce.Do(buildIfaceMT)
   223  
   224  		ud.Metatable = ifaceMT
   225  	case reflect.Map:
   226  		if rval.IsNil() {
   227  			return nil
   228  		}
   229  
   230  		mapOnce.Do(buildMapMT)
   231  
   232  		ud.Metatable = mapMT
   233  	case reflect.Ptr:
   234  		if rval.IsNil() {
   235  			return nil
   236  		}
   237  
   238  		ptrOnce.Do(buildPtrMT)
   239  
   240  		ud.Metatable = ptrMT
   241  	case reflect.Slice:
   242  		if rval.IsNil() {
   243  			return nil
   244  		}
   245  
   246  		sliceOnce.Do(buildSliceMT)
   247  
   248  		ud.Metatable = sliceMT
   249  	case reflect.Struct:
   250  		structOnce.Do(buildStructMT)
   251  
   252  		ud.Metatable = structMT
   253  	case reflect.UnsafePointer:
   254  		return object.LightUserdata{Pointer: unsafe.Pointer(rval.Pointer())}
   255  	case reflect.Invalid:
   256  		return nil
   257  	default:
   258  		panic("unreachable")
   259  	}
   260  
   261  	return ud
   262  }
   263  
   264  // Value (Lua) -> reflect.Value (Go)
   265  func toReflectValue(typ reflect.Type, val object.Value) reflect.Value {
   266  	switch val := val.(type) {
   267  	case nil:
   268  		if typ == tValue {
   269  			return reflect.Zero(typ)
   270  		}
   271  
   272  		switch typ.Kind() {
   273  		case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
   274  			return reflect.Zero(typ)
   275  		}
   276  	case object.Boolean:
   277  		if typ == tValue {
   278  			return reflect.ValueOf(val)
   279  		}
   280  
   281  		if typ.Kind() == reflect.Bool {
   282  			return reflect.ValueOf(val).Convert(typ)
   283  		}
   284  	case object.Integer:
   285  		if typ == tValue {
   286  			return reflect.ValueOf(val)
   287  		}
   288  
   289  		switch typ.Kind() {
   290  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
   291  			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
   292  			reflect.Float32, reflect.Float64:
   293  			return reflect.ValueOf(val).Convert(typ)
   294  		case reflect.String:
   295  			return reflect.ValueOf(integerToString(val)).Convert(typ)
   296  		}
   297  	case object.Number:
   298  		if typ == tValue {
   299  			return reflect.ValueOf(val)
   300  		}
   301  
   302  		switch typ.Kind() {
   303  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   304  			if ival, ok := numberToInteger(val); ok {
   305  				return reflect.ValueOf(ival).Convert(typ)
   306  			}
   307  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   308  			if u, ok := numberToGoUint(val); ok {
   309  				return reflect.ValueOf(u).Convert(typ)
   310  			}
   311  		case reflect.Float32, reflect.Float64:
   312  			return reflect.ValueOf(val).Convert(typ)
   313  		case reflect.String:
   314  			return reflect.ValueOf(numberToString(val)).Convert(typ)
   315  		}
   316  	case object.String:
   317  		if typ == tValue {
   318  			return reflect.ValueOf(val)
   319  		}
   320  
   321  		switch typ.Kind() {
   322  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   323  			if ival, ok := stringToInteger(val); ok {
   324  				return reflect.ValueOf(ival).Convert(typ)
   325  			}
   326  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   327  			if u, ok := stringToGoUint(val); ok {
   328  				return reflect.ValueOf(u).Convert(typ)
   329  			}
   330  		case reflect.Float32, reflect.Float64:
   331  			if nval, ok := stringToNumber(val); ok {
   332  				return reflect.ValueOf(nval).Convert(typ)
   333  			}
   334  		case reflect.String:
   335  			return reflect.ValueOf(val).Convert(typ)
   336  		}
   337  	case object.LightUserdata:
   338  		if typ == tValue {
   339  			return reflect.ValueOf(val)
   340  		}
   341  
   342  		if typ.Kind() == reflect.UnsafePointer {
   343  			return reflect.ValueOf(val.Pointer).Convert(typ)
   344  		}
   345  	case object.GoFunction:
   346  		if typ == tValue {
   347  			return reflect.ValueOf(val)
   348  		}
   349  
   350  		rval := reflect.ValueOf(val)
   351  		rtyp := rval.Type()
   352  
   353  		if rtyp == typ {
   354  			return rval
   355  		}
   356  	case *object.Userdata:
   357  		if typ == tValue {
   358  			return reflect.ValueOf(val)
   359  		}
   360  
   361  		if rval, ok := val.Value.(reflect.Value); ok {
   362  			rtyp := rval.Type()
   363  
   364  			if rtyp == typ {
   365  				return rval
   366  			}
   367  		} else {
   368  			rval := reflect.ValueOf(val.Value)
   369  			rtyp := rval.Type()
   370  
   371  			if rtyp == typ {
   372  				return rval
   373  			}
   374  		}
   375  	case object.Table:
   376  		if typ == tValue {
   377  			return reflect.ValueOf(val)
   378  		}
   379  
   380  		rval := reflect.ValueOf(val)
   381  		rtyp := rval.Type()
   382  
   383  		if rtyp == typ {
   384  			return rval
   385  		}
   386  	case object.Closure:
   387  		if typ == tValue {
   388  			return reflect.ValueOf(val)
   389  		}
   390  
   391  		rval := reflect.ValueOf(val)
   392  		rtyp := rval.Type()
   393  
   394  		if rtyp == typ {
   395  			return rval
   396  		}
   397  	case object.Thread:
   398  		if typ == tValue {
   399  			return reflect.ValueOf(val)
   400  		}
   401  
   402  		rval := reflect.ValueOf(val)
   403  		rtyp := rval.Type()
   404  
   405  		if rtyp == typ {
   406  			return rval
   407  		}
   408  	default:
   409  		panic("unreachable")
   410  	}
   411  
   412  	return reflect.ValueOf(nil)
   413  }