func mruby2go(mrb *C.mrb_state, o C.mrb_value) interface{} { switch o.tt { case C.MRB_TT_TRUE: return true case C.MRB_TT_FALSE: return false case C.MRB_TT_FLOAT: return float32(C._mrb_float(o)) case C.MRB_TT_FIXNUM: return int32(C._mrb_fixnum(o)) case C.MRB_TT_ARRAY: { var list []interface{} for i := 0; i < int(C._RARRAY_LEN(o)); i++ { list = append(list, mruby2go(mrb, C.mrb_ary_ref(mrb, o, C.mrb_int(i)))) } return list } case C.MRB_TT_HASH: { hash := make(map[string]interface{}) keys := C.mrb_hash_keys(mrb, o) for i := 0; i < int(C._RARRAY_LEN(keys)); i++ { key := C.mrb_ary_ref(mrb, keys, C.mrb_int(i)) val := C.mrb_hash_get(mrb, o, key) hash[C.GoString(C.mrb_string_value_ptr(mrb, key))] = mruby2go(mrb, val) } return hash } case C.MRB_TT_STRING: return C.GoString(C.mrb_string_value_ptr(mrb, o)) } return nil }
func (v *MrbValue) call(method string, args []Value, block Value) (*MrbValue, error) { var argv []C.mrb_value = nil var argvPtr *C.mrb_value = nil if len(args) > 0 { // Make the raw byte slice to hold our arguments we'll pass to C argv = make([]C.mrb_value, len(args)) for i, arg := range args { argv[i] = arg.MrbValue(&Mrb{v.state}).value } argvPtr = &argv[0] } var blockV *C.mrb_value if block != nil { val := block.MrbValue(&Mrb{v.state}).value blockV = &val } cs := C.CString(method) defer C.free(unsafe.Pointer(cs)) // If we have a block, we have to call a separate function to // pass a block in. Otherwise, we just call it directly. var result C.mrb_value if blockV == nil { result = C.mrb_funcall_argv( v.state, v.value, C.mrb_intern_cstr(v.state, cs), C.mrb_int(len(argv)), argvPtr) } else { result = C.mrb_funcall_with_block( v.state, v.value, C.mrb_intern_cstr(v.state, cs), C.mrb_int(len(argv)), argvPtr, *blockV) } if exc := checkException(v.state); exc != nil { return nil, exc } return newValue(v.state, result), nil }
// Yield yields to a block with the given arguments. // // This should be called within the context of a Func. func (m *Mrb) Yield(block Value, args ...Value) (*MrbValue, error) { mrbBlock := block.MrbValue(m) var argv []C.mrb_value = nil var argvPtr *C.mrb_value = nil if len(args) > 0 { // Make the raw byte slice to hold our arguments we'll pass to C argv = make([]C.mrb_value, len(args)) for i, arg := range args { argv[i] = arg.MrbValue(m).value } argvPtr = &argv[0] } result := C.mrb_yield_argv( m.state, mrbBlock.value, C.mrb_int(len(argv)), argvPtr) if m.state.exc != nil { return nil, newExceptionValue(m.state) } return newValue(m.state, result), nil }
// Converts Go value to mruby value. func (m *MRuby) mrubyValue(i interface{}) C.mrb_value { v := reflect.ValueOf(i) switch v.Kind() { case reflect.Invalid: return C.mrb_nil_value() // mrb_undef_value() explodes case reflect.Bool: b := v.Bool() if b { return C.mrb_true_value() } else { return C.mrb_false_value() } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return C.mrb_fixnum_value(C.mrb_int(v.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return C.mrb_fixnum_value(C.mrb_int(v.Uint())) case reflect.Float32, reflect.Float64: return C.mrb_float_value((*C.struct_mrb_state)(m.state), C.mrb_float(v.Float())) case reflect.String: cs := C.CString(v.String()) defer C.free(unsafe.Pointer(cs)) if v.Type() == symbolT { return C.mrb_check_intern_cstr(m.state, cs) } else { return C.mrb_str_new_cstr(m.state, cs) } case reflect.Array, reflect.Slice: l := v.Len() res := C.mrb_ary_new_capa(m.state, C.mrb_int(l)) for i := 0; i < l; i++ { C.mrb_ary_set(m.state, res, C.mrb_int(i), m.mrubyValue(v.Index(i).Interface())) } return res case reflect.Map: l := v.Len() res := C.mrb_hash_new_capa(m.state, C.int(l)) for _, key := range v.MapKeys() { val := v.MapIndex(key) C.mrb_hash_set(m.state, res, m.mrubyValue(key.Interface()), m.mrubyValue(val.Interface())) } return res } panic(fmt.Errorf("gomruby bug: failed to convert Go value %#v (%T) to mruby value", i, i)) }
// Loads mruby code. Arguments are exposed as ARGV array. func (c *LoadContext) Load(code string, args ...interface{}) (res interface{}, err error) { l := len(args) ARGV := C.mrb_ary_new_capa(c.m.state, C.mrb_int(l)) for i := 0; i < l; i++ { ii := C.mrb_int(i) C.mrb_ary_set(c.m.state, ARGV, ii, c.m.mrubyValue(args[ii])) } C.mrb_define_global_const(c.m.state, argvCS, ARGV) codeC := C.CString(code) defer C.free(unsafe.Pointer(codeC)) v := C.mrb_load_string_cxt(c.m.state, codeC, c.context) res = c.m.goValue(v) if c.m.state.exc != nil { v = C.mrb_obj_value(unsafe.Pointer(c.m.state.exc)) err = errors.New(c.m.inspect(v)) } return }
// Get gets an element form the Array by index. // // This does not copy the element. This is a pointer/reference directly // to the element in the array. func (v *Array) Get(idx int) (*MrbValue, error) { result := C.mrb_ary_entry(v.value, C.mrb_int(idx)) val := newValue(v.state, result) if val.Type() == TypeNil { val = nil } return val, nil }
// Converts mruby value to Go value. func (m *MRuby) goValue(v C.mrb_value) interface{} { switch v.tt { case C.MRB_TT_UNDEF: // for example, result of syntax error return nil case C.MRB_TT_TRUE: return true case C.MRB_TT_FALSE: if C._gomruby_is_nil(v) == 0 { return false } return nil case C.MRB_TT_FIXNUM: return int(C._gomruby_fixnum(v)) case C.MRB_TT_FLOAT: return float64(C._gomruby_float(v)) case C.MRB_TT_SYMBOL: cs := C.mrb_string_value_ptr(m.state, v) return Symbol(C.GoString(cs)) case C.MRB_TT_STRING: cs := C.mrb_string_value_ptr(m.state, v) return C.GoString(cs) case C.MRB_TT_ARRAY: l := int(C.mrb_ary_len(m.state, v)) res := make([]interface{}, l) for i := 0; i < l; i++ { res[i] = m.goValue(C.mrb_ary_ref(m.state, v, C.mrb_int(i))) } return res case C.MRB_TT_HASH: keys := C.mrb_hash_keys(m.state, v) l := int(C.mrb_ary_len(m.state, keys)) res := make(map[interface{}]interface{}, l) for i := 0; i < l; i++ { key := C.mrb_ary_ref(m.state, keys, C.mrb_int(i)) val := C.mrb_hash_get(m.state, v, key) res[m.goValue(key)] = m.goValue(val) } return res } panic(fmt.Errorf("gomruby bug: failed to convert mruby value %#v to Go value", v)) }
// Get gets an element form the Array by index. // // This does not copy the element. This is a pointer/reference directly // to the element in the array. func (v *Array) Get(idx int) (*MrbValue, error) { result := C.mrb_ary_entry(v.value, C.mrb_int(idx)) if v.state.exc != nil { return nil, newExceptionValue(v.state) } val := newValue(v.state, result) if val.Type() == TypeFalse { val = nil } return val, nil }
func go2mruby(mrb *C.mrb_state, o interface{}) C.mrb_value { v := reflect.ValueOf(o) switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return C.mrb_fixnum_value(C.mrb_int(v.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return C.mrb_fixnum_value(C.mrb_int(v.Uint())) case reflect.Float32, reflect.Float64: return C.mrb_float_value((C.mrb_float)(v.Float())) case reflect.Complex64, reflect.Complex128: return C.mrb_float_value((C.mrb_float)(v.Float())) case reflect.String: ptr := C.CString(v.String()) return C.mrb_str_new(mrb, ptr, C.strlen(ptr)) case reflect.Bool: if v.Bool() { return C.mrb_true_value() } return C.mrb_false_value() case reflect.Array, reflect.Slice: ary := C.mrb_ary_new(mrb) for i := 0; i < v.Len(); i++ { C.mrb_ary_push(mrb, ary, go2mruby(mrb, v.Index(i).Interface())) } return ary case reflect.Map: hash := C.mrb_hash_new(mrb, 32) for _, key := range v.MapKeys() { val := v.MapIndex(key) C.mrb_hash_set(mrb, hash, go2mruby(mrb, key.String()), go2mruby(mrb, val.Interface())) } return hash case reflect.Interface: return go2mruby(mrb, v.Elem().Interface()) } return C.mrb_nil_value() }
// Instantiate the class with the given args. func (c *Class) New(args ...Value) (*MrbValue, error) { var argv []C.mrb_value = nil var argvPtr *C.mrb_value = nil if len(args) > 0 { // Make the raw byte slice to hold our arguments we'll pass to C argv = make([]C.mrb_value, len(args)) for i, arg := range args { argv[i] = arg.MrbValue(c.mrb).value } argvPtr = &argv[0] } result := C.mrb_obj_new(c.mrb.state, c.class, C.mrb_int(len(argv)), argvPtr) if c.mrb.state.exc != nil { return nil, newExceptionValue(c.mrb.state) } return newValue(c.mrb.state, result), nil }
// Returns a Value for a fixed number. func (m *Mrb) FixnumValue(v int) *MrbValue { return newValue(m.state, C.mrb_fixnum_value(C.mrb_int(v))) }