1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-08-13 19:52:52 +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:
Tim Voronov
2019-05-19 12:12:11 -04:00
committed by GitHub
parent ab0a617031
commit 6933798419
13 changed files with 1296 additions and 285 deletions

View File

@@ -2,6 +2,7 @@ package operators
import ( import (
"context" "context"
"strings"
"github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values" "github.com/MontFerret/ferret/pkg/runtime/values"
@@ -88,9 +89,62 @@ func Not(left, _ core.Value) core.Value {
return values.True 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 // Adds numbers
// Concats strings // Concatenates strings
func Add(left, right core.Value) core.Value { func Add(inputL, inputR core.Value) core.Value {
left := ToNumberOrString(inputL)
right := ToNumberOrString(inputR)
if left.Type() == types.Int { if left.Type() == types.Int {
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -126,7 +180,10 @@ func Add(left, right core.Value) core.Value {
return values.NewString(left.String() + right.String()) 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 left.Type() == types.Int {
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -162,7 +219,10 @@ func Subtract(left, right core.Value) core.Value {
return values.ZeroInt 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 left.Type() == types.Int {
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -198,20 +258,31 @@ func Multiply(left, right core.Value) core.Value {
return values.ZeroInt 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 left.Type() == types.Int {
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Int) l := values.Float(left.(values.Int))
r := right.(values.Int) r := values.Float(right.(values.Int))
if r == 0.0 {
panic("divide by zero")
}
return l / r return l / r
} }
if right.Type() == types.Float { if right.Type() == types.Float {
l := left.(values.Int) l := values.Float(left.(values.Int))
r := right.(values.Float) 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) l := left.(values.Float)
r := right.(values.Float) r := right.(values.Float)
if r == 0.0 {
panic("divide by zero")
}
return l / r return l / r
} }
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Float) 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 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 left.Type() == types.Int {
if right.Type() == types.Int { if right.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -270,7 +352,9 @@ func Modulus(left, right core.Value) core.Value {
return values.ZeroInt 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 { if left.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -286,7 +370,9 @@ func Increment(left, _ core.Value) core.Value {
return values.None 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 { if left.Type() == types.Int {
l := left.(values.Int) l := left.(values.Int)
@@ -303,31 +389,27 @@ func Decrement(left, _ core.Value) core.Value {
} }
func Negative(value, _ 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 { if value.Type() == types.Int {
return -value.(values.Int) return -value.(values.Int)
} }
if value.Type() == types.Float {
return -value.(values.Float) return -value.(values.Float)
}
return value
} }
func Positive(value, _ core.Value) core.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 { if value.Type() == types.Int {
return +value.(values.Int) return +value.(values.Int)
} }
if value.Type() == types.Float {
return +value.(values.Float) return +value.(values.Float)
}
return value
} }
func ToBoolean(value, _ core.Value) core.Value { func ToBoolean(value, _ core.Value) core.Value {

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,8 @@ import (
type Float float64 type Float float64
var NaN = Float(math.NaN())
const ZeroFloat = Float(0.0) const ZeroFloat = Float(0.0)
func NewFloat(input float64) Float { func NewFloat(input float64) Float {
@@ -80,7 +82,7 @@ func (t Float) Type() core.Type {
} }
func (t Float) String() string { func (t Float) String() string {
return fmt.Sprintf("%f", t) return fmt.Sprintf("%v", float64(t))
} }
func (t Float) Compare(other core.Value) int64 { func (t Float) Compare(other core.Value) int64 {

View File

@@ -235,58 +235,116 @@ func ToBoolean(input core.Value) core.Value {
switch input.Type() { switch input.Type() {
case types.Boolean: case types.Boolean:
return input return input
case types.None:
return False
case types.String: case types.String:
return NewBoolean(input.String() != "") return NewBoolean(input.(String) != "")
case types.Int: case types.Int:
return NewBoolean(input.(Int) != 0) return NewBoolean(input.(Int) != 0)
case types.Float: case types.Float:
return NewBoolean(input.(Float) != 0) return NewBoolean(input.(Float) != 0)
case types.DateTime:
return NewBoolean(!input.(DateTime).IsZero())
case types.None:
return False
default: default:
return True return True
} }
} }
func ToFloat(input core.Value) (Float, error) { func ToFloat(input core.Value) Float {
switch val := input.(type) { switch val := input.(type) {
case Float: case Float:
return val, nil return val
case Int: case Int:
return Float(val), nil return Float(val)
case String: case String:
i, err := strconv.ParseFloat(string(val), 64) i, err := strconv.ParseFloat(string(val), 64)
if err != nil { 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: 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) { switch val := input.(type) {
case Int: case Int:
return val, nil return val
case Float: case Float:
return Int(val), nil return Int(val)
case String: case String:
i, err := strconv.ParseInt(string(val), 10, 64) i, err := strconv.ParseInt(string(val), 10, 64)
if err != nil { 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: 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) { switch value := input.(type) {
case Boolean, case Boolean,
Int, Int,
@@ -294,9 +352,9 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) {
String, String,
DateTime: DateTime:
return NewArrayWith(value), nil return NewArrayWith(value)
case *Array: case *Array:
return value.Copy(), nil return value.Copy()
case *Object: case *Object:
arr := NewArray(int(value.Length())) arr := NewArray(int(value.Length()))
@@ -306,12 +364,12 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) {
return true return true
}) })
return arr, nil return arr
case core.Iterable: case core.Iterable:
iterator, err := value.Iterate(ctx) iterator, err := value.Iterate(ctx)
if err != nil { if err != nil {
return None, err return None
} }
arr := NewArray(10) arr := NewArray(10)
@@ -320,7 +378,7 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) {
val, _, err := iterator.Next(ctx) val, _, err := iterator.Next(ctx)
if err != nil { if err != nil {
return None, err return None
} }
if val == None { if val == None {
@@ -330,9 +388,9 @@ func ToArray(ctx context.Context, input core.Value) (core.Value, error) {
arr.Push(val) arr.Push(val)
} }
return arr, nil return arr
default: default:
return NewArray(0), nil return NewArray(0)
} }
} }
@@ -372,3 +430,9 @@ func MapHash(input map[string]core.Value) uint64 {
return h.Sum64() return h.Sum64()
} }
func IsNumber(input core.Value) Boolean {
t := input.Type()
return t == types.Int || t == types.Float
}

View File

@@ -225,41 +225,58 @@ func TestHelpers(t *testing.T) {
Convey("ToFloat", func() { Convey("ToFloat", func() {
Convey("Should convert Int", func() { Convey("Should convert Int", func() {
input := values.NewInt(100) input := values.NewInt(100)
output, err := values.ToFloat(input) output := values.ToFloat(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewFloat(100)) So(output, ShouldEqual, values.NewFloat(100))
}) })
Convey("Should convert Float", func() { Convey("Should convert Float", func() {
input := values.NewFloat(100) input := values.NewFloat(100)
output, err := values.ToFloat(input) output := values.ToFloat(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewFloat(100)) So(output, ShouldEqual, values.NewFloat(100))
}) })
Convey("Should convert String", func() { Convey("Should convert String", func() {
input := values.NewString("100.1") input := values.NewString("100.1")
output, err := values.ToFloat(input) output := values.ToFloat(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewFloat(100.1)) 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() { Convey("Should NOT convert other types", func() {
inputs := []core.Value{ inputs := []core.Value{
values.NewBoolean(true),
values.NewCurrentDateTime(),
values.NewArray(1),
values.NewObject(), values.NewObject(),
values.NewBinary([]byte("")), values.NewBinary([]byte("")),
} }
for _, input := range inputs { for _, input := range inputs {
_, err := values.ToFloat(input) So(values.ToFloat(input), ShouldEqual, values.ZeroFloat)
So(err, ShouldNotBeNil)
} }
}) })
}) })
@@ -267,41 +284,58 @@ func TestHelpers(t *testing.T) {
Convey("ToInt", func() { Convey("ToInt", func() {
Convey("Should convert Int", func() { Convey("Should convert Int", func() {
input := values.NewInt(100) input := values.NewInt(100)
output, err := values.ToInt(input) output := values.ToInt(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewInt(100)) So(output, ShouldEqual, values.NewInt(100))
}) })
Convey("Should convert Float", func() { Convey("Should convert Float", func() {
input := values.NewFloat(100.1) input := values.NewFloat(100.1)
output, err := values.ToInt(input) output := values.ToInt(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewInt(100)) So(output, ShouldEqual, values.NewInt(100))
}) })
Convey("Should convert String", func() { Convey("Should convert String", func() {
input := values.NewString("100") input := values.NewString("100")
output, err := values.ToInt(input) output := values.ToInt(input)
So(err, ShouldBeNil)
So(output, ShouldEqual, values.NewInt(100)) 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() { Convey("Should NOT convert other types", func() {
inputs := []core.Value{ inputs := []core.Value{
values.NewBoolean(true),
values.NewCurrentDateTime(),
values.NewArray(1),
values.NewObject(), values.NewObject(),
values.NewBinary([]byte("")), values.NewBinary([]byte("")),
} }
for _, input := range inputs { for _, input := range inputs {
_, err := values.ToInt(input) So(values.ToInt(input), ShouldEqual, values.ZeroInt)
So(err, ShouldNotBeNil)
} }
}) })
}) })
@@ -338,10 +372,9 @@ func TestHelpers(t *testing.T) {
} }
for _, pairs := range inputs { for _, pairs := range inputs {
actual, err := values.ToArray(context.Background(), pairs[0]) actual := values.ToArray(context.Background(), pairs[0])
expected := pairs[1] expected := pairs[1]
So(err, ShouldBeNil)
So(actual.Compare(expected), ShouldEqual, 0) So(actual.Compare(expected), ShouldEqual, 0)
} }
}) })
@@ -357,9 +390,7 @@ func TestHelpers(t *testing.T) {
} }
input := values.NewArrayWith(vals...) input := values.NewArrayWith(vals...)
output, err := values.ToArray(context.Background(), input) output := values.ToArray(context.Background(), input)
So(err, ShouldBeNil)
arr := output.(*values.Array) arr := output.(*values.Array)
@@ -383,9 +414,7 @@ func TestHelpers(t *testing.T) {
values.NewObjectProperty("qaz", values.NewObject()), values.NewObjectProperty("qaz", values.NewObject()),
) )
output, err := values.ToArray(context.Background(), input) output := values.ToArray(context.Background(), input)
So(err, ShouldBeNil)
arr := output.(*values.Array).Sort() arr := output.(*values.Array).Sort()

View File

@@ -38,17 +38,8 @@ func MouseMoveXY(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err return values.None, err
} }
x, err := values.ToFloat(args[0]) x := values.ToFloat(args[0])
y := values.ToFloat(args[1])
if err != nil {
return values.None, err
}
y, err := values.ToFloat(args[1])
if err != nil {
return values.None, err
}
doc := args[0].(drivers.HTMLDocument) doc := args[0].(drivers.HTMLDocument)

View File

@@ -38,17 +38,8 @@ func ScrollXY(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err return values.None, err
} }
x, err := values.ToFloat(args[1]) x := values.ToFloat(args[1])
y := values.ToFloat(args[2])
if err != nil {
return values.None, err
}
y, err := values.ToFloat(args[2])
if err != nil {
return values.None, err
}
doc := args[0].(drivers.HTMLDocument) doc := args[0].(drivers.HTMLDocument)

View File

@@ -26,22 +26,10 @@ func Rand(_ context.Context, args ...core.Value) (core.Value, error) {
var max float64 var max float64
var min float64 var min float64
arg1, err := values.ToFloat(args[0]) max = float64(values.ToFloat(args[0]))
if err != nil {
return values.None, err
}
max = float64(arg1)
if len(args) > 1 { if len(args) > 1 {
arg2, err := values.ToFloat(args[1]) min = float64(values.ToFloat(args[1]))
if err != nil {
return values.None, err
}
min = float64(arg2)
} else { } else {
max, min = core.NumberBoundaries(max) max, min = core.NumberBoundaries(max)
} }

View File

@@ -20,5 +20,5 @@ func ToArray(ctx context.Context, args ...core.Value) (core.Value, error) {
return values.None, err return values.None, err
} }
return values.ToArray(ctx, args[0]) return values.ToArray(ctx, args[0]), nil
} }

View File

@@ -5,7 +5,6 @@ import (
"github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values" "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. // 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 return values.None, err
} }
arg := args[0] return values.ToBoolean(args[0]), nil
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
}
} }

View File

@@ -2,11 +2,9 @@ package types
import ( import (
"context" "context"
"strconv"
"github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values" "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. // 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 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 array with two or more members is converted to the number 0.
// An object / HTML node 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) err := core.ValidateArgs(args, 1, 1)
if err != nil { if err != nil {
return values.None, err return values.None, err
} }
arg := args[0] return values.ToFloat(args[0]), nil
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
}
} }

View File

@@ -2,11 +2,9 @@ package types
import ( import (
"context" "context"
"strconv"
"github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values" "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. // 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 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 array with two or more members is converted to the number 0.
// An object / HTML node 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) err := core.ValidateArgs(args, 1, 1)
if err != nil { if err != nil {
return values.None, err return values.None, err
} }
arg := args[0] return values.ToInt(args[0]), nil
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
}
} }

View File

@@ -17,11 +17,7 @@ func Wait(_ context.Context, args ...core.Value) (core.Value, error) {
return values.None, nil return values.None, nil
} }
arg, err := values.ToInt(args[0]) arg := values.ToInt(args[0])
if err != nil {
return values.None, err
}
time.Sleep(time.Millisecond * time.Duration(arg)) time.Sleep(time.Millisecond * time.Duration(arg))