diff --git a/core/core.go b/core/core.go index 28b9f0c..099580a 100644 --- a/core/core.go +++ b/core/core.go @@ -143,8 +143,6 @@ func Import(env *Env) *Env { return errors.New("Должно быть число секунд (допустимо с дробной частью)") })) - // TODO: добавить операции по умножению длительностей VMTimeDuration на числа VMNumberer.Decimal - env.DefineS("длительностьнаносекунды", VMNanosecond) env.DefineS("длительностьмикросекунды", VMMicrosecond) env.DefineS("длительностьмиллисекунды", VMMillisecond) diff --git a/core/coretime.go b/core/coretime.go index d59fcd9..9ff3d1c 100644 --- a/core/coretime.go +++ b/core/coretime.go @@ -157,6 +157,113 @@ func fmtInt(buf []byte, v uint64) int { return w } +// EvalBinOp сравнивает два значения или выполняет бинарную операцию +func (x VMTimeDuration) EvalBinOp(op VMOperation, y VMOperationer) (VMValuer, error) { + switch op { + case ADD: + switch yy := y.(type) { + case VMTimeDuration: + return VMTimeDuration(int64(x) + int64(yy)), nil + case VMTime: + return yy.Add(x), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case SUB: + switch yy := y.(type) { + case VMTimeDuration: + return VMTimeDuration(int64(x) - int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case MUL: + switch yy := y.(type) { + case VMInt: + return VMTimeDuration(int64(x) * int64(yy)), nil + case VMDecimal: + return VMTimeDuration(yy.Mul(NewVMDecimalFromInt64(int64(x))).Int()), nil + case VMTimeDuration: + return VMTimeDuration(int64(x) * int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case QUO: + switch yy := y.(type) { + case VMTimeDuration: + return VMTimeDuration(int64(x) / int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case REM: + switch yy := y.(type) { + case VMTimeDuration: + return VMTimeDuration(int64(x) % int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case EQL: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) == int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case NEQ: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) != int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case GTR: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) > int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case GEQ: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) >= int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case LSS: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) < int64(yy)), nil + } + return VMNil, errors.New("Операция между значениями невозможна") + case LEQ: + switch yy := y.(type) { + case VMTimeDuration: + return VMBool(int64(x) <= int64(yy)), nil + } + 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 VMTimeDuration) ConvertToType(nt reflect.Type) (VMValuer, error) { + switch nt { + case ReflectVMString: + return VMString(x.String()), nil + case ReflectVMInt: + return VMInt(int64(x)), nil + case ReflectVMTimeDuration: + return x, nil + case ReflectVMDecimal: + return NewVMDecimalFromInt64(int64(x)), nil + } + return VMNil, errors.New("Приведение к типу невозможно") +} + func (x VMTimeDuration) MarshalBinary() ([]byte, error) { var buf bytes.Buffer binary.Write(&buf, binary.LittleEndian, int64(x)) diff --git a/main_test.go b/main_test.go index ae0366e..e6dfc42 100644 --- a/main_test.go +++ b/main_test.go @@ -44,9 +44,10 @@ func TestRun(t *testing.T) { # массив с вложенным массивом со структурой и датой а=[2, 1, [3, {"привет":2, "а":1}, Дата("2017-08-17T09:23:00+03:00")], 4] - а[2][1].а=Дата("2017-08-17T09:23:00+03:00") + Сообщить("Исходное:", а, а[2][1].а) + а[2][1].а=Дата("2017-08-17T09:23:00+03:00")+ДлительностьДня*5 # приведение массива или структуры к типу "строка" означает сериализацию в json, со всеми вложенными массивами и структурами - Сообщить(а, а[2][1].а) + Сообщить("Измененное:", а, а[2][1].а) Сообщить(Строка(а)) Сообщить("Ключи в порядке сортировки:", Ключи(а[2][1])) # приведение строки к массиву или структуре означает десериализацию из json diff --git a/parser/optimize.go b/parser/optimize.go index cba03d6..998e0c8 100644 --- a/parser/optimize.go +++ b/parser/optimize.go @@ -4,8 +4,6 @@ import ( "github.com/covrom/gonec/ast" ) -// TODO: переделать на универсальную рефлексию перебора полей структур - func ConstFolding(inast ast.Stmts) ast.Stmts { for i := range inast { inast[i].Simplify() @@ -13,451 +11,3 @@ func ConstFolding(inast ast.Stmts) ast.Stmts { return inast } -// func simplifyExprFolding(expr ast.Expr) ast.Expr { -// none := reflect.Value{} -// switch e := expr.(type) { -// case *ast.BinOpExpr: -// // упрощаем подвыражения -// for i2, e2 := range e.Lhss { -// e.Lhss[i2] = simplifyExprFolding(e2) -// } -// for i2, e2 := range e.Rhss { -// e.Rhss[i2] = simplifyExprFolding(e2) -// } -// // e.Lhs = simplifyExprFolding(e.Lhs) -// // e.Rhs = simplifyExprFolding(e.Rhs) -// // если с обеих сторон по одному выражению, и они вычисляемые, то вычисляем результат операции -// if len(e.Lhss) == 1 && len(e.Rhss) == 1 { -// r1 := exprAsValue(e.Lhss[0]) -// r2 := exprAsValue(e.Rhss[0]) -// if r1.IsValid() && r2.IsValid() { -// r, err := EvalBinOp(e.Operator, r1, r2, none) -// if err == nil && r.IsValid() { -// // log.Println("Set native value!") -// return &ast.NativeExpr{Value: r} -// } -// } -// } -// return e -// case *ast.LetExpr: -// e.Lhs = simplifyExprFolding(e.Lhs) -// e.Rhs = simplifyExprFolding(e.Rhs) -// return e -// case *ast.UnaryExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// v := exprAsValue(e.Expr) -// if v.IsValid() { -// r, err := EvalUnOp(e.Operator, v, none) -// if err == nil && r.IsValid() { -// return &ast.NativeExpr{Value: r} -// } -// } -// return e -// case *ast.ParenExpr: -// e.SubExpr = simplifyExprFolding(e.SubExpr) -// v := exprAsValue(e.SubExpr) -// if v.IsValid() { -// return &ast.NativeExpr{Value: v} -// } -// return e -// case *ast.TernaryOpExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// e.Lhs = simplifyExprFolding(e.Lhs) -// e.Rhs = simplifyExprFolding(e.Rhs) - -// v := exprAsValue(e.Expr) -// r1 := exprAsValue(e.Lhs) -// r2 := exprAsValue(e.Rhs) - -// if v.IsValid() && r1.IsValid() && r2.IsValid() && v.Kind() == reflect.Bool { -// if ToBool(v) { -// return &ast.NativeExpr{Value: r1} -// } else { -// return &ast.NativeExpr{Value: r2} -// } -// } -// return e -// case *ast.ArrayExpr: -// a := make([]interface{}, len(e.Exprs)) -// waserrors := false -// for i := range e.Exprs { -// e.Exprs[i] = simplifyExprFolding(e.Exprs[i]) -// arg := exprAsValue(e.Exprs[i]) -// if arg.IsValid() { -// a[i] = arg.Interface() -// } else { -// waserrors = true -// } -// } -// if waserrors { -// return e -// } else { -// return &ast.NativeExpr{Value: reflect.ValueOf(core.VMSlice(a))} -// } -// case *ast.MapExpr: -// waserrors := false -// m := make(map[string]interface{}) -// for k, v := range e.MapExpr { -// vv := simplifyExprFolding(v) -// e.MapExpr[k] = vv -// arg := exprAsValue(vv) -// if arg.IsValid() { -// m[k] = arg.Interface() -// } else { -// waserrors = true -// } -// } -// if waserrors { -// return e -// } else { -// return &ast.NativeExpr{Value: reflect.ValueOf(core.VMStringMap(m))} -// } -// case *ast.CallExpr: -// for i := range e.SubExprs { -// e.SubExprs[i] = simplifyExprFolding(e.SubExprs[i]) -// } -// return e -// case *ast.AnonCallExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// for i := range e.SubExprs { -// e.SubExprs[i] = simplifyExprFolding(e.SubExprs[i]) -// } -// return e -// case *ast.ItemExpr: -// e.Value = simplifyExprFolding(e.Value) -// e.Index = simplifyExprFolding(e.Index) -// return e -// // case *ast.LetsExpr: -// // for i2, e2 := range e.Lhss { -// // e.Lhss[i2] = simplifyExprFolding(e2) -// // } -// // for i2, e2 := range e.Rhss { -// // e.Rhss[i2] = simplifyExprFolding(e2) -// // } -// // return e -// case *ast.AssocExpr: -// e.Lhs = simplifyExprFolding(e.Lhs) -// e.Rhs = simplifyExprFolding(e.Rhs) -// return e -// case *ast.ChanExpr: -// e.Lhs = simplifyExprFolding(e.Lhs) -// e.Rhs = simplifyExprFolding(e.Rhs) -// return e -// case *ast.MakeArrayExpr: -// e.CapExpr = simplifyExprFolding(e.CapExpr) -// e.LenExpr = simplifyExprFolding(e.LenExpr) -// return e -// case *ast.TypeCast: -// e.CastExpr = simplifyExprFolding(e.CastExpr) -// e.TypeExpr = simplifyExprFolding(e.TypeExpr) -// return e -// case *ast.MakeExpr: -// e.TypeExpr = simplifyExprFolding(e.TypeExpr) -// return e -// case *ast.MakeChanExpr: -// e.SizeExpr = simplifyExprFolding(e.SizeExpr) -// return e -// case *ast.PairExpr: -// e.Value = simplifyExprFolding(e.Value) -// return e -// case *ast.AddrExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// return e -// case *ast.DerefExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// return e -// case *ast.MemberExpr: -// e.Expr = simplifyExprFolding(e.Expr) -// return e -// case *ast.SliceExpr: -// e.Value = simplifyExprFolding(e.Value) -// e.Begin = simplifyExprFolding(e.Begin) -// e.End = simplifyExprFolding(e.End) -// return e -// case *ast.FuncExpr: -// e.Stmts = ConstFolding(e.Stmts) -// return e -// default: -// // одиночные значения - преобразовываем в нативные -// r := exprAsValue(e) -// if r.IsValid() { -// return &ast.NativeExpr{Value: r} -// } -// } -// // если не преобразовали - вернем исходное выражение -// return expr -// } - -// func exprAsValue(expr ast.Expr) (r reflect.Value) { -// none := reflect.Value{} -// var err error -// switch e := expr.(type) { -// case *ast.NativeExpr: -// r = e.Value -// case *ast.ConstExpr: -// r = InvokeConst(e.Value, none) -// case *ast.NumberExpr: -// r, err = InvokeNumber(e.Lit, none) -// if err != nil { -// // ошибки пропускаем -// return none -// } -// case *ast.StringExpr: -// r = reflect.ValueOf(e.Lit) -// } -// return -// } - -// func InvokeConst(v string, defval reflect.Value) reflect.Value { -// switch strings.ToLower(v) { -// case "истина": -// return reflect.ValueOf(true) -// case "ложь": -// return reflect.ValueOf(false) -// case "null": -// return reflect.ValueOf(ast.NullVar) -// } -// return defval -// } - -// func InvokeNumber(lit string, defval reflect.Value) (reflect.Value, error) { -// if strings.Contains(lit, ".") || strings.Contains(lit, "e") { -// v, err := strconv.ParseFloat(lit, 64) -// if err != nil { -// return defval, err -// } -// return reflect.ValueOf(float64(v)), nil -// } -// var i int64 -// var err error -// if strings.HasPrefix(lit, "0x") { -// i, err = strconv.ParseInt(lit[2:], 16, 64) -// } else { -// i, err = strconv.ParseInt(lit, 10, 64) -// } -// if err != nil { -// return defval, err -// } -// return reflect.ValueOf(i), nil -// } - -// func EvalUnOp(op string, v, defval reflect.Value) (reflect.Value, error) { -// switch op { -// case "-": -// if v.Kind() == reflect.Float64 { -// return reflect.ValueOf(-v.Float()), nil -// } -// return reflect.ValueOf(-v.Int()), nil -// case "^": -// return reflect.ValueOf(^ToInt64(v)), nil -// case "!": -// return reflect.ValueOf(!ToBool(v)), nil -// default: -// return defval, fmt.Errorf("Неизвестный оператор") -// } -// } - -// func ToBool(v reflect.Value) bool { -// if v.Kind() == reflect.Interface { -// v = v.Elem() -// } - -// switch v.Kind() { -// case reflect.Float32, reflect.Float64: -// return v.Float() != 0.0 -// case reflect.Int, reflect.Int32, reflect.Int64: -// return v.Int() != 0 -// case reflect.Bool: -// return v.Bool() -// case reflect.String: -// vlow := strings.ToLower(v.String()) -// if vlow == "true" || vlow == "истина" { -// return true -// } -// if ToInt64(v) != 0 { -// return true -// } -// } -// return false -// } - -// func ToInt64(v reflect.Value) int64 { -// if v.Kind() == reflect.Interface { -// v = v.Elem() -// } -// switch v.Kind() { -// case reflect.Float32, reflect.Float64: -// return int64(v.Float()) -// case reflect.Int, reflect.Int32, reflect.Int64: -// return v.Int() -// case reflect.String: -// s := v.String() -// var i int64 -// var err error -// if strings.HasPrefix(s, "0x") { -// i, err = strconv.ParseInt(s, 16, 64) -// } else { -// i, err = strconv.ParseInt(s, 10, 64) -// } -// if err == nil { -// return int64(i) -// } -// } -// return 0 -// } - -// func ToString(v reflect.Value) string { -// if v.Kind() == reflect.Interface { -// v = v.Elem() -// } -// if v.Kind() == reflect.String { -// return v.String() -// } -// if !v.IsValid() { -// return "Неопределено" -// } -// if v.Kind() == reflect.Bool { -// if v.Bool() { -// return "true" // для совместимости -// } else { -// return "false" // для совместимости -// } -// } -// return fmt.Sprint(v.Interface()) -// } - -// func ToFloat64(v reflect.Value) float64 { -// if v.Kind() == reflect.Interface { -// v = v.Elem() -// } -// switch v.Kind() { -// case reflect.Float32, reflect.Float64: -// return v.Float() -// case reflect.Int, reflect.Int32, reflect.Int64: -// return float64(v.Int()) -// } -// return 0.0 -// } - -// func IsNil(v reflect.Value) bool { -// if !v.IsValid() || v.Kind().String() == "unsafe.Pointer" { -// return true -// } -// if (v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr) && v.IsNil() { -// return true -// } -// return false -// } - -// func IsNum(v reflect.Value) bool { -// switch v.Kind() { -// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64: -// return true -// } -// return false -// } - -// // equal returns true when lhsV and rhsV is same value. -// func Equal(lhsV, rhsV reflect.Value) bool { -// lhsIsNil, rhsIsNil := IsNil(lhsV), IsNil(rhsV) -// if lhsIsNil && rhsIsNil { -// return true -// } -// if (!lhsIsNil && rhsIsNil) || (lhsIsNil && !rhsIsNil) { -// return false -// } -// if lhsV.Kind() == reflect.Interface || lhsV.Kind() == reflect.Ptr { -// lhsV = lhsV.Elem() -// } -// if rhsV.Kind() == reflect.Interface || rhsV.Kind() == reflect.Ptr { -// rhsV = rhsV.Elem() -// } -// if !lhsV.IsValid() || !rhsV.IsValid() { -// return true -// } -// if IsNum(lhsV) && IsNum(rhsV) { -// if rhsV.Type().ConvertibleTo(lhsV.Type()) { -// rhsV = rhsV.Convert(lhsV.Type()) -// } -// } -// if lhsV.CanInterface() && rhsV.CanInterface() { -// return reflect.DeepEqual(lhsV.Interface(), rhsV.Interface()) -// } -// return reflect.DeepEqual(lhsV, rhsV) -// } - -// func EvalBinOp(op string, lhsV, rhsV, defval reflect.Value) (reflect.Value, error) { -// switch op { - -// // TODO: расширить возможные варианты - -// case "+": -// if lhsV.Kind() == reflect.String || rhsV.Kind() == reflect.String { -// return reflect.ValueOf(ToString(lhsV) + ToString(rhsV)), nil -// } -// if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() != reflect.Array && rhsV.Kind() != reflect.Slice) { -// return reflect.Append(lhsV, rhsV), nil -// } -// if (lhsV.Kind() == reflect.Array || lhsV.Kind() == reflect.Slice) && (rhsV.Kind() == reflect.Array || rhsV.Kind() == reflect.Slice) { -// return reflect.AppendSlice(lhsV, rhsV), nil -// } -// if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 { -// return reflect.ValueOf(ToFloat64(lhsV) + ToFloat64(rhsV)), nil -// } -// return reflect.ValueOf(ToInt64(lhsV) + ToInt64(rhsV)), nil -// case "-": -// if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 { -// return reflect.ValueOf(ToFloat64(lhsV) - ToFloat64(rhsV)), nil -// } -// return reflect.ValueOf(ToInt64(lhsV) - ToInt64(rhsV)), nil -// case "*": -// if lhsV.Kind() == reflect.String && (rhsV.Kind() == reflect.Int || rhsV.Kind() == reflect.Int32 || rhsV.Kind() == reflect.Int64) { -// return reflect.ValueOf(strings.Repeat(ToString(lhsV), int(ToInt64(rhsV)))), nil -// } -// if lhsV.Kind() == reflect.Float64 || rhsV.Kind() == reflect.Float64 { -// return reflect.ValueOf(ToFloat64(lhsV) * ToFloat64(rhsV)), nil -// } -// return reflect.ValueOf(ToInt64(lhsV) * ToInt64(rhsV)), nil -// case "/": -// return reflect.ValueOf(ToFloat64(lhsV) / ToFloat64(rhsV)), nil -// case "%": -// return reflect.ValueOf(ToInt64(lhsV) % ToInt64(rhsV)), nil -// case "==": -// return reflect.ValueOf(Equal(lhsV, rhsV)), nil -// case "!=": -// return reflect.ValueOf(Equal(lhsV, rhsV) == false), nil -// case ">": -// return reflect.ValueOf(ToFloat64(lhsV) > ToFloat64(rhsV)), nil -// case ">=": -// return reflect.ValueOf(ToFloat64(lhsV) >= ToFloat64(rhsV)), nil -// case "<": -// return reflect.ValueOf(ToFloat64(lhsV) < ToFloat64(rhsV)), nil -// case "<=": -// return reflect.ValueOf(ToFloat64(lhsV) <= ToFloat64(rhsV)), nil -// case "|": -// return reflect.ValueOf(ToInt64(lhsV) | ToInt64(rhsV)), nil -// case "||": -// if ToBool(lhsV) { -// return lhsV, nil -// } -// return rhsV, nil -// case "&": -// return reflect.ValueOf(ToInt64(lhsV) & ToInt64(rhsV)), nil -// case "&&": -// if ToBool(lhsV) { -// return rhsV, nil -// } -// return lhsV, nil -// case "**": -// if lhsV.Kind() == reflect.Float64 { -// return reflect.ValueOf(math.Pow(ToFloat64(lhsV), ToFloat64(rhsV))), nil -// } -// return reflect.ValueOf(int64(math.Pow(ToFloat64(lhsV), ToFloat64(rhsV)))), nil -// case ">>": -// return reflect.ValueOf(ToInt64(lhsV) >> uint64(ToInt64(rhsV))), nil -// case "<<": -// return reflect.ValueOf(ToInt64(lhsV) << uint64(ToInt64(rhsV))), nil -// default: -// return defval, fmt.Errorf("Неизвестный оператор") -// } -// }