From 00fa1b54ca563ef38d1987855c882691d073fbc1 Mon Sep 17 00:00:00 2001 From: Roman TSovanyan Date: Sun, 1 Oct 2017 14:16:00 +0300 Subject: [PATCH] todos --- bincode/binfuncs.go | 378 -------------------------------------------- core/coreifaces.go | 6 - core/coretypes.go | 176 ++++++++++++++++++++- 3 files changed, 174 insertions(+), 386 deletions(-) diff --git a/bincode/binfuncs.go b/bincode/binfuncs.go index 85e0b4b..3969a59 100644 --- a/bincode/binfuncs.go +++ b/bincode/binfuncs.go @@ -40,381 +40,3 @@ func LeftRightBounds(rb, re int, vlen int) (ii, ij int) { return } -// func EvalBinOp(op core.VMOperation, lhsV, rhsV reflect.Value) (interface{}, error) { -// // log.Println(OperMapR[op]) -// if !lhsV.IsValid() || !rhsV.IsValid() { -// if !rhsV.IsValid() && !rhsV.IsValid() { -// // в обоих значениях nil -// return true, nil -// } else { -// // одно из значений nil, а второе нет -// return false, nil -// } -// } -// lk := lhsV.Kind() -// rk := rhsV.Kind() -// lvi := lhsV.Interface() -// rvi := rhsV.Interface() - -// switch op { - -// // TODO: математика множеств и графов - -// case core.ADD: -// if lk == reflect.String || rk == reflect.String { -// return ToString(lvi) + ToString(rvi), nil -// } -// if (lk == reflect.Array || lk == reflect.Slice) && (rk != reflect.Array && rk != reflect.Slice) { -// return reflect.Append(lhsV, rhsV).Interface(), nil -// } -// if (lk == reflect.Array || lk == reflect.Slice) && (rk == reflect.Array || rk == reflect.Slice) { -// return reflect.AppendSlice(lhsV, rhsV).Interface(), nil -// } -// if lk == reflect.Float64 || rk == reflect.Float64 { -// return ToFloat64(lvi) + ToFloat64(rvi), nil -// } -// if lk == reflect.Struct && rk == reflect.Int64 { -// // проверяем на дату + число -// if lhsV.Type().AssignableTo(core.ReflectVMTime) { -// if rhsV.Type().AssignableTo(reflect.TypeOf(time.Duration(0))) { -// // это Duration -// return time.Time(lvi.(core.VMTime)).Add(time.Duration(rhsV.Int())), nil -// } else { -// // это было число в секундах -// return time.Time(lvi.(core.VMTime)).Add(time.Duration(1e9 * rhsV.Int())), nil -// } -// } -// } -// return ToInt64(lvi) + ToInt64(rvi), nil -// case core.SUB: -// if lk == reflect.Float64 || rk == reflect.Float64 { -// return ToFloat64(lvi) - ToFloat64(rvi), nil -// } -// if lk == reflect.Struct && rk == reflect.Int64 { -// // проверяем на дату + число -// if lhsV.Type().AssignableTo(core.ReflectVMTime) { -// if rhsV.Type().AssignableTo(reflect.TypeOf(time.Duration(0))) { -// // это Duration -// return time.Time(lvi.(core.VMTime)).Add(time.Duration(-rhsV.Int())), nil -// } else { -// // это было число в секундах -// return time.Time(lvi.(core.VMTime)).Add(time.Duration(-1e9 * rhsV.Int())), nil -// } -// } -// } -// if lk == reflect.Struct && rk == reflect.Struct { -// // проверяем на дата - дата -// if lhsV.Type().AssignableTo(core.ReflectVMTime) && rhsV.Type().AssignableTo(core.ReflectVMTime) { -// return time.Time(lvi.(core.VMTime)).Sub(time.Time(rvi.(core.VMTime))), nil -// } -// } -// return ToInt64(lvi) - ToInt64(rvi), nil -// case core.MUL: -// if lk == reflect.String && (rk == reflect.Int || rk == reflect.Int32 || rk == reflect.Int64) { -// return strings.Repeat(ToString(lvi), int(ToInt64(rvi))), nil -// } -// if lk == reflect.Float64 || rk == reflect.Float64 { -// return ToFloat64(lvi) * ToFloat64(rvi), nil -// } -// return ToInt64(lvi) * ToInt64(rvi), nil -// case core.QUO: -// return ToFloat64(lvi) / ToFloat64(rvi), nil -// case core.REM: -// return ToInt64(lvi) % ToInt64(rvi), nil -// case core.EQL: -// return Equal(lvi, rvi), nil -// case core.NEQ: -// return Equal(lvi, rvi) == false, nil -// case core.GTR: -// return ToFloat64(lvi) > ToFloat64(rvi), nil -// case core.GEQ: -// return ToFloat64(lvi) >= ToFloat64(rvi), nil -// case core.LSS: -// return ToFloat64(lvi) < ToFloat64(rvi), nil -// case core.LEQ: -// return ToFloat64(lvi) <= ToFloat64(rvi), nil -// case core.OR: -// return ToInt64(lvi) | ToInt64(rvi), nil -// case core.LOR: -// // if x := ToBool(lvi); x { -// // return x, nil -// // } else { -// // return ToBool(rvi), nil -// // } -// case core.AND: -// return ToInt64(lvi) & ToInt64(rvi), nil -// case core.LAND: -// // if x := ToBool(lvi); x { -// // return ToBool(rvi), nil -// // } else { -// // return x, nil -// // } -// case core.POW: -// if lk == reflect.Float64 { -// return math.Pow(ToFloat64(lvi), ToFloat64(rvi)), nil -// } -// return int64(math.Pow(ToFloat64(lvi), ToFloat64(rvi))), nil -// case core.SHR: -// return ToInt64(lvi) >> uint64(ToInt64(rvi)), nil -// case core.SHL: -// return ToInt64(lvi) << uint64(ToInt64(rvi)), nil -// } -// return nil, fmt.Errorf("Неизвестный оператор") -// } - -// func TypeCastConvert(v interface{}, nt reflect.Type, skipCollections bool) (interface{}, error) { -// rv := reflect.ValueOf(v) -// rvkind := rv.Kind() - -// if skipCollections && (rvkind == reflect.Array || rvkind == reflect.Slice || -// rvkind == reflect.Map || rvkind == reflect.Struct || rvkind == reflect.Chan) { -// return v, nil -// } -// if rvkind == reflect.Interface || rvkind == reflect.Ptr { -// rv = rv.Elem() -// rvkind = rv.Kind() -// v = rv.Interface() -// } -// // учитываем случай двойной вложенности указателя или интерфейса в указателе -// if rvkind == reflect.Interface || rvkind == reflect.Ptr { -// rv = rv.Elem() -// rvkind = rv.Kind() -// v = rv.Interface() -// } -// if rvkind == nt.Kind() { -// return v, nil -// } - -// switch rvkind { -// case reflect.Array, reflect.Slice: -// switch nt.Kind() { -// case reflect.String: -// // сериализуем в json -// b, err := json.Marshal(v) -// if err != nil { -// return nil, err -// } -// return string(b), nil -// default: -// // преобразуем в такой же слайс, но с типизированными значениями, и копируем их с новым типом -// rs := reflect.MakeSlice(reflect.SliceOf(nt), rv.Len(), rv.Cap()) -// for i := 0; i < rv.Len(); i++ { -// iv := rv.Index(i).Interface() -// // конверсия вложенных массивов и структур не производится -// rsi, err := TypeCastConvert(iv, nt, true) -// if err != nil { -// return nil, err -// } -// sv := rs.Index(i) -// if sv.CanSet() { -// sv.Set(reflect.ValueOf(rsi)) -// } -// //rs = reflect.Append(rs, rsi) -// } -// return rs.Interface(), nil -// } -// case reflect.Chan: -// // возвращаем новый канал с типизированными значениями и прежним размером буфера -// return reflect.MakeChan(reflect.ChanOf(reflect.BothDir, nt), rv.Cap()).Interface(), nil -// case reflect.Map: -// switch nt.Kind() { -// case reflect.String: -// // сериализуем в json -// b, err := json.Marshal(v) -// if err != nil { -// return nil, err -// } -// return string(b), nil -// case reflect.Struct: -// // для приведения в структурные типы - можно использовать мапу для заполнения полей -// rs := reflect.New(nt) // указатель на новую структуру -// //заполняем экспортируемые неанонимные поля, если их находим в мапе -// for i := 0; i < nt.NumField(); i++ { -// f := nt.Field(i) -// if f.PkgPath == "" && !f.Anonymous { -// setv := reflect.Indirect(rv.MapIndex(reflect.ValueOf(f.Name))) -// if setv.Kind() == reflect.Interface { -// setv = setv.Elem() -// } -// fv := rs.Elem().FieldByName(f.Name) -// if setv.IsValid() && fv.IsValid() && fv.CanSet() { -// if fv.Kind() != setv.Kind() { -// if setv.Type().ConvertibleTo(fv.Type()) { -// setv = setv.Convert(fv.Type()) -// } else { -// return nil, fmt.Errorf("Поле структуры имеет другой тип") -// } -// } -// fv.Set(setv) -// } -// } -// } -// return rs.Interface(), nil -// } -// case reflect.String: -// if nt.AssignableTo(core.ReflectVMTime) { -// tt, err := time.Parse(time.RFC3339, rv.String()) -// if err == nil { -// return core.VMTime(tt), nil -// } else { -// panic(err) -// } -// } -// switch nt.Kind() { -// case reflect.Float64: -// if rv.Type().ConvertibleTo(nt) { -// return rv.Convert(nt).Interface(), nil -// } -// f, err := strconv.ParseFloat(ToString(v), 64) -// if err == nil { -// return f, nil -// } -// case reflect.Array, reflect.Slice: -// //парсим json из строки и пытаемся получить массив -// var rm core.VMSlice -// if err := json.Unmarshal([]byte(ToString(v)), &rm); err != nil { -// return nil, err -// } -// return rm, nil -// case reflect.Map: -// //парсим json из строки и пытаемся получить мапу -// var rm core.VMStringMap -// if err := json.Unmarshal([]byte(ToString(v)), rm); err != nil { -// return nil, err -// } -// return rm, nil -// case reflect.Struct: -// //парсим json из строки и пытаемся получить указатель на структуру -// rm := reflect.New(nt).Interface() -// if err := json.Unmarshal([]byte(ToString(v)), rm); err != nil { -// return nil, err -// } -// return rm, nil -// case reflect.Int64: -// if rv.Type().ConvertibleTo(nt) { -// return rv.Convert(nt).Interface(), nil -// } -// i, err := strconv.ParseInt(ToString(v), 10, 64) -// if err == nil { -// return i, nil -// } -// f, err := strconv.ParseFloat(ToString(v), 64) -// if err == nil { -// return int64(f), nil -// } -// case reflect.Bool: -// s := strings.ToLower(ToString(v)) -// if s == "истина" || s == "true" { -// return true, nil -// } -// if s == "ложь" || s == "false" { -// return false, nil -// } -// if rv.Type().ConvertibleTo(reflect.TypeOf(1.0)) && rv.Convert(reflect.TypeOf(1.0)).Float() > 0.0 { -// return true, nil -// } -// b, err := strconv.ParseBool(s) -// if err == nil { -// return b, nil -// } -// return false, nil -// default: -// if rv.Type().ConvertibleTo(nt) { -// return rv.Convert(nt).Interface(), nil -// } -// } -// case reflect.Bool: -// switch nt.Kind() { -// case reflect.String: -// // if ToBool(v) { -// // return "true", nil // для совместимости с другими платформами -// // } else { -// // return "false", nil // для совместимости с другими платформами -// // } -// case reflect.Int64: -// // if ToBool(v) { -// // return int64(1), nil -// // } else { -// // return int64(0), nil -// // } -// case reflect.Float64: -// // if ToBool(v) { -// // return float64(1.0), nil -// // } else { -// // return float64(0.0), nil -// // } -// } -// case reflect.Float32, reflect.Float64, -// reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, -// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: -// // приведение к дате -// if nt.AssignableTo(core.ReflectVMTime) { -// switch rvkind { -// case reflect.Float32, reflect.Float64: -// rti := int64(rv.Float()) -// rtins := int64((rv.Float() - float64(rti)) * 1e9) -// return core.VMTime(time.Unix(rti, rtins)), nil -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, -// reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: -// rti := rv.Int() -// return core.VMTime(time.Unix(rti, 0)), nil -// } -// } -// // числа конвертируются стандартно -// switch nt.Kind() { -// case reflect.Bool: -// // return ToBool(v), nil -// default: -// if rv.Type().ConvertibleTo(nt) { -// return rv.Convert(nt).Interface(), nil -// } -// } -// case reflect.Struct: -// t, ok := v.(time.Time) -// if !ok { -// var t2 core.VMTime -// t2, ok = v.(core.VMTime) -// if ok { -// t = time.Time(t2) -// } -// } -// if ok { -// if nt.AssignableTo(core.ReflectVMTime) { -// return core.VMTime(t), nil -// } -// // это дата/время - конвертируем в секунды (целые или с плавающей запятой) или в формат RFC3339 -// switch nt.Kind() { -// case reflect.String: -// return t.Format(time.RFC3339), nil -// case reflect.Int64: -// return t.Unix(), nil // до секунд -// case reflect.Float64: -// return float64(t.UnixNano()) / 1e9, nil // после запятой - наносекунды -// } -// } else { -// switch nt.Kind() { -// case reflect.Map: -// // структура может быть приведена в мапу -// rs := make(core.VMStringMap) -// rtyp := rv.Type() -// for i := 0; i < rtyp.NumField(); i++ { -// f := rtyp.Field(i) -// fv := rv.Field(i) -// if f.PkgPath == "" && !f.Anonymous { -// rs[f.Name] = core.ReflectToVMValue(fv) -// } -// } -// return rs, nil -// case reflect.String: -// // сериализуем структуру в json -// b, err := json.Marshal(v) -// if err != nil { -// return nil, err -// } -// return string(b), nil - -// } -// } -// } -// return nil, fmt.Errorf("Приведение типа недопустимо") -// } diff --git a/core/coreifaces.go b/core/coreifaces.go index 5de7a64..e425577 100644 --- a/core/coreifaces.go +++ b/core/coreifaces.go @@ -25,24 +25,18 @@ type ( ParseGoType(interface{}) // используется для указателей, т.к. парсит в их значения } - // TODO: реализовать VMOperationer во всех типах с возможностью операции с другим операндом - // VMOperationer может выполнить операцию с другим значением, операцию сравнения или математическую VMOperationer interface { VMValuer EvalBinOp(VMOperation, VMOperationer) (VMValuer, error) // возвращает результат выражения с другим значением } - // TODO: реализовать VMUnarer во всех типах с унарными операциями - // VMUnarer может выполнить унарную операцию над свои значением VMUnarer interface { VMValuer EvalUnOp(rune) (VMValuer, error) // возвращает результат выражения с другим значением } - // TODO: реализовать VMConverter во всех типах, кроме функций - // VMConverter может конвертироваться в тип reflect.Type VMConverter interface { VMValuer diff --git a/core/coretypes.go b/core/coretypes.go index 30b7eef..6eabced 100644 --- a/core/coretypes.go +++ b/core/coretypes.go @@ -160,10 +160,94 @@ func (x VMNilType) BinaryType() VMBinaryType { return VMNIL } -// TODO: маршалинг Nil,NULL и сравнение их со значениями - var VMNil = VMNilType{} +// EvalBinOp сравнивает два значения или выполняет бинарную операцию +func (x VMNilType) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { + switch op { + case ADD: + return VMNil, errors.New("Операция между значениями невозможна") + case SUB: + return VMNil, errors.New("Операция между значениями невозможна") + case MUL: + return VMNil, errors.New("Операция между значениями невозможна") + case QUO: + return VMNil, errors.New("Операция между значениями невозможна") + case REM: + return VMNil, errors.New("Операция между значениями невозможна") + case EQL: + switch y.(type) { + case VMNullType, VMNilType: + return VMBool(true), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case NEQ: + switch y.(type) { + case VMNullType, VMNilType: + return VMBool(false), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case GTR: + return VMNil, errors.New("Операция между значениями невозможна") + case GEQ: + return VMNil, errors.New("Операция между значениями невозможна") + case LSS: + return VMNil, errors.New("Операция между значениями невозможна") + case LEQ: + return VMNil, errors.New("Операция между значениями невозможна") + case OR: + return VMNil, errors.New("Операция между значениями невозможна") + case LOR: + return VMNil, errors.New("Операция между значениями невозможна") + case AND: + return VMNil, errors.New("Операция между значениями невозможна") + case LAND: + return VMNil, errors.New("Операция между значениями невозможна") + case POW: + return VMNil, errors.New("Операция между значениями невозможна") + case SHR: + return VMNil, errors.New("Операция между значениями невозможна") + case SHL: + return VMNil, errors.New("Операция между значениями невозможна") + } + return VMNil, errors.New("Неизвестная операция") +} + +func (x VMNilType) MarshalBinary() ([]byte, error) { + return []byte{}, nil +} + +func (x *VMNilType) UnmarshalBinary(data []byte) error { + *x = VMNil + return nil +} + +func (x VMNilType) GobEncode() ([]byte, error) { + return x.MarshalBinary() +} + +func (x *VMNilType) GobDecode(data []byte) error { + return x.UnmarshalBinary(data) +} + +func (x VMNilType) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +func (x *VMNilType) UnmarshalText(data []byte) error { + *x = VMNil + return nil +} + +func (x VMNilType) MarshalJSON() ([]byte, error) { + return []byte("null"), nil +} + +func (x *VMNilType) UnmarshalJSON(data []byte) error { + *x = VMNil + return nil +} + // тип NULL type VMNullType struct{} @@ -178,6 +262,92 @@ func (x VMNullType) BinaryType() VMBinaryType { var VMNullVar = VMNullType{} +// EvalBinOp сравнивает два значения или выполняет бинарную операцию +func (x VMNullType) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { + switch op { + case ADD: + return VMNil, errors.New("Операция между значениями невозможна") + case SUB: + return VMNil, errors.New("Операция между значениями невозможна") + case MUL: + return VMNil, errors.New("Операция между значениями невозможна") + case QUO: + return VMNil, errors.New("Операция между значениями невозможна") + case REM: + return VMNil, errors.New("Операция между значениями невозможна") + case EQL: + switch y.(type) { + case VMNullType, VMNilType: + return VMBool(true), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case NEQ: + switch y.(type) { + case VMNullType, VMNilType: + return VMBool(false), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case GTR: + return VMNil, errors.New("Операция между значениями невозможна") + case GEQ: + return VMNil, errors.New("Операция между значениями невозможна") + case LSS: + return VMNil, errors.New("Операция между значениями невозможна") + case LEQ: + return VMNil, errors.New("Операция между значениями невозможна") + case OR: + return VMNil, errors.New("Операция между значениями невозможна") + case LOR: + return VMNil, errors.New("Операция между значениями невозможна") + case AND: + return VMNil, errors.New("Операция между значениями невозможна") + case LAND: + return VMNil, errors.New("Операция между значениями невозможна") + case POW: + return VMNil, errors.New("Операция между значениями невозможна") + case SHR: + return VMNil, errors.New("Операция между значениями невозможна") + case SHL: + return VMNil, errors.New("Операция между значениями невозможна") + } + return VMNil, errors.New("Неизвестная операция") +} + +func (x VMNullType) MarshalBinary() ([]byte, error) { + return []byte{}, nil +} + +func (x *VMNullType) UnmarshalBinary(data []byte) error { + *x = VMNullVar + return nil +} + +func (x VMNullType) GobEncode() ([]byte, error) { + return x.MarshalBinary() +} + +func (x *VMNullType) GobDecode(data []byte) error { + return x.UnmarshalBinary(data) +} + +func (x VMNullType) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +func (x *VMNullType) UnmarshalText(data []byte) error { + *x = VMNullVar + return nil +} + +func (x VMNullType) MarshalJSON() ([]byte, error) { + return []byte("null"), nil +} + +func (x *VMNullType) UnmarshalJSON(data []byte) error { + *x = VMNullVar + return nil +} + // HashBytes хэширует байты по алгоритму SipHash-2-4 func HashBytes(buf []byte) uint64 { @@ -282,6 +452,8 @@ func VMValuerFromJSON(s string) (VMValuer, error) { return VMSliceFromJson(s) case map[string]interface{}: return VMStringMapFromJson(s) + case nil: + return VMNil, nil default: return VMNil, errors.New("Невозможно определить значение") }