1 Star 0 Fork 1

landy / qlang

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
builtin.go 11.31 KB
一键复制 编辑 原始数据 按行查看 历史
xushiwei 提交于 2016-05-28 19:11 . #96 builtin function: make
package builtin
import (
"fmt"
"reflect"
"strings"
"qlang.io/qlang.spec.v1"
"qlang.io/qlang.spec.v1/types"
)
// -----------------------------------------------------------------------------
// Panic panics with v.
//
func Panic(v interface{}) {
panic(v)
}
// Panicf panics with sprintf(format, args...).
//
func Panicf(format string, args ...interface{}) {
panic(fmt.Sprintf(format, args...))
}
// -----------------------------------------------------------------------------
var (
zeroVal reflect.Value
)
// Mkmap makes a new map object.
//
func Mkmap(typ interface{}, n ...int) interface{} {
return reflect.MakeMap(types.Reflect(typ)).Interface()
}
// MapOf makes a map type.
//
func MapOf(key, val interface{}) interface{} {
return reflect.MapOf(types.Reflect(key), types.Reflect(val))
}
// MapFrom creates a map from args.
//
func MapFrom(args ...interface{}) interface{} {
n := len(args)
if (n & 1) != 0 {
panic("please use `mapFrom(key1, val1, key2, val2, ...)`")
}
if n == 0 {
return make(map[string]interface{})
}
switch kindOf2Args(args, 0) {
case reflect.String:
switch kindOf2Args(args, 1) {
case reflect.String:
ret := make(map[string]string, n>>1)
for i := 0; i < n; i += 2 {
ret[args[i].(string)] = args[i+1].(string)
}
return ret
case reflect.Int:
ret := make(map[string]int, n>>1)
for i := 0; i < n; i += 2 {
ret[args[i].(string)] = asInt(args[i+1])
}
return ret
case reflect.Float64:
ret := make(map[string]float64, n>>1)
for i := 0; i < n; i += 2 {
ret[args[i].(string)] = asFloat(args[i+1])
}
return ret
default:
ret := make(map[string]interface{}, n>>1)
for i := 0; i < n; i += 2 {
if t := args[i+1]; t != qlang.Undefined {
ret[args[i].(string)] = t
}
}
return ret
}
case reflect.Int:
switch kindOf2Args(args, 1) {
case reflect.String:
ret := make(map[int]string, n>>1)
for i := 0; i < n; i += 2 {
ret[asInt(args[i])] = args[i+1].(string)
}
return ret
case reflect.Int:
ret := make(map[int]int, n>>1)
for i := 0; i < n; i += 2 {
ret[asInt(args[i])] = asInt(args[i+1])
}
return ret
case reflect.Float64:
ret := make(map[int]float64, n>>1)
for i := 0; i < n; i += 2 {
ret[asInt(args[i])] = asFloat(args[i+1])
}
return ret
default:
ret := make(map[int]interface{}, n>>1)
for i := 0; i < n; i += 2 {
if t := args[i+1]; t != qlang.Undefined {
ret[asInt(args[i])] = t
}
}
return ret
}
default:
panic("mapFrom: key type only support `string`, `int` now")
}
}
// Delete deletes a key from map object.
//
func Delete(m interface{}, key interface{}) {
reflect.ValueOf(m).SetMapIndex(reflect.ValueOf(key), zeroVal)
}
// Set sets (index, value) pairs to an object. object can be a slice, an array, a map or a user-defined class.
//
func Set(m interface{}, args ...interface{}) {
n := len(args)
if (n & 1) != 0 {
panic("call with invalid argument count: please use `set(obj, member1, val1, ...)")
}
o := reflect.ValueOf(m)
switch o.Kind() {
case reflect.Slice, reflect.Array:
telem := reflect.TypeOf(m).Elem()
for i := 0; i < n; i += 2 {
val := autoConvert(telem, args[i+1])
o.Index(args[i].(int)).Set(val)
}
case reflect.Map:
setMapMember(o, args...)
default:
setMember(m, args...)
}
}
// SetIndex sets a (index, value) pair to an object. object can be a slice, an array, a map or a user-defined class.
//
func SetIndex(m, key, v interface{}) {
o := reflect.ValueOf(m)
switch o.Kind() {
case reflect.Map:
var val reflect.Value
if v == qlang.Undefined {
val = zeroVal
} else {
val = autoConvert(o.Type().Elem(), v)
}
o.SetMapIndex(reflect.ValueOf(key), val)
case reflect.Slice, reflect.Array:
if idx, ok := key.(int); ok {
o.Index(idx).Set(reflect.ValueOf(v))
} else {
panic("slice index isn't an integer value")
}
default:
setMember(m, key, v)
}
}
type varSetter interface {
SetVar(name string, val interface{})
}
func setMember(m interface{}, args ...interface{}) {
if v, ok := m.(varSetter); ok {
for i := 0; i < len(args); i += 2 {
v.SetVar(args[i].(string), args[i+1])
}
return
}
o := reflect.ValueOf(m)
if o.Kind() == reflect.Ptr {
o = o.Elem()
if o.Kind() == reflect.Struct {
setStructMember(o, args...)
return
}
}
panic(fmt.Sprintf("type `%v` doesn't support `set` operator", reflect.TypeOf(m)))
}
func setStructMember(o reflect.Value, args ...interface{}) {
for i := 0; i < len(args); i += 2 {
key := args[i].(string)
field := o.FieldByName(strings.Title(key))
if !field.IsValid() {
panic(fmt.Sprintf("struct `%v` doesn't has member `%v`", o.Type(), key))
}
field.Set(reflect.ValueOf(args[i+1]))
}
}
func setMapMember(o reflect.Value, args ...interface{}) {
var val reflect.Value
telem := o.Type().Elem()
for i := 0; i < len(args); i += 2 {
key := reflect.ValueOf(args[i])
t := args[i+1]
if t == qlang.Undefined {
val = zeroVal
} else {
val = autoConvert(telem, t)
}
o.SetMapIndex(key, val)
}
}
// Get gets a value from an object. object can be a slice, an array, a map or a user-defined class.
//
func Get(m interface{}, key interface{}) interface{} {
o := reflect.ValueOf(m)
switch o.Kind() {
case reflect.Map:
v := o.MapIndex(reflect.ValueOf(key))
if v.IsValid() {
return v.Interface()
}
return qlang.Undefined
case reflect.Slice, reflect.String, reflect.Array:
return o.Index(key.(int)).Interface()
default:
return qlang.GetEx(m, key)
}
}
// GetVar returns a member variable of an object. object can be a slice, an array, a map or a user-defined class.
//
func GetVar(m interface{}, key interface{}) interface{} {
return &qlang.DataIndex{Data: m, Index: key}
}
// Len returns length of a collection object. object can be a slice, an array, a map, a string or a chan.
//
func Len(a interface{}) int {
if a == nil {
return 0
}
if ch, ok := a.(*qlang.Chan); ok {
return ch.Data.Len()
}
return reflect.ValueOf(a).Len()
}
// Cap returns capacity of a collection object. object can be a slice, an array or a chan.
//
func Cap(a interface{}) int {
if a == nil {
return 0
}
if ch, ok := a.(*qlang.Chan); ok {
return ch.Data.Cap()
}
return reflect.ValueOf(a).Cap()
}
// SubSlice returns a[i:j]. if i == nil it returns a[:j]. if j == nil it returns a[i:].
//
func SubSlice(a, i, j interface{}) interface{} {
var va = reflect.ValueOf(a)
var i1, j1 int
if i != nil {
i1 = asInt(i)
}
if j != nil {
j1 = asInt(j)
} else {
j1 = va.Len()
}
return va.Slice(i1, j1).Interface()
}
// Copy does copy(a, b).
//
func Copy(a, b interface{}) int {
return reflect.Copy(reflect.ValueOf(a), reflect.ValueOf(b))
}
// Append does append(a, vals...)
//
func Append(a interface{}, vals ...interface{}) interface{} {
switch arr := a.(type) {
case []int:
return appendInts(arr, vals...)
case []interface{}:
return append(arr, vals...)
case []string:
return appendStrings(arr, vals...)
case []byte:
return appendBytes(arr, vals...)
case []float64:
return appendFloats(arr, vals...)
}
va := reflect.ValueOf(a)
telem := va.Type().Elem()
x := make([]reflect.Value, len(vals))
for i, v := range vals {
x[i] = autoConvert(telem, v)
}
return reflect.Append(va, x...).Interface()
}
func autoConvert(telem reflect.Type, v interface{}) reflect.Value {
if v == nil {
return reflect.Zero(telem)
}
val := reflect.ValueOf(v)
if telem != reflect.TypeOf(v) {
val = qlang.AutoConvert(val, telem)
}
return val
}
func appendFloats(a []float64, vals ...interface{}) interface{} {
for _, v := range vals {
switch val := v.(type) {
case float64:
a = append(a, val)
case int:
a = append(a, float64(val))
case float32:
a = append(a, float64(val))
default:
panic("unsupported: []float64 append " + reflect.TypeOf(v).String())
}
}
return a
}
func appendInts(a []int, vals ...interface{}) interface{} {
for _, v := range vals {
switch val := v.(type) {
case int:
a = append(a, val)
default:
panic("unsupported: []int append " + reflect.TypeOf(v).String())
}
}
return a
}
func appendBytes(a []byte, vals ...interface{}) interface{} {
for _, v := range vals {
switch val := v.(type) {
case byte:
a = append(a, val)
case int:
a = append(a, byte(val))
default:
panic("unsupported: []byte append " + reflect.TypeOf(v).String())
}
}
return a
}
func appendStrings(a []string, vals ...interface{}) interface{} {
for _, v := range vals {
switch val := v.(type) {
case string:
a = append(a, val)
default:
panic("unsupported: []string append " + reflect.TypeOf(v).String())
}
}
return a
}
// Mkslice returns a new slice.
//
func Mkslice(typ interface{}, args ...interface{}) interface{} {
n, cap := 0, 0
if len(args) == 1 {
if v, ok := args[0].(int); ok {
n, cap = v, v
} else {
panic("second param type of func `slice` must be `int`")
}
} else if len(args) > 1 {
if v, ok := args[0].(int); ok {
n = v
} else {
panic("2nd param type of func `slice` must be `int`")
}
if v, ok := args[1].(int); ok {
cap = v
} else {
panic("3rd param type of func `slice` must be `int`")
}
}
typSlice := reflect.SliceOf(types.Reflect(typ))
return reflect.MakeSlice(typSlice, n, cap).Interface()
}
// SliceFrom creates a slice from [a1, a2, ...].
//
func SliceFrom(args ...interface{}) interface{} {
n := len(args)
if n == 0 {
return []interface{}(nil)
}
switch kindOfArgs(args) {
case reflect.Int:
return appendInts(make([]int, 0, n), args...)
case reflect.Float64:
return appendFloats(make([]float64, 0, n), args...)
case reflect.String:
return appendStrings(make([]string, 0, n), args...)
case reflect.Uint8:
return appendBytes(make([]byte, 0, n), args...)
default:
return append(make([]interface{}, 0, n), args...)
}
}
// SliceFromTy creates a slice from `[]T{a1, a2, ...}`.
//
func SliceFromTy(args ...interface{}) interface{} {
got, ok := args[0].(qlang.GoTyper)
if !ok {
panic(fmt.Sprintf("`%v` is not a qlang type", args[0]))
}
t := got.GoType()
n := len(args)
ret := reflect.MakeSlice(reflect.SliceOf(t), 0, n-1).Interface()
return Append(ret, args[1:]...)
}
// SliceOf makes a slice type.
//
func SliceOf(typ interface{}) interface{} {
return reflect.SliceOf(types.Reflect(typ))
}
// StructInit creates a struct object from `structInit(structType, member1, val1, ...)`.
//
func StructInit(args ...interface{}) interface{} {
if (len(args) & 1) != 1 {
panic("call with invalid argument count: please use `structInit(structType, member1, val1, ...)")
}
got, ok := args[0].(qlang.GoTyper)
if !ok {
panic(fmt.Sprintf("`%v` is not a qlang type", args[0]))
}
t := got.GoType()
if t.Kind() != reflect.Struct {
panic(fmt.Sprintf("`%v` is not a struct type", args[0]))
}
ret := reflect.New(t)
setStructMember(ret.Elem(), args[1:]...)
return ret.Interface()
}
// MapInit creates a map object from `mapInit(mapType, member1, val1, ...)`.
//
func MapInit(args ...interface{}) interface{} {
if (len(args) & 1) != 1 {
panic("call with invalid argument count: please use `mapInit(mapType, member1, val1, ...)")
}
got, ok := args[0].(qlang.GoTyper)
if !ok {
panic(fmt.Sprintf("`%v` is not a qlang type", args[0]))
}
t := got.GoType()
if t.Kind() != reflect.Map {
panic(fmt.Sprintf("`%v` is not a map type", args[0]))
}
ret := reflect.MakeMap(t)
setMapMember(ret, args[1:]...)
return ret.Interface()
}
// -----------------------------------------------------------------------------
Go
1
https://gitee.com/landylee007/qlang.git
git@gitee.com:landylee007/qlang.git
landylee007
qlang
qlang
v2.9.60

搜索帮助

53164aa7 5694891 3bd8fe86 5694891