diff --git a/examples/gno.land/p/demo/ufmt/ufmt.gno b/examples/gno.land/p/demo/ufmt/ufmt.gno index 0e6143d6ebd..30bf61691f3 100644 --- a/examples/gno.land/p/demo/ufmt/ufmt.gno +++ b/examples/gno.land/p/demo/ufmt/ufmt.gno @@ -64,12 +64,18 @@ func Sprintf(format string, args ...interface{}) string { switch v := arg.(type) { case int: buf += strconv.Itoa(v) + case int32: + buf += strconv.Itoa(int(v)) case int64: buf += strconv.Itoa(int(v)) case uint: buf += strconv.FormatUint(uint64(v), 10) + case uint32: + buf += strconv.FormatUint(uint64(v), 10) case uint64: buf += strconv.FormatUint(v, 10) + case bigint: + buf += string(v) default: buf += "(unhandled)" } diff --git a/gno.land/pkg/sdk/vm/convert.go b/gno.land/pkg/sdk/vm/convert.go index de4db67fb04..b6c41bfd235 100644 --- a/gno.land/pkg/sdk/vm/convert.go +++ b/gno.land/pkg/sdk/vm/convert.go @@ -3,6 +3,7 @@ package vm import ( "encoding/base64" "fmt" + "math/big" "strconv" gno "github.com/gnolang/gno/gnovm/pkg/gnolang" @@ -153,6 +154,18 @@ func convertArgToGno(arg string, argT gno.Type) (tv gno.TypedValue) { } tv.SetUint64(u64) return + case gno.BigintType: + if arg[0] == '+' { + panic("numbers cannot start with +") + } + bi, ok := big.NewInt(0).SetString(arg, 10) + if !ok { + panic(fmt.Sprintf( + "error parsing bigint %v", arg)) + } + + tv.SetBigInt(bi) + return default: panic(fmt.Sprintf("unexpected primitive type %s", bt.String())) } diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 69e468f755a..ba2dd33e22e 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -2,6 +2,7 @@ package gnolang import ( "fmt" + "math/big" "reflect" ) @@ -508,7 +509,9 @@ func go2GnoValueUpdate(alloc *Allocator, rlm *Realm, lvl int, tv *TypedValue, rv tv.SetFloat64(rv.Float()) } case BigintKind: - panic("not yet implemented") + if lvl != 0 { + tv.SetBigInt(rv.Interface().(*big.Int)) + } case BigdecKind: panic("not yet implemented") case ArrayKind: @@ -828,7 +831,7 @@ func gno2GoType(t Type) reflect.Type { case Float64Type: return reflect.TypeOf(float64(0)) case BigintType, UntypedBigintType: - panic("not yet implemented") + return reflect.TypeOf(big.NewInt(0)) case BigdecType, UntypedBigdecType: panic("not yet implemented") default: @@ -1113,6 +1116,8 @@ func gno2GoValue(tv *TypedValue, rv reflect.Value) (ret reflect.Value) { rv.SetFloat(float64(tv.GetFloat32())) case Float64Type: rv.SetFloat(tv.GetFloat64()) + case BigintType, UntypedBigintType: + rv.Set(reflect.ValueOf(tv.GetBigInt())) default: panic(fmt.Sprintf( "unexpected type %s", diff --git a/gnovm/pkg/gnolang/op_binary.go b/gnovm/pkg/gnolang/op_binary.go index 9162a710d7d..18ebb8ac141 100644 --- a/gnovm/pkg/gnolang/op_binary.go +++ b/gnovm/pkg/gnolang/op_binary.go @@ -1109,9 +1109,9 @@ func shlAssign(lv, rv *TypedValue) { case Uint64Type: lv.SetUint64(lv.GetUint64() << rv.GetUint()) case BigintType, UntypedBigintType: - lb := lv.GetBigInt() - lb = big.NewInt(0).Lsh(lb, rv.GetUint()) - lv.V = BigintValue{V: lb} + z := big.NewInt(0) + z.Lsh(lv.GetBigInt(), rv.GetUint()) + lv.V = BigintValue{V: z} default: panic(fmt.Sprintf( "operators << and <<= not defined for %s", diff --git a/gnovm/pkg/gnolang/values.go b/gnovm/pkg/gnolang/values.go index d8c656d2ca3..f9e6d186cf5 100644 --- a/gnovm/pkg/gnolang/values.go +++ b/gnovm/pkg/gnolang/values.go @@ -996,6 +996,7 @@ func (tv TypedValue) Copy(alloc *Allocator) (cp TypedValue) { case BigintValue: cp.T = tv.T cp.V = cv.Copy(alloc) + cp.N = tv.N case *ArrayValue: cp.T = tv.T cp.V = cv.Copy(alloc) @@ -1432,6 +1433,17 @@ func (tv *TypedValue) GetFloat64() float64 { return *(*float64)(unsafe.Pointer(&tv.N)) } +func (tv *TypedValue) SetBigInt(bi *big.Int) { + if debug { + if tv.T.Kind() != BigintKind || isNative(tv.T) { + panic(fmt.Sprintf( + "TypedValue.SetBigInt() on type %s", + tv.T.String())) + } + } + tv.V = BigintValue{bi} +} + func (tv *TypedValue) GetBigInt() *big.Int { if debug { if tv.T != nil && tv.T.Kind() != BigintKind { @@ -2439,6 +2451,10 @@ func defaultValue(alloc *Allocator, t Type) Value { ) } default: + switch t.Kind() { + case BigintKind: + return BigintValue{V: big.NewInt(0)} + } return nil } } diff --git a/gnovm/pkg/gnolang/values_conversions.go b/gnovm/pkg/gnolang/values_conversions.go index e2000defdde..65b131f86dc 100644 --- a/gnovm/pkg/gnolang/values_conversions.go +++ b/gnovm/pkg/gnolang/values_conversions.go @@ -130,6 +130,9 @@ GNO_CASE: x := uint64(tv.GetInt()) tv.T = t tv.SetUint64(x) + case BigintKind: + tv.V = BigintValue{V: big.NewInt(tv.GetInt64())} + tv.T = t case Float32Kind: x := float32(tv.GetInt()) // XXX determinism? tv.T = t @@ -307,6 +310,9 @@ GNO_CASE: x := uint64(tv.GetInt32()) tv.T = t tv.SetUint64(x) + case BigintKind: + tv.V = BigintValue{V: big.NewInt(tv.GetInt64())} + tv.T = t case Float32Kind: x := float32(tv.GetInt32()) // XXX determinism? tv.T = t @@ -366,6 +372,9 @@ GNO_CASE: x := uint64(tv.GetInt64()) tv.T = t tv.SetUint64(x) + case BigintKind: + tv.V = BigintValue{V: big.NewInt(tv.GetInt64())} + tv.T = t case Float32Kind: x := float32(tv.GetInt64()) // XXX determinism? tv.T = t @@ -425,6 +434,9 @@ GNO_CASE: x := uint64(tv.GetUint()) tv.T = t tv.SetUint64(x) + case BigintKind: + tv.V = BigintValue{V: big.NewInt(tv.GetInt64())} + tv.T = t case Float32Kind: x := float32(tv.GetUint()) // XXX determinism? tv.T = t @@ -661,6 +673,9 @@ GNO_CASE: x := tv.GetUint64() tv.T = t tv.SetUint64(x) + case BigintKind: + tv.V = BigintValue{V: big.NewInt(tv.GetInt64())} + tv.T = t case Float32Kind: x := float32(tv.GetUint64()) // XXX determinism? tv.T = t @@ -678,6 +693,41 @@ GNO_CASE: "cannot convert %s to %s", tvk.String(), k.String())) } + case BigintKind: + switch k { + case IntKind, Int8Kind, Int16Kind, Int32Kind, UintKind, Uint8Kind, Uint16Kind, Uint32Kind: + panic(fmt.Sprintf( + "cannot convert %s to %s", + tvk.String(), k.String())) + case Int64Kind: + x := tv.GetBigInt() + if x.IsInt64() { + tv.T = t + tv.SetInt64(x.Int64()) + } else { + panic(fmt.Sprintf( + "cannot convert %s to %s", + tvk.String(), k.String())) + } + case Uint64Kind: + x := tv.GetBigInt() + if x.IsUint64() { + tv.T = t + tv.SetUint64(x.Uint64()) + } else { + panic(fmt.Sprintf( + "cannot convert %s to %s", + tvk.String(), k.String())) + } + case StringKind: + tv.T = t + tv.SetString(StringValue(tv.GetBigInt().String())) + default: + panic(fmt.Sprintf( + "cannot convert %s to %s", + tvk.String(), k.String())) + + } case Float32Kind: switch k { case IntKind: @@ -809,6 +859,20 @@ GNO_CASE: "cannot convert %s to %s", tvk.String(), t.String())) } + case PrimitiveType: + switch k { + case BigintKind: + bi := new(big.Int) + bi, ok := bi.SetString(tv.GetString(), 10) + if !ok { + panic(fmt.Sprintf( + "cannot convert %s to %s", + tvk.String(), k.String(), + )) + } + tv.V = BigintValue{V: bi} + tv.T = t + } default: panic(fmt.Sprintf( "cannot convert %s to %s",