mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	Bugfix/#295 arithmetic operators (#298)
* Some work * Updated Add operator * Updated Subtract operator * Updated Subtract operator tests * Added tests for multiplication * Added division * Updated the rest of operators
This commit is contained in:
		| @@ -2,6 +2,7 @@ package operators | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| @@ -88,9 +89,62 @@ func Not(left, _ core.Value) core.Value { | ||||
| 	return values.True | ||||
| } | ||||
|  | ||||
| func ToNumberOrString(input core.Value) core.Value { | ||||
| 	switch input.Type() { | ||||
| 	case types.Int, types.Float, types.String: | ||||
| 		return input | ||||
| 	default: | ||||
| 		return values.ToInt(input) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ToNumberOnly(input core.Value) core.Value { | ||||
| 	switch input.Type() { | ||||
| 	case types.Int, types.Float: | ||||
| 		return input | ||||
| 	case types.String: | ||||
| 		if strings.Contains(input.String(), ".") { | ||||
| 			return values.ToFloat(input) | ||||
| 		} | ||||
|  | ||||
| 		return values.ToInt(input) | ||||
| 	case types.Array: | ||||
| 		arr := input.(*values.Array) | ||||
| 		length := arr.Length() | ||||
|  | ||||
| 		if length == 0 { | ||||
| 			return values.ZeroInt | ||||
| 		} | ||||
|  | ||||
| 		i := values.ZeroInt | ||||
| 		f := values.ZeroFloat | ||||
|  | ||||
| 		for y := values.Int(0); y < length; y++ { | ||||
| 			out := ToNumberOnly(arr.Get(y)) | ||||
|  | ||||
| 			if out.Type() == types.Int { | ||||
| 				i += out.(values.Int) | ||||
| 			} else { | ||||
| 				f += out.(values.Float) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if f == 0 { | ||||
| 			return i | ||||
| 		} | ||||
|  | ||||
| 		return values.Float(i) + f | ||||
| 	default: | ||||
| 		return values.ToInt(input) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Adds numbers | ||||
| // Concats strings | ||||
| func Add(left, right core.Value) core.Value { | ||||
| // Concatenates strings | ||||
| func Add(inputL, inputR core.Value) core.Value { | ||||
| 	left := ToNumberOrString(inputL) | ||||
| 	right := ToNumberOrString(inputR) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Int) | ||||
| @@ -126,7 +180,10 @@ func Add(left, right core.Value) core.Value { | ||||
| 	return values.NewString(left.String() + right.String()) | ||||
| } | ||||
|  | ||||
| func Subtract(left, right core.Value) core.Value { | ||||
| func Subtract(inputL, inputR core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
| 	right := ToNumberOnly(inputR) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Int) | ||||
| @@ -162,7 +219,10 @@ func Subtract(left, right core.Value) core.Value { | ||||
| 	return values.ZeroInt | ||||
| } | ||||
|  | ||||
| func Multiply(left, right core.Value) core.Value { | ||||
| func Multiply(inputL, inputR core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
| 	right := ToNumberOnly(inputR) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Int) | ||||
| @@ -198,20 +258,31 @@ func Multiply(left, right core.Value) core.Value { | ||||
| 	return values.ZeroInt | ||||
| } | ||||
|  | ||||
| func Divide(left, right core.Value) core.Value { | ||||
| func Divide(inputL, inputR core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
| 	right := ToNumberOnly(inputR) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Int) | ||||
| 			r := right.(values.Int) | ||||
| 			l := values.Float(left.(values.Int)) | ||||
| 			r := values.Float(right.(values.Int)) | ||||
|  | ||||
| 			if r == 0.0 { | ||||
| 				panic("divide by zero") | ||||
| 			} | ||||
|  | ||||
| 			return l / r | ||||
| 		} | ||||
|  | ||||
| 		if right.Type() == types.Float { | ||||
| 			l := left.(values.Int) | ||||
| 			l := values.Float(left.(values.Int)) | ||||
| 			r := right.(values.Float) | ||||
|  | ||||
| 			return values.Float(l) / r | ||||
| 			if r == 0.0 { | ||||
| 				panic("divide by zero") | ||||
| 			} | ||||
|  | ||||
| 			return l / r | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -220,21 +291,32 @@ func Divide(left, right core.Value) core.Value { | ||||
| 			l := left.(values.Float) | ||||
| 			r := right.(values.Float) | ||||
|  | ||||
| 			if r == 0.0 { | ||||
| 				panic("divide by zero") | ||||
| 			} | ||||
|  | ||||
| 			return l / r | ||||
| 		} | ||||
|  | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Float) | ||||
| 			r := right.(values.Int) | ||||
| 			r := values.Float(right.(values.Int)) | ||||
|  | ||||
| 			return l / values.Float(r) | ||||
| 			if r == 0.0 { | ||||
| 				panic("divide by zero") | ||||
| 			} | ||||
|  | ||||
| 			return l / r | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return values.ZeroInt | ||||
| } | ||||
|  | ||||
| func Modulus(left, right core.Value) core.Value { | ||||
| func Modulus(inputL, inputR core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
| 	right := ToNumberOnly(inputR) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		if right.Type() == types.Int { | ||||
| 			l := left.(values.Int) | ||||
| @@ -270,7 +352,9 @@ func Modulus(left, right core.Value) core.Value { | ||||
| 	return values.ZeroInt | ||||
| } | ||||
|  | ||||
| func Increment(left, _ core.Value) core.Value { | ||||
| func Increment(inputL, _ core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		l := left.(values.Int) | ||||
|  | ||||
| @@ -286,7 +370,9 @@ func Increment(left, _ core.Value) core.Value { | ||||
| 	return values.None | ||||
| } | ||||
|  | ||||
| func Decrement(left, _ core.Value) core.Value { | ||||
| func Decrement(inputL, _ core.Value) core.Value { | ||||
| 	left := ToNumberOnly(inputL) | ||||
|  | ||||
| 	if left.Type() == types.Int { | ||||
| 		l := left.(values.Int) | ||||
|  | ||||
| @@ -303,31 +389,27 @@ func Decrement(left, _ core.Value) core.Value { | ||||
| } | ||||
|  | ||||
| func Negative(value, _ core.Value) core.Value { | ||||
| 	err := core.ValidateType(value, types.Int, types.Float) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.ZeroInt | ||||
| 	} | ||||
|  | ||||
| 	if value.Type() == types.Int { | ||||
| 		return -value.(values.Int) | ||||
| 	} | ||||
|  | ||||
| 	return -value.(values.Float) | ||||
| 	if value.Type() == types.Float { | ||||
| 		return -value.(values.Float) | ||||
| 	} | ||||
|  | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| func Positive(value, _ core.Value) core.Value { | ||||
| 	err := core.ValidateType(value, types.Int, types.Float) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.ZeroInt | ||||
| 	} | ||||
|  | ||||
| 	if value.Type() == types.Int { | ||||
| 		return +value.(values.Int) | ||||
| 	} | ||||
|  | ||||
| 	return +value.(values.Float) | ||||
| 	if value.Type() == types.Float { | ||||
| 		return +value.(values.Float) | ||||
| 	} | ||||
|  | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| func ToBoolean(value, _ core.Value) core.Value { | ||||
|   | ||||
							
								
								
									
										1022
									
								
								pkg/runtime/expressions/operators/operator_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1022
									
								
								pkg/runtime/expressions/operators/operator_test.go
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -14,6 +14,8 @@ import ( | ||||
|  | ||||
| type Float float64 | ||||
|  | ||||
| var NaN = Float(math.NaN()) | ||||
|  | ||||
| const ZeroFloat = Float(0.0) | ||||
|  | ||||
| func NewFloat(input float64) Float { | ||||
| @@ -80,7 +82,7 @@ func (t Float) Type() core.Type { | ||||
| } | ||||
|  | ||||
| func (t Float) String() string { | ||||
| 	return fmt.Sprintf("%f", t) | ||||
| 	return fmt.Sprintf("%v", float64(t)) | ||||
| } | ||||
|  | ||||
| func (t Float) Compare(other core.Value) int64 { | ||||
|   | ||||
| @@ -235,58 +235,116 @@ func ToBoolean(input core.Value) core.Value { | ||||
| 	switch input.Type() { | ||||
| 	case types.Boolean: | ||||
| 		return input | ||||
| 	case types.None: | ||||
| 		return False | ||||
| 	case types.String: | ||||
| 		return NewBoolean(input.String() != "") | ||||
| 		return NewBoolean(input.(String) != "") | ||||
| 	case types.Int: | ||||
| 		return NewBoolean(input.(Int) != 0) | ||||
| 	case types.Float: | ||||
| 		return NewBoolean(input.(Float) != 0) | ||||
| 	case types.DateTime: | ||||
| 		return NewBoolean(!input.(DateTime).IsZero()) | ||||
| 	case types.None: | ||||
| 		return False | ||||
| 	default: | ||||
| 		return True | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ToFloat(input core.Value) (Float, error) { | ||||
| func ToFloat(input core.Value) Float { | ||||
| 	switch val := input.(type) { | ||||
| 	case Float: | ||||
| 		return val, nil | ||||
| 		return val | ||||
| 	case Int: | ||||
| 		return Float(val), nil | ||||
| 		return Float(val) | ||||
| 	case String: | ||||
| 		i, err := strconv.ParseFloat(string(val), 64) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return ZeroFloat, err | ||||
| 			return ZeroFloat | ||||
| 		} | ||||
|  | ||||
| 		return Float(i), nil | ||||
| 		return Float(i) | ||||
| 	case Boolean: | ||||
| 		if val { | ||||
| 			return Float(1) | ||||
| 		} | ||||
|  | ||||
| 		return Float(0) | ||||
| 	case DateTime: | ||||
| 		dt := input.(DateTime) | ||||
|  | ||||
| 		if dt.IsZero() { | ||||
| 			return ZeroFloat | ||||
| 		} | ||||
|  | ||||
| 		return NewFloat(float64(dt.Unix())) | ||||
| 	case *Array: | ||||
| 		length := val.Length() | ||||
|  | ||||
| 		if length == 0 { | ||||
| 			return ZeroFloat | ||||
| 		} | ||||
|  | ||||
| 		res := ZeroFloat | ||||
|  | ||||
| 		for i := Int(0); i < length; i++ { | ||||
| 			res += ToFloat(val.Get(i)) | ||||
| 		} | ||||
|  | ||||
| 		return res | ||||
| 	default: | ||||
| 		return ZeroFloat, core.TypeError(input.Type(), types.Int, types.Float, types.String) | ||||
| 		return ZeroFloat | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ToInt(input core.Value) (Int, error) { | ||||
| func ToInt(input core.Value) Int { | ||||
| 	switch val := input.(type) { | ||||
| 	case Int: | ||||
| 		return val, nil | ||||
| 		return val | ||||
| 	case Float: | ||||
| 		return Int(val), nil | ||||
| 		return Int(val) | ||||
| 	case String: | ||||
| 		i, err := strconv.ParseInt(string(val), 10, 64) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return ZeroInt, err | ||||
| 			return ZeroInt | ||||
| 		} | ||||
|  | ||||
| 		return Int(i), nil | ||||
| 		return Int(i) | ||||
| 	case Boolean: | ||||
| 		if val { | ||||
| 			return Int(1) | ||||
| 		} | ||||
|  | ||||
| 		return Int(0) | ||||
| 	case DateTime: | ||||
| 		dt := input.(DateTime) | ||||
|  | ||||
| 		if dt.IsZero() { | ||||
| 			return ZeroInt | ||||
| 		} | ||||
|  | ||||
| 		return NewInt(int(dt.Unix())) | ||||
| 	case *Array: | ||||
| 		length := val.Length() | ||||
|  | ||||
| 		if length == 0 { | ||||
| 			return ZeroInt | ||||
| 		} | ||||
|  | ||||
| 		res := ZeroInt | ||||
|  | ||||
| 		for i := Int(0); i < length; i++ { | ||||
| 			res += ToInt(val.Get(i)) | ||||
| 		} | ||||
|  | ||||
| 		return res | ||||
| 	default: | ||||
| 		return ZeroInt, core.TypeError(input.Type(), types.Int, types.Float, types.String) | ||||
| 		return ZeroInt | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ToArray(ctx context.Context, input core.Value) (core.Value, error) { | ||||
| func ToArray(ctx context.Context, input core.Value) core.Value { | ||||
| 	switch value := input.(type) { | ||||
| 	case Boolean, | ||||
| 		Int, | ||||
| @@ -294,9 +352,9 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) { | ||||
| 		String, | ||||
| 		DateTime: | ||||
|  | ||||
| 		return NewArrayWith(value), nil | ||||
| 		return NewArrayWith(value) | ||||
| 	case *Array: | ||||
| 		return value.Copy(), nil | ||||
| 		return value.Copy() | ||||
| 	case *Object: | ||||
| 		arr := NewArray(int(value.Length())) | ||||
|  | ||||
| @@ -306,12 +364,12 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) { | ||||
| 			return true | ||||
| 		}) | ||||
|  | ||||
| 		return arr, nil | ||||
| 		return arr | ||||
| 	case core.Iterable: | ||||
| 		iterator, err := value.Iterate(ctx) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return None, err | ||||
| 			return None | ||||
| 		} | ||||
|  | ||||
| 		arr := NewArray(10) | ||||
| @@ -320,7 +378,7 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) { | ||||
| 			val, _, err := iterator.Next(ctx) | ||||
|  | ||||
| 			if err != nil { | ||||
| 				return None, err | ||||
| 				return None | ||||
| 			} | ||||
|  | ||||
| 			if val == None { | ||||
| @@ -330,9 +388,9 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) { | ||||
| 			arr.Push(val) | ||||
| 		} | ||||
|  | ||||
| 		return arr, nil | ||||
| 		return arr | ||||
| 	default: | ||||
| 		return NewArray(0), nil | ||||
| 		return NewArray(0) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -372,3 +430,9 @@ func MapHash(input map[string]core.Value) uint64 { | ||||
|  | ||||
| 	return h.Sum64() | ||||
| } | ||||
|  | ||||
| func IsNumber(input core.Value) Boolean { | ||||
| 	t := input.Type() | ||||
|  | ||||
| 	return t == types.Int || t == types.Float | ||||
| } | ||||
|   | ||||
| @@ -225,41 +225,58 @@ func TestHelpers(t *testing.T) { | ||||
| 		Convey("ToFloat", func() { | ||||
| 			Convey("Should convert Int", func() { | ||||
| 				input := values.NewInt(100) | ||||
| 				output, err := values.ToFloat(input) | ||||
| 				output := values.ToFloat(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewFloat(100)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Float", func() { | ||||
| 				input := values.NewFloat(100) | ||||
| 				output, err := values.ToFloat(input) | ||||
| 				output := values.ToFloat(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewFloat(100)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert String", func() { | ||||
| 				input := values.NewString("100.1") | ||||
| 				output, err := values.ToFloat(input) | ||||
| 				output := values.ToFloat(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewFloat(100.1)) | ||||
|  | ||||
| 				output2 := values.ToFloat(values.NewString("foobar")) | ||||
| 				So(output2, ShouldEqual, values.ZeroFloat) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Boolean", func() { | ||||
| 				So(values.ToFloat(values.True), ShouldEqual, values.NewFloat(1)) | ||||
| 				So(values.ToFloat(values.False), ShouldEqual, values.NewFloat(0)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Array with single item", func() { | ||||
| 				So(values.ToFloat(values.NewArrayWith(values.NewFloat(1))), ShouldEqual, values.NewFloat(1)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Array with multiple items", func() { | ||||
| 				arg := values.NewArrayWith(values.NewFloat(1), values.NewFloat(1)) | ||||
|  | ||||
| 				So(values.ToFloat(arg), ShouldEqual, values.NewFloat(2)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert DateTime", func() { | ||||
| 				dt := values.NewCurrentDateTime() | ||||
| 				ts := dt.Time.Unix() | ||||
|  | ||||
| 				So(values.ToFloat(dt), ShouldEqual, values.NewFloat(float64(ts))) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should NOT convert other types", func() { | ||||
| 				inputs := []core.Value{ | ||||
| 					values.NewBoolean(true), | ||||
| 					values.NewCurrentDateTime(), | ||||
| 					values.NewArray(1), | ||||
| 					values.NewObject(), | ||||
| 					values.NewBinary([]byte("")), | ||||
| 				} | ||||
|  | ||||
| 				for _, input := range inputs { | ||||
| 					_, err := values.ToFloat(input) | ||||
|  | ||||
| 					So(err, ShouldNotBeNil) | ||||
| 					So(values.ToFloat(input), ShouldEqual, values.ZeroFloat) | ||||
| 				} | ||||
| 			}) | ||||
| 		}) | ||||
| @@ -267,41 +284,58 @@ func TestHelpers(t *testing.T) { | ||||
| 		Convey("ToInt", func() { | ||||
| 			Convey("Should convert Int", func() { | ||||
| 				input := values.NewInt(100) | ||||
| 				output, err := values.ToInt(input) | ||||
| 				output := values.ToInt(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewInt(100)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Float", func() { | ||||
| 				input := values.NewFloat(100.1) | ||||
| 				output, err := values.ToInt(input) | ||||
| 				output := values.ToInt(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewInt(100)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert String", func() { | ||||
| 				input := values.NewString("100") | ||||
| 				output, err := values.ToInt(input) | ||||
| 				output := values.ToInt(input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				So(output, ShouldEqual, values.NewInt(100)) | ||||
|  | ||||
| 				output2 := values.ToInt(values.NewString("foobar")) | ||||
| 				So(output2, ShouldEqual, values.ZeroInt) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Boolean", func() { | ||||
| 				So(values.ToInt(values.True), ShouldEqual, values.NewInt(1)) | ||||
| 				So(values.ToInt(values.False), ShouldEqual, values.NewInt(0)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Array with single item", func() { | ||||
| 				So(values.ToInt(values.NewArrayWith(values.NewFloat(1))), ShouldEqual, values.NewInt(1)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert Array with multiple items", func() { | ||||
| 				arg := values.NewArrayWith(values.NewFloat(1), values.NewFloat(1)) | ||||
|  | ||||
| 				So(values.ToInt(arg), ShouldEqual, values.NewFloat(2)) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should convert DateTime", func() { | ||||
| 				dt := values.NewCurrentDateTime() | ||||
| 				ts := dt.Time.Unix() | ||||
|  | ||||
| 				So(values.ToInt(dt), ShouldEqual, values.NewInt(int(ts))) | ||||
| 			}) | ||||
|  | ||||
| 			Convey("Should NOT convert other types", func() { | ||||
| 				inputs := []core.Value{ | ||||
| 					values.NewBoolean(true), | ||||
| 					values.NewCurrentDateTime(), | ||||
| 					values.NewArray(1), | ||||
| 					values.NewObject(), | ||||
| 					values.NewBinary([]byte("")), | ||||
| 				} | ||||
|  | ||||
| 				for _, input := range inputs { | ||||
| 					_, err := values.ToInt(input) | ||||
|  | ||||
| 					So(err, ShouldNotBeNil) | ||||
| 					So(values.ToInt(input), ShouldEqual, values.ZeroInt) | ||||
| 				} | ||||
| 			}) | ||||
| 		}) | ||||
| @@ -338,10 +372,9 @@ func TestHelpers(t *testing.T) { | ||||
| 				} | ||||
|  | ||||
| 				for _, pairs := range inputs { | ||||
| 					actual, err := values.ToArray(context.Background(), pairs[0]) | ||||
| 					actual := values.ToArray(context.Background(), pairs[0]) | ||||
| 					expected := pairs[1] | ||||
|  | ||||
| 					So(err, ShouldBeNil) | ||||
| 					So(actual.Compare(expected), ShouldEqual, 0) | ||||
| 				} | ||||
| 			}) | ||||
| @@ -357,9 +390,7 @@ func TestHelpers(t *testing.T) { | ||||
| 				} | ||||
|  | ||||
| 				input := values.NewArrayWith(vals...) | ||||
| 				output, err := values.ToArray(context.Background(), input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				output := values.ToArray(context.Background(), input) | ||||
|  | ||||
| 				arr := output.(*values.Array) | ||||
|  | ||||
| @@ -383,9 +414,7 @@ func TestHelpers(t *testing.T) { | ||||
| 					values.NewObjectProperty("qaz", values.NewObject()), | ||||
| 				) | ||||
|  | ||||
| 				output, err := values.ToArray(context.Background(), input) | ||||
|  | ||||
| 				So(err, ShouldBeNil) | ||||
| 				output := values.ToArray(context.Background(), input) | ||||
|  | ||||
| 				arr := output.(*values.Array).Sort() | ||||
|  | ||||
|   | ||||
| @@ -38,17 +38,8 @@ func MouseMoveXY(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	x, err := values.ToFloat(args[0]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	y, err := values.ToFloat(args[1]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
| 	x := values.ToFloat(args[0]) | ||||
| 	y := values.ToFloat(args[1]) | ||||
|  | ||||
| 	doc := args[0].(drivers.HTMLDocument) | ||||
|  | ||||
|   | ||||
| @@ -38,17 +38,8 @@ func ScrollXY(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	x, err := values.ToFloat(args[1]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	y, err := values.ToFloat(args[2]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
| 	x := values.ToFloat(args[1]) | ||||
| 	y := values.ToFloat(args[2]) | ||||
|  | ||||
| 	doc := args[0].(drivers.HTMLDocument) | ||||
|  | ||||
|   | ||||
| @@ -26,22 +26,10 @@ func Rand(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var max float64 | ||||
| 	var min float64 | ||||
|  | ||||
| 	arg1, err := values.ToFloat(args[0]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	max = float64(arg1) | ||||
| 	max = float64(values.ToFloat(args[0])) | ||||
|  | ||||
| 	if len(args) > 1 { | ||||
| 		arg2, err := values.ToFloat(args[1]) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.None, err | ||||
| 		} | ||||
|  | ||||
| 		min = float64(arg2) | ||||
| 		min = float64(values.ToFloat(args[1])) | ||||
| 	} else { | ||||
| 		max, min = core.NumberBoundaries(max) | ||||
| 	} | ||||
|   | ||||
| @@ -20,5 +20,5 @@ func ToArray(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	return values.ToArray(ctx, args[0]) | ||||
| 	return values.ToArray(ctx, args[0]), nil | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
|  | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values/types" | ||||
| ) | ||||
|  | ||||
| // ToBool takes an input value of any type and converts it into the appropriate boolean value. | ||||
| @@ -24,44 +23,5 @@ func ToBool(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arg := args[0] | ||||
|  | ||||
| 	switch arg.Type() { | ||||
| 	case types.Boolean: | ||||
| 		return arg, nil | ||||
| 	case types.Int: | ||||
| 		val := arg.(values.Int) | ||||
|  | ||||
| 		if val != 0 { | ||||
| 			return values.True, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.False, nil | ||||
| 	case types.Float: | ||||
| 		val := arg.(values.Float) | ||||
|  | ||||
| 		if val != 0 { | ||||
| 			return values.True, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.False, nil | ||||
| 	case types.String: | ||||
| 		if arg.String() != "" { | ||||
| 			return values.True, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.False, nil | ||||
| 	case types.DateTime: | ||||
| 		val := arg.(values.DateTime) | ||||
|  | ||||
| 		if !val.IsZero() { | ||||
| 			return values.True, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.False, nil | ||||
| 	case types.None: | ||||
| 		return values.False, nil | ||||
| 	default: | ||||
| 		return values.True, nil | ||||
| 	} | ||||
| 	return values.ToBoolean(args[0]), nil | ||||
| } | ||||
|   | ||||
| @@ -2,11 +2,9 @@ package types | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values/types" | ||||
| ) | ||||
|  | ||||
| // ToFloat takes an input value of any type and convert it into a float value. | ||||
| @@ -20,67 +18,12 @@ import ( | ||||
| // An empty array is converted to 0, an array with one member is converted into the result of TO_NUMBER() for its sole member. | ||||
| // An array with two or more members is converted to the number 0. | ||||
| // An object / HTML node is converted to the number 0. | ||||
| func ToFloat(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| func ToFloat(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arg := args[0] | ||||
|  | ||||
| 	switch arg.Type() { | ||||
| 	case types.Boolean: | ||||
| 		val := arg.(values.Boolean) | ||||
|  | ||||
| 		if val { | ||||
| 			return values.NewFloat(1), nil | ||||
| 		} | ||||
|  | ||||
| 		return values.ZeroFloat, nil | ||||
| 	case types.Int: | ||||
| 		val := arg.(values.Int) | ||||
|  | ||||
| 		return values.Float(val), nil | ||||
| 	case types.Float: | ||||
| 		return arg, nil | ||||
| 	case types.String: | ||||
| 		str := arg.String() | ||||
|  | ||||
| 		if str == "" { | ||||
| 			return values.ZeroFloat, nil | ||||
| 		} | ||||
|  | ||||
| 		num, err := strconv.ParseFloat(str, 64) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.ZeroFloat, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.NewFloat(num), nil | ||||
| 	case types.DateTime: | ||||
| 		val := arg.(values.DateTime) | ||||
|  | ||||
| 		if val.IsZero() { | ||||
| 			return values.ZeroFloat, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.NewFloat(float64(val.Unix())), nil | ||||
| 	case types.None: | ||||
| 		return values.ZeroFloat, nil | ||||
| 	case types.Array: | ||||
| 		val := arg.(*values.Array) | ||||
|  | ||||
| 		if val.Length() == 0 { | ||||
| 			return values.ZeroFloat, nil | ||||
| 		} | ||||
|  | ||||
| 		if val.Length() == 1 { | ||||
| 			return ToFloat(ctx, val.Get(0)) | ||||
| 		} | ||||
|  | ||||
| 		return values.ZeroFloat, nil | ||||
| 	default: | ||||
| 		return values.ZeroFloat, nil | ||||
| 	} | ||||
| 	return values.ToFloat(args[0]), nil | ||||
| } | ||||
|   | ||||
| @@ -2,11 +2,9 @@ package types | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values/types" | ||||
| ) | ||||
|  | ||||
| // ToInt takes an input value of any type and convert it into an integer value. | ||||
| @@ -20,67 +18,12 @@ import ( | ||||
| // An empty array is converted to 0, an array with one member is converted into the result of TO_NUMBER() for its sole member. | ||||
| // An array with two or more members is converted to the number 0. | ||||
| // An object / HTML node is converted to the number 0. | ||||
| func ToInt(ctx context.Context, args ...core.Value) (core.Value, error) { | ||||
| func ToInt(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arg := args[0] | ||||
|  | ||||
| 	switch arg.Type() { | ||||
| 	case types.Boolean: | ||||
| 		val := arg.(values.Boolean) | ||||
|  | ||||
| 		if val { | ||||
| 			return values.NewInt(1), nil | ||||
| 		} | ||||
|  | ||||
| 		return values.ZeroInt, nil | ||||
| 	case types.Int: | ||||
| 		return arg, nil | ||||
| 	case types.Float: | ||||
| 		val := arg.(values.Float) | ||||
|  | ||||
| 		return values.Int(val), nil | ||||
| 	case types.String: | ||||
| 		str := arg.String() | ||||
|  | ||||
| 		if str == "" { | ||||
| 			return values.ZeroInt, nil | ||||
| 		} | ||||
|  | ||||
| 		num, err := strconv.Atoi(str) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.ZeroInt, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.NewInt(num), nil | ||||
| 	case types.DateTime: | ||||
| 		val := arg.(values.DateTime) | ||||
|  | ||||
| 		if val.IsZero() { | ||||
| 			return values.ZeroInt, nil | ||||
| 		} | ||||
|  | ||||
| 		return values.NewInt(int(val.Unix())), nil | ||||
| 	case types.None: | ||||
| 		return values.ZeroInt, nil | ||||
| 	case types.Array: | ||||
| 		val := arg.(*values.Array) | ||||
|  | ||||
| 		if val.Length() == 0 { | ||||
| 			return values.ZeroInt, nil | ||||
| 		} | ||||
|  | ||||
| 		if val.Length() == 1 { | ||||
| 			return ToInt(ctx, val.Get(0)) | ||||
| 		} | ||||
|  | ||||
| 		return values.ZeroInt, nil | ||||
| 	default: | ||||
| 		return values.ZeroInt, nil | ||||
| 	} | ||||
| 	return values.ToInt(args[0]), nil | ||||
| } | ||||
|   | ||||
| @@ -17,11 +17,7 @@ func Wait(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	arg, err := values.ToInt(args[0]) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
| 	arg := values.ToInt(args[0]) | ||||
|  | ||||
| 	time.Sleep(time.Millisecond * time.Duration(arg)) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user