Repository: goplus/gop
Pull request #435 (2020-07-11 18:03:41)

gop/constant


Patch:
diff --git a/constant/const.go b/constant/const.go
index d14bf01c..a1d8679a 100644
--- a/constant/const.go
+++ b/constant/const.go
@@ -159,6 +159,9 @@ func StringVal(x Value) string {
 // x must be an Int or an Unknown. If the result is not exact, its value is undefined.
 // If x is Unknown, the result is (0, false).
 func Int64Val(x Value) (int64, bool) {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Int64Val(x)
 }
 
@@ -166,11 +169,17 @@ func Int64Val(x Value) (int64, bool) {
 // x must be an Int or an Unknown. If the result is not exact, its value is undefined.
 // If x is Unknown, the result is (0, false).
 func Uint64Val(x Value) (uint64, bool) {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Uint64Val(x)
 }
 
 // Float32Val is like Float64Val but for float32 instead of float64.
 func Float32Val(x Value) (float32, bool) {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Float32Val(x)
 }
 
@@ -180,6 +189,9 @@ func Float32Val(x Value) (float32, bool) {
 // matches the sign of x, even for 0.
 // If x is Unknown, the result is (0, false).
 func Float64Val(x Value) (float64, bool) {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Float64Val(x)
 }
 
@@ -193,10 +205,13 @@ func Float64Val(x Value) (float64, bool) {
 //    String             string
 //    Int                int64 or *big.Int
 //    Float              *big.Float or *big.Rat
-//    Rat                *big.Rat or *big.Int
+//    Rat                int64, *big.Int, *big.Float or *big.Rat
 //    everything else    nil
 //
 func Val(x Value) interface{} {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Val(x)
 }
 
@@ -227,6 +242,9 @@ func BitLen(x Value) int {
 // x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
 // otherwise it is != 0. If x is Unknown, the result is 1.
 func Sign(x Value) int {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Sign(x)
 }
 
@@ -250,6 +268,9 @@ func MakeFromBytes(bytes []byte) Value {
 // fraction, the result is Unknown. Otherwise the result is an Int
 // with the same sign as x.
 func Num(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Num(x)
 }
 
@@ -257,6 +278,9 @@ func Num(x Value) Value {
 // If x is Unknown, or if it is too large or small to represent as a
 // fraction, the result is Unknown. Otherwise the result is an Int >= 1.
 func Denom(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.Denom(x)
 }
 
@@ -264,39 +288,68 @@ func Denom(x Value) Value {
 // x must be Int, Float, or Unknown.
 // If x is Unknown, the result is Unknown.
 func MakeImag(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.MakeImag(x)
 }
 
 // Real returns the real part of x, which must be a numeric or unknown value.
 // If x is Unknown, the result is Unknown.
 func Real(x Value) Value {
+	if _, ok := x.(*ratVal); ok {
+		return x
+	}
 	return constant.Real(x)
 }
 
 // Imag returns the imaginary part of x, which must be a numeric or unknown value.
 // If x is Unknown, the result is Unknown.
 func Imag(x Value) Value {
+	if _, ok := x.(*ratVal); ok {
+		return constant.MakeInt64(0)
+	}
 	return constant.Imag(x)
 }
 
 // ----------------------------------------------------------------------------
 // Numeric conversions
 
+// IsInt returns whether x is an integer.
+func IsInt(x Value) bool {
+	switch v := Val(x).(type) {
+	case int64, *big.Int:
+		return true
+	case *big.Rat:
+		return v.IsInt()
+	}
+	return false
+}
+
 // ToInt converts x to an Int value if x is representable as an Int.
 // Otherwise it returns an Unknown.
 func ToInt(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.ToInt(x)
 }
 
 // ToFloat converts x to a Float value if x is representable as a Float.
 // Otherwise it returns an Unknown.
 func ToFloat(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.ToFloat(x)
 }
 
 // ToComplex converts x to a Complex value if x is representable as a Complex.
 // Otherwise it returns an Unknown.
 func ToComplex(x Value) Value {
+	if v, ok := x.(*ratVal); ok {
+		x = v.Value
+	}
 	return constant.ToComplex(x)
 }
 


Test patch:
diff --git a/constant/const_test.go b/constant/const_test.go
index a2a24d35..d83c0d4f 100644
--- a/constant/const_test.go
+++ b/constant/const_test.go
@@ -53,8 +53,10 @@ func TestMakeVal(test *testing.T) {
 	t.Call(MakeFloat64, 1e4).PropEqual("kind", Float).PropEqual("string", "10000")
 	t.Call(Make, false).PropEqual("kind", Bool).PropEqual("string", "false")
 	t.Call(MakeImag, MakeInt64(1000)).PropEqual("kind", Complex).PropEqual("string", "(0 + 1000i)")
+	t.Call(MakeImag, MakeRat(int64(1000))).PropEqual("kind", Complex).PropEqual("string", "(0 + 1000i)")
 	t.Call(MakeFromLiteral, "1x1r", token.RAT, uint(0)).PropEqual("kind", Unknown)
 	t.Call(MakeFromLiteral, "1r", token.RAT, uint(0)).PropEqual("kind", Rat).PropEqual("string", "1")
+	t.Call(Val, MakeFromLiteral("1.2r", token.RAT, uint(0))).Equal(big.NewRat(6, 5))
 	t.Call(Val, MakeFromLiteral("1.2", token.FLOAT, uint(0))).Equal(big.NewRat(6, 5))
 	t.Call(Val, MakeFromLiteral("3.14159265358979323846264338327950288419716939937510582097494459", token.FLOAT, uint(0))).
 		PropEqual("string", "314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000")
@@ -86,27 +88,42 @@ func TestVal(test *testing.T) {
 	t.Call(BoolVal, MakeBool(true)).Equal(true)
 	t.Call(StringVal, MakeString("hello")).Equal("hello")
 	t.Call(Int64Val, MakeInt64(1000)).Equal(int64(1000)).Next().Equal(true)
+	t.Call(Int64Val, MakeRat(int64(1000))).Equal(int64(1000)).Next().Equal(true)
 	t.Call(Uint64Val, MakeInt64(1000)).Equal(uint64(1000)).Next().Equal(true)
+	t.Call(Uint64Val, MakeRat(int64(1000))).Equal(uint64(1000)).Next().Equal(true)
 	t.Call(Uint64Val, MakeInt64(-1000)).Equal(uint64(18446744073709550616)).Next().Equal(false)
 	t.Call(Float32Val, MakeInt64(-1000)).Equal(float32(-1000)).Next().Equal(true)
+	t.Call(Float32Val, MakeRat(int64(-1000))).Equal(float32(-1000)).Next().Equal(true)
 	t.Call(Float64Val, MakeInt64(-1000)).Equal(float64(-1000)).Next().Equal(true)
+	t.Call(Float64Val, MakeRat(int64(-1000))).Equal(float64(-1000)).Next().Equal(true)
 	t.Call(Val, MakeInt64(-1000)).Equal(int64(-1000))
 	t.Call(BitLen, MakeInt64(4)).Equal(3)
 	t.Call(Sign, MakeInt64(4)).Equal(1)
+	t.Call(Sign, MakeRat(int64(-1000))).Equal(-1)
 	t.Call(Bytes, MakeInt64(0x408)).Equal([]byte{8, 4})
 	t.Call(MakeFromBytes, []byte{8, 4}).Equal(MakeInt64(0x408))
+	t.Call(Num, MakeRat(int64(4))).Equal(MakeInt64(4))
 	t.Call(Num, MakeInt64(4)).Equal(MakeInt64(4))
+	t.Call(Denom, MakeRat(int64(4))).Equal(MakeInt64(1))
 	t.Call(Denom, MakeInt64(4)).Equal(MakeInt64(1))
+	t.Call(Real, MakeRat(int64(4))).Equal(MakeRat(int64(4)))
 	t.Call(Real, MakeImag(MakeInt64(4))).Equal(MakeInt64(0))
-	t.Call(Imag, MakeImag(MakeInt64(4))).Equal(MakeInt64(4))
+	t.Call(Imag, MakeRat(int64(4))).Equal(MakeInt64(0))
+	t.Call(Imag, MakeInt64(4)).Equal(MakeInt64(0))
 }
 
 func TestToVal(test *testing.T) {
 	t := ts.New(test)
+	t.Call(IsInt, MakeFloat64(10)).Equal(true)
+	t.Call(IsInt, MakeString("10")).Equal(false)
+	t.Call(IsInt, MakeInt64(10)).Equal(true)
+	t.Call(ToInt, MakeRat(int64(10))).Equal(MakeInt64(10))
 	t.Call(ToInt, MakeFloat64(10)).Equal(MakeInt64(10))
 	t.Call(ToInt, MakeFloat64(10.8)).Equal(MakeUnknown())
 	t.Call(ToInt, MakeFloat64(10)).Equal(MakeInt64(10))
+	t.Call(ToFloat, MakeRat(int64(10))).PropEqual("kind", Float).PropEqual("string", "10")
 	t.Call(ToFloat, MakeInt64(10)).PropEqual("kind", Float).PropEqual("string", "10")
+	t.Call(ToComplex, MakeRat(int64(10))).PropEqual("kind", Complex).PropEqual("string", "(10 + 0i)")
 	t.Call(ToComplex, MakeInt64(10)).PropEqual("kind", Complex).PropEqual("string", "(10 + 0i)")
 }