github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/map.go (about) 1 package reflect 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/hirochachacha/plua/internal/tables" 8 "github.com/hirochachacha/plua/object" 9 "github.com/hirochachacha/plua/object/fnutil" 10 ) 11 12 func buildMapMT() { 13 mt := tables.NewTableSize(0, 7) 14 15 mt.Set(object.TM_METATABLE, object.True) 16 mt.Set(object.TM_NAME, object.String("MAP*")) 17 mt.Set(object.TM_TOSTRING, object.GoFunction(mtostring)) 18 19 mt.Set(object.TM_INDEX, object.GoFunction(mindex)) 20 mt.Set(object.TM_NEWINDEX, object.GoFunction(mnewindex)) 21 mt.Set(object.TM_LEN, object.GoFunction(mlength)) 22 mt.Set(object.TM_PAIRS, object.GoFunction(mpairs)) 23 24 mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Pointer() == y.Pointer() }, toMap)) 25 26 mapMT = mt 27 } 28 29 func toMap(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) { 30 val, err := toValue(ap, n, "MAP*") 31 if err != nil { 32 return reflect.Value{}, err 33 } 34 if val.Kind() != reflect.Map { 35 return reflect.Value{}, ap.TypeError(n, "MAP*") 36 } 37 return val, nil 38 } 39 40 func mtostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 41 ap := fnutil.NewArgParser(th, args) 42 43 m, err := toMap(ap, 0) 44 if err != nil { 45 return nil, err 46 } 47 48 return []object.Value{object.String(fmt.Sprintf("go map (0x%x)", m.Pointer()))}, nil 49 } 50 51 func mlength(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 52 ap := fnutil.NewArgParser(th, args) 53 54 m, err := toMap(ap, 0) 55 if err != nil { 56 return nil, err 57 } 58 59 return []object.Value{object.Integer(m.Len())}, nil 60 } 61 62 func mindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 63 ap := fnutil.NewArgParser(th, args) 64 65 m, err := toMap(ap, 0) 66 if err != nil { 67 return nil, err 68 } 69 70 key, err := ap.ToValue(1) 71 if err != nil { 72 return nil, err 73 } 74 75 ktyp := m.Type().Key() 76 77 if rkey := toReflectValue(ktyp, key); rkey.IsValid() { 78 rval := m.MapIndex(rkey) 79 80 return []object.Value{valueOfReflect(rval, false)}, nil 81 } 82 83 return nil, object.NewRuntimeError(fmt.Sprintf("cannot use %v (type %s) as type %s in map index", key, reflect.TypeOf(key), ktyp)) 84 } 85 86 func mnewindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 87 ap := fnutil.NewArgParser(th, args) 88 89 m, err := toMap(ap, 0) 90 if err != nil { 91 return nil, err 92 } 93 94 key, err := ap.ToValue(1) 95 if err != nil { 96 return nil, err 97 } 98 99 val, err := ap.ToValue(2) 100 if err != nil { 101 return nil, err 102 } 103 104 styp := m.Type() 105 ktyp := styp.Key() 106 vtyp := styp.Elem() 107 108 if rkey := toReflectValue(ktyp, key); rkey.IsValid() { 109 if rval := toReflectValue(vtyp, val); rval.IsValid() { 110 m.SetMapIndex(rkey, rval) 111 112 return nil, nil 113 } 114 115 return nil, object.NewRuntimeError(fmt.Sprintf("cannot use %v (type %s) as type %s in map assignment", val, reflect.TypeOf(val), vtyp)) 116 } 117 118 return nil, object.NewRuntimeError(fmt.Sprintf("cannot use %v (type %s) as type %s in map index", key, reflect.TypeOf(key), ktyp)) 119 } 120 121 func mpairs(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 122 ap := fnutil.NewArgParser(th, args) 123 124 m, err := toMap(ap, 0) 125 if err != nil { 126 return nil, err 127 } 128 129 keys := m.MapKeys() 130 length := len(keys) 131 132 i := 0 133 134 next := func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 135 if i == length { 136 return nil, nil 137 } 138 139 key := keys[i] 140 rval := m.MapIndex(key) 141 142 i++ 143 144 return []object.Value{valueOfReflect(key, false), valueOfReflect(rval, false)}, nil 145 } 146 147 return []object.Value{object.GoFunction(next)}, nil 148 }