diff --git a/examples/gno.land/p/demo/ufmt/ufmt.gno b/examples/gno.land/p/demo/ufmt/ufmt.gno index c2abf43c85a..c9acee1c910 100644 --- a/examples/gno.land/p/demo/ufmt/ufmt.gno +++ b/examples/gno.land/p/demo/ufmt/ufmt.gno @@ -22,6 +22,8 @@ func Println(args ...interface{}) { strs = append(strs, v.String()) case error: strs = append(strs, v.Error()) + case float64: + strs = append(strs, Sprintf("%f", v)) case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: strs = append(strs, Sprintf("%d", v)) case bool: @@ -49,21 +51,28 @@ func Println(args ...interface{}) { // // The currently formatted verbs are the following: // -// %s: places a string value directly. -// If the value implements the interface interface{ String() string }, -// the String() method is called to retrieve the value. Same about Error() -// string. -// %c: formats the character represented by Unicode code point -// %d: formats an integer value using package "strconv". -// Currently supports only uint, uint64, int, int64. -// %t: formats a boolean value to "true" or "false". -// %x: formats an integer value as a hexadecimal string. -// Currently supports only uint8, []uint8, [32]uint8. -// %c: formats a rune value as a string. -// Currently supports only rune, int. -// %q: formats a string value as a quoted string. -// %T: formats the type of the value. -// %%: outputs a literal %. Does not consume an argument. +// %s: places a string value directly. +// If the value implements the interface interface{ String() string }, +// the String() method is called to retrieve the value. Same about Error() +// string. +// %c: formats the character represented by Unicode code point +// %d: formats an integer value using package "strconv". +// Currently supports only uint, uint64, int, int64. +// %f: formats a float value, with a default precision of 6. +// %e: formats a float with scientific notation; 1.23456e+78 +// %E: formats a float with scientific notation; 1.23456E+78 +// %F: The same as %f +// %g: formats a float value with %e for large exponents, and %f with full precision for smaller numbers +// %G: formats a float value with %G for large exponents, and %F with full precision for smaller numbers +// %t: formats a boolean value to "true" or "false". +// %x: formats an integer value as a hexadecimal string. +// Currently supports only uint8, []uint8, [32]uint8. +// %c: formats a rune value as a string. +// Currently supports only rune, int. +// %q: formats a string value as a quoted string. +// %T: formats the type of the value. +// %v: formats the value with a default representation appropriate for the value's type +// %%: outputs a literal %. Does not consume an argument. func Sprintf(format string, args ...interface{}) string { // we use runes to handle multi-byte characters sTor := []rune(format) @@ -97,6 +106,51 @@ func Sprintf(format string, args ...interface{}) string { argNum++ switch verb { + case "v": + switch v := arg.(type) { + case nil: + buf += "" + case bool: + if v { + buf += "true" + } else { + buf += "false" + } + case int: + buf += strconv.Itoa(v) + case int8: + buf += strconv.Itoa(int(v)) + case int16: + buf += strconv.Itoa(int(v)) + case int32: + buf += strconv.Itoa(int(v)) + case int64: + buf += strconv.Itoa(int(v)) + case uint: + buf += strconv.FormatUint(uint64(v), 10) + case uint8: + buf += strconv.FormatUint(uint64(v), 10) + case uint16: + buf += strconv.FormatUint(uint64(v), 10) + case uint32: + buf += strconv.FormatUint(uint64(v), 10) + case uint64: + buf += strconv.FormatUint(v, 10) + case float64: + buf += strconv.FormatFloat(v, 'g', -1, 64) + case string: + buf += v + case []byte: + buf += string(v) + case []rune: + buf += string(v) + case interface{ String() string }: + buf += v.String() + case error: + buf += v.Error() + default: + buf += fallback(verb, v) + } case "s": switch v := arg.(type) { case interface{ String() string }: @@ -153,6 +207,24 @@ func Sprintf(format string, args ...interface{}) string { default: buf += fallback(verb, v) } + case "e", "E", "f", "F", "g", "G": + switch v := arg.(type) { + case float64: + switch verb { + case "e": + buf += strconv.FormatFloat(v, byte('e'), -1, 64) + case "E": + buf += strconv.FormatFloat(v, byte('E'), -1, 64) + case "f", "F": + buf += strconv.FormatFloat(v, byte('f'), 6, 64) + case "g": + buf += strconv.FormatFloat(v, byte('g'), -1, 64) + case "G": + buf += strconv.FormatFloat(v, byte('G'), -1, 64) + } + default: + buf += fallback(verb, v) + } case "t": switch v := arg.(type) { case bool: @@ -244,6 +316,8 @@ func fallback(verb string, arg interface{}) string { case error: // note: also "string=" in Go fmt s = "string=" + v.Error() + case float64: + s = "float64=" + Sprintf("%f", v) case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: // note: rune, byte would be dups, being aliases if typename, e := typeToString(v); e != nil { diff --git a/examples/gno.land/p/demo/ufmt/ufmt_test.gno b/examples/gno.land/p/demo/ufmt/ufmt_test.gno index 2a583202a93..1cb7231a611 100644 --- a/examples/gno.land/p/demo/ufmt/ufmt_test.gno +++ b/examples/gno.land/p/demo/ufmt/ufmt_test.gno @@ -20,21 +20,34 @@ func TestSprintf(t *testing.T) { expectedOutput string }{ {"hello %s!", []interface{}{"planet"}, "hello planet!"}, + {"hello %v!", []interface{}{"planet"}, "hello planet!"}, {"hi %%%s!", []interface{}{"worl%d"}, "hi %worl%d!"}, {"%s %c %d %t", []interface{}{"foo", 'α', 421, true}, "foo α 421 true"}, {"string [%s]", []interface{}{"foo"}, "string [foo]"}, {"int [%d]", []interface{}{int(42)}, "int [42]"}, + {"int [%v]", []interface{}{int(42)}, "int [42]"}, {"int8 [%d]", []interface{}{int8(8)}, "int8 [8]"}, + {"int8 [%v]", []interface{}{int8(8)}, "int8 [8]"}, {"int16 [%d]", []interface{}{int16(16)}, "int16 [16]"}, + {"int16 [%v]", []interface{}{int16(16)}, "int16 [16]"}, {"int32 [%d]", []interface{}{int32(32)}, "int32 [32]"}, + {"int32 [%v]", []interface{}{int32(32)}, "int32 [32]"}, {"int64 [%d]", []interface{}{int64(64)}, "int64 [64]"}, + {"int64 [%v]", []interface{}{int64(64)}, "int64 [64]"}, {"uint [%d]", []interface{}{uint(42)}, "uint [42]"}, + {"uint [%v]", []interface{}{uint(42)}, "uint [42]"}, {"uint8 [%d]", []interface{}{uint8(8)}, "uint8 [8]"}, + {"uint8 [%v]", []interface{}{uint8(8)}, "uint8 [8]"}, {"uint16 [%d]", []interface{}{uint16(16)}, "uint16 [16]"}, + {"uint16 [%v]", []interface{}{uint16(16)}, "uint16 [16]"}, {"uint32 [%d]", []interface{}{uint32(32)}, "uint32 [32]"}, + {"uint32 [%v]", []interface{}{uint32(32)}, "uint32 [32]"}, {"uint64 [%d]", []interface{}{uint64(64)}, "uint64 [64]"}, + {"uint64 [%v]", []interface{}{uint64(64)}, "uint64 [64]"}, {"bool [%t]", []interface{}{true}, "bool [true]"}, + {"bool [%v]", []interface{}{true}, "bool [true]"}, {"bool [%t]", []interface{}{false}, "bool [false]"}, + {"bool [%v]", []interface{}{false}, "bool [false]"}, {"no args", nil, "no args"}, {"finish with %", nil, "finish with %"}, {"stringer [%s]", []interface{}{stringer{}}, "stringer [I'm a stringer]"},