Repository: goplus/gop
Pull request #434 (2020-07-10 16:56:18)

github.com/goplus/gop/constant


Patch:
diff --git a/constant/const.go b/constant/const.go
index 98ab439a..d14bf01c 100644
--- a/constant/const.go
+++ b/constant/const.go
@@ -1,8 +1,33 @@
+/*
+ Copyright 2020 The GoPlus Authors (goplus.org)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// Package constant implements Values representing untyped
+// Go+ constants and their corresponding operations.
+//
+// A special Unknown value may be used when a value
+// is unknown due to an error. Operations on unknown
+// values produce unknown values unless specified
+// otherwise.
+//
 package constant
 
 import (
 	"go/constant"
 	gotoken "go/token"
+	"math/big"
 
 	"github.com/goplus/gop/token"
 )
@@ -86,9 +111,17 @@ func MakeFloat64(x float64) Value {
 }
 
 // MakeRat returns the Rat value of x.
-func MakeRat(x string) Value {
-	//TODO:
-	return &ratVal{nil}
+func MakeRat(x interface{}) Value {
+	return &ratVal{constant.Make(x)}
+}
+
+// MakeRatFromString returns the Rat value of x.
+func MakeRatFromString(x string) Value {
+	v := constant.MakeFromLiteral(x, gotoken.FLOAT, 0)
+	if v.Kind() != Unknown {
+		v = &ratVal{v}
+	}
+	return v
 }
 
 // MakeFromLiteral returns the corresponding integer, floating-point,
@@ -97,8 +130,9 @@ func MakeRat(x string) Value {
 // token.CHAR, token.STRING or token.RAT. The final argument must be zero.
 // If the literal string syntax is invalid, the result is an Unknown.
 func MakeFromLiteral(lit string, tok token.Token, zero uint) Value {
-	if tok == token.RAT {
-		return MakeRat(lit[:len(lit)-1])
+	switch tok {
+	case token.RAT:
+		return MakeRatFromString(lit[:len(lit)-1])
 	}
 	return constant.MakeFromLiteral(lit, gotoken.Token(tok), zero)
 }
@@ -275,6 +309,10 @@ func ToComplex(x Value) Value {
 // If y is Unknown, the result is Unknown.
 //
 func UnaryOp(op token.Token, y Value, prec uint) Value {
+	if v, ok := y.(*ratVal); ok {
+		ret := constant.UnaryOp(gotoken.Token(op), v.Value, prec)
+		return &ratVal{ret}
+	}
 	return constant.UnaryOp(gotoken.Token(op), y, prec)
 }
 
@@ -289,6 +327,18 @@ func UnaryOp(op token.Token, y Value, prec uint) Value {
 // Division by zero leads to a run-time panic.
 //
 func BinaryOp(x Value, op token.Token, y Value) Value {
+	vx, okx := x.(*ratVal)
+	vy, oky := y.(*ratVal)
+	if okx || oky {
+		if okx {
+			x = vx.Value
+		}
+		if oky {
+			y = vy.Value
+		}
+		ret := constant.BinaryOp(x, gotoken.Token(op), y)
+		return &ratVal{ret}
+	}
 	return constant.BinaryOp(x, gotoken.Token(op), y)
 }
 
@@ -297,6 +347,15 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
 // an Int or an Unknown. If x is Unknown, the result is x.
 //
 func Shift(x Value, op token.Token, s uint) Value {
+	if v, ok := x.(*ratVal); ok {
+		vx := v.Value
+		val := constant.Val(vx)
+		if rat, ok := val.(*big.Rat); ok && rat.IsInt() {
+			vx = constant.Num(vx)
+		}
+		ret := constant.Shift(vx, gotoken.Token(op), s)
+		return &ratVal{ret}
+	}
 	return constant.Shift(x, gotoken.Token(op), s)
 }
 
@@ -306,6 +365,12 @@ func Shift(x Value, op token.Token, s uint) Value {
 // false.
 //
 func Compare(x Value, op token.Token, y Value) bool {
+	if vx, ok := x.(*ratVal); ok {
+		x = vx.Value
+	}
+	if vy, ok := y.(*ratVal); ok {
+		y = vy.Value
+	}
 	return constant.Compare(x, gotoken.Token(op), y)
 }
 
diff --git a/go.mod b/go.mod
index 493f3bc5..79136604 100644
--- a/go.mod
+++ b/go.mod
@@ -3,5 +3,5 @@ module github.com/goplus/gop
 go 1.14
 
 require (
-	github.com/qiniu/x v1.10.5
+	github.com/qiniu/x v1.10.8
 )
diff --git a/go.sum b/go.sum
index a68cfd55..11d7e402 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,2 @@
-github.com/qiniu/x v1.10.5 h1:7V/CYWEmo9axJULvrJN6sMYh2FdY+esN5h8jwDkA4b0=
-github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
+github.com/qiniu/x v1.10.8 h1:lwIRAR4vFDI+l05OhmM12nkY8d2zyYsLh2FyCE7GVQ0=
+github.com/qiniu/x v1.10.8/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=


Test patch:
diff --git a/constant/const_test.go b/constant/const_test.go
new file mode 100644
index 00000000..a2a24d35
--- /dev/null
+++ b/constant/const_test.go
@@ -0,0 +1,113 @@
+/*
+ Copyright 2020 The GoPlus Authors (goplus.org)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package constant
+
+import (
+	"math/big"
+	"testing"
+
+	"github.com/goplus/gop/token"
+	"github.com/qiniu/x/ts"
+)
+
+// ----------------------------------------------------------------------------
+
+func TestOp(test *testing.T) {
+	t := ts.New(test)
+	x := MakeRatFromString("1.3e-2")
+	y := Make(int64(3))
+	t.Case("-Rat 13/1000", UnaryOp(token.SUB, x, 0)).PropEqual("kind", Rat).PropEqual("string", "-13/1000")
+	t.Case("-Int 3", UnaryOp(token.SUB, y, 0)).PropEqual("kind", Int).PropEqual("string", "-3")
+	t.Case("Rat 13/1000 + Int 3", BinaryOp(x, token.ADD, y)).PropEqual("kind", Rat).PropEqual("string", "3013/1000")
+	t.Case("Rat 1/2 + Float 1.5", BinaryOp(MakeRatFromString("1p-1"), token.ADD, MakeFloat64(1.5))).PropEqual("kind", Rat).PropEqual("string", "2")
+	t.Case("Rat 1.2 + Rat 1/2", BinaryOp(MakeRatFromString("1.2"), token.ADD, MakeRatFromString("1p-1"))).PropEqual("kind", Rat).PropEqual("string", "17/10")
+	t.Case("Int 1 + Int 2", BinaryOp(MakeInt64(1), token.ADD, MakeInt64(2))).PropEqual("kind", Int).PropEqual("string", "3")
+	t.Case("Cmp(Int 1 != Int 2)", Compare(MakeInt64(1), token.NEQ, MakeInt64(2))).Equal(true)
+	t.Case("Cmp(Rat 1p1 != Int 2)", Compare(MakeRatFromString("1p1"), token.EQL, MakeInt64(2))).Equal(true)
+	t.Case("Cmp(Rat 1p1 != Rat 2)", Compare(MakeRatFromString("1p1"), token.EQL, MakeRatFromString("2"))).Equal(true)
+	t.Case("Shift(Int 1, Int 2)", Shift(MakeInt64(1), token.SHL, 2)).Equal(MakeInt64(4))
+	t.Case("Shift(Rat 1, Int 2)", Shift(MakeRatFromString("1"), token.SHL, 2)).PropEqual("kind", Rat).PropEqual("string", "4")
+}
+
+func TestMakeVal(test *testing.T) {
+	t := ts.New(test)
+	t.Call(MakeUnknown).PropEqual("kind", Unknown).PropEqual("string", "unknown")
+	t.Call(MakeBool, true).PropEqual("kind", Bool).PropEqual("string", "true")
+	t.Call(MakeString, "hello").PropEqual("kind", String).PropEqual("string", `"hello"`)
+	t.Call(MakeInt64, int64(-10000)).PropEqual("kind", Int).PropEqual("string", "-10000")
+	t.Call(MakeUint64, uint64(10000)).PropEqual("kind", Int).PropEqual("string", "10000")
+	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(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.2", token.FLOAT, uint(0))).Equal(big.NewRat(6, 5))
+	t.Call(Val, MakeFromLiteral("3.14159265358979323846264338327950288419716939937510582097494459", token.FLOAT, uint(0))).
+		PropEqual("string", "314159265358979323846264338327950288419716939937510582097494459/100000000000000000000000000000000000000000000000000000000000000")
+}
+
+func TestMakeRat(test *testing.T) {
+	t := ts.New(test)
+	t.Call(MakeRat, int64(1)).PropEqual("kind", Rat).PropEqual("string", "1")
+	t.Call(MakeRat, big.NewInt(1)).PropEqual("kind", Rat).PropEqual("string", "1")
+	t.Call(MakeRat, big.NewRat(1, 3)).PropEqual("kind", Rat).PropEqual("string", "1/3")
+}
+
+func TestMakeRatFromString(test *testing.T) {
+	t := ts.New(test)
+	t.Call(MakeRatFromString, "1x").PropEqual("kind", Unknown)
+	t.Call(MakeRatFromString, "1e3x").PropEqual("kind", Unknown)
+	t.Call(MakeRatFromString, "1").PropEqual("kind", Rat).PropEqual("string", "1")
+	t.Call(MakeRatFromString, "1.234567").PropEqual("kind", Rat).PropEqual("string", "1234567/1000000")
+	t.Call(MakeRatFromString, ".234567").PropEqual("kind", Rat).PropEqual("string", "234567/1000000")
+	t.Call(MakeRatFromString, "1_111e2").PropEqual("kind", Rat).PropEqual("string", "111100")
+	t.Call(MakeRatFromString, "1_111E-2").PropEqual("kind", Rat).PropEqual("string", "1111/100")
+	t.Call(MakeRatFromString, "1111p-2").PropEqual("kind", Rat).PropEqual("string", "1111/4")
+	t.Call(MakeRatFromString, "1111P2").PropEqual("kind", Rat).PropEqual("string", "4444")
+	t.Call(MakeRatFromString, "1.3e-2").PropEqual("kind", Rat).PropEqual("string", "13/1000")
+}
+
+func TestVal(test *testing.T) {
+	t := ts.New(test)
+	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(Uint64Val, MakeInt64(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(Float64Val, MakeInt64(-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(Bytes, MakeInt64(0x408)).Equal([]byte{8, 4})
+	t.Call(MakeFromBytes, []byte{8, 4}).Equal(MakeInt64(0x408))
+	t.Call(Num, MakeInt64(4)).Equal(MakeInt64(4))
+	t.Call(Denom, MakeInt64(4)).Equal(MakeInt64(1))
+	t.Call(Real, MakeImag(MakeInt64(4))).Equal(MakeInt64(0))
+	t.Call(Imag, MakeImag(MakeInt64(4))).Equal(MakeInt64(4))
+}
+
+func TestToVal(test *testing.T) {
+	t := ts.New(test)
+	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, MakeInt64(10)).PropEqual("kind", Float).PropEqual("string", "10")
+	t.Call(ToComplex, MakeInt64(10)).PropEqual("kind", Complex).PropEqual("string", "(10 + 0i)")
+}
+
+// ----------------------------------------------------------------------------