Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ require (
github.com/go-ruby-erb/erb v0.0.0-20260629074717-0999ae4dd529
github.com/go-ruby-faker/faker v0.0.0-20260630192057-0a0efdf75352
github.com/go-ruby-find/find v0.0.0-20260630081030-35072d185272
github.com/go-ruby-format/format v0.0.0-20260629094031-e294417ab31c
github.com/go-ruby-format/format v0.0.0-20260703115518-8adcf1b4af5f
github.com/go-ruby-getoptlong/getoptlong v0.0.0-20260629150025-1a1bfd19bc49
github.com/go-ruby-grape/grape v0.0.0-20260702151528-455377c8c7c3
github.com/go-ruby-haml/haml v0.0.0-20260701125233-5bf8084caf1c
Expand Down Expand Up @@ -60,7 +60,7 @@ require (
github.com/go-ruby-pathname/pathname v0.0.0-20260629151955-d8d2c4e5f81b
github.com/go-ruby-pg/pg v0.0.0-20260702135906-e5650264cc5d
github.com/go-ruby-prettyprint/prettyprint v0.0.0-20260629152429-60a380e82d7d
github.com/go-ruby-prime/prime v0.0.0-20260629151744-aa26747e21a8
github.com/go-ruby-prime/prime v0.0.0-20260703101152-9274dca78d88
github.com/go-ruby-pstore/pstore v0.0.0-20260630081017-0dd55a12f94e
github.com/go-ruby-public-suffix/public-suffix v0.0.0-20260630151503-f308d4002444
github.com/go-ruby-rack/rack v0.0.0-20260630124607-8a4f9cfcdbb5
Expand Down Expand Up @@ -88,7 +88,7 @@ require (
github.com/go-ruby-uri/uri v0.0.0-20260629113958-59633d1b0deb
github.com/go-ruby-xslt/xslt v0.0.0-20260702171958-146eaf3f0176
github.com/go-ruby-yaml/yaml v0.0.0-20260629093916-8035038027bd
github.com/go-ruby-zlib/zlib v0.0.0-20260630052127-b4ac0c1ab281
github.com/go-ruby-zlib/zlib v0.0.0-20260703114753-dbf176c108fc
)

require (
Expand All @@ -99,6 +99,7 @@ require (
github.com/go-simd/base64 v0.0.0-20260627054622-4058a7093f4c // indirect
github.com/go-simd/hex v0.0.0-20260627054622-d04d429c6aea // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
Expand Down
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ github.com/go-ruby-faker/faker v0.0.0-20260630192057-0a0efdf75352 h1:cRiGBGZWF8P
github.com/go-ruby-faker/faker v0.0.0-20260630192057-0a0efdf75352/go.mod h1:7h2mxQ3mnWz9bg39nSDr0h/LxqnEnbrJxmNRDbu3zs8=
github.com/go-ruby-find/find v0.0.0-20260630081030-35072d185272 h1:tHmlER04rO8LxFWbDiKqcFDzB4WFzBio/c6kgeOdpGo=
github.com/go-ruby-find/find v0.0.0-20260630081030-35072d185272/go.mod h1:wpq0ciEFn8zUc1vfuHRjF2U8mH0krhJCRHHr+JOGaEY=
github.com/go-ruby-format/format v0.0.0-20260629094031-e294417ab31c h1:dJBMxMFxBLrk4LoWL23tOl5M8P0CA8Gb7r/mvsaPk6A=
github.com/go-ruby-format/format v0.0.0-20260629094031-e294417ab31c/go.mod h1:1tuz12SHPOcnFSfdPYRFwVvRhMT4Xn4M4jfPFgM7pLA=
github.com/go-ruby-format/format v0.0.0-20260703115518-8adcf1b4af5f h1:N4nvZMNtLocbwcjJiXIhZ0gq8r0fUc7J3F/U2hnDMYQ=
github.com/go-ruby-format/format v0.0.0-20260703115518-8adcf1b4af5f/go.mod h1:1tuz12SHPOcnFSfdPYRFwVvRhMT4Xn4M4jfPFgM7pLA=
github.com/go-ruby-getoptlong/getoptlong v0.0.0-20260629150025-1a1bfd19bc49 h1:v2Cy3bZTTi+u9XKBRP8FmYHwsWwZ+t8hlh3s4i1gGfQ=
github.com/go-ruby-getoptlong/getoptlong v0.0.0-20260629150025-1a1bfd19bc49/go.mod h1:nGvVSBSIsYrhM2qs4yQ2k8uDbXCFPWQXXqkowleHMDs=
github.com/go-ruby-grape/grape v0.0.0-20260702151528-455377c8c7c3 h1:JPcmRUa/fiwj55H7LXULvrxifCaQkH6fXTvDZZg3pvw=
Expand Down Expand Up @@ -128,8 +128,8 @@ github.com/go-ruby-pg/pg v0.0.0-20260702135906-e5650264cc5d h1:JKIZD+pJQ64/nla4D
github.com/go-ruby-pg/pg v0.0.0-20260702135906-e5650264cc5d/go.mod h1:XIYL8wT1Thvoeh7y5v9ZrL+34ySHiieu1/GyDZauULk=
github.com/go-ruby-prettyprint/prettyprint v0.0.0-20260629152429-60a380e82d7d h1:hH6O6QdrUlbePkqb8skhFQ0BVuMe0u1c/CXFFaVUnXg=
github.com/go-ruby-prettyprint/prettyprint v0.0.0-20260629152429-60a380e82d7d/go.mod h1:SIQyfiIJRKJq0OD9gWYfmvQTdJClJf8z56BsfVVw7rY=
github.com/go-ruby-prime/prime v0.0.0-20260629151744-aa26747e21a8 h1:zghkWpebo93z7Uz/BMXnLSN30ZPeLXS35Y1HPeXkUE4=
github.com/go-ruby-prime/prime v0.0.0-20260629151744-aa26747e21a8/go.mod h1:dG/91hk8HlQ6YAdD64xiMFHTTmXjTWtapKWoG9JtcRA=
github.com/go-ruby-prime/prime v0.0.0-20260703101152-9274dca78d88 h1:td+zp+GfoRSqG1kuNvKiX+ujC6QQwR5YsQjqeXFUofg=
github.com/go-ruby-prime/prime v0.0.0-20260703101152-9274dca78d88/go.mod h1:dG/91hk8HlQ6YAdD64xiMFHTTmXjTWtapKWoG9JtcRA=
github.com/go-ruby-pstore/pstore v0.0.0-20260630081017-0dd55a12f94e h1:JmbJL+0nq6HY1SX1tDBFQyo7M8JgbQ+ukwn8iLyNGfs=
github.com/go-ruby-pstore/pstore v0.0.0-20260630081017-0dd55a12f94e/go.mod h1:tbYmHYXjnNXJCNYABDx9nWfuGBCXeKrp134bNsQeTpM=
github.com/go-ruby-public-suffix/public-suffix v0.0.0-20260630151503-f308d4002444 h1:vkMPJDpZHmu09pVxr7CFppoh1b5Kc8LkhKpxkSBoyxA=
Expand Down Expand Up @@ -184,8 +184,8 @@ github.com/go-ruby-xslt/xslt v0.0.0-20260702171958-146eaf3f0176 h1:iHTCF/Eu0/lwO
github.com/go-ruby-xslt/xslt v0.0.0-20260702171958-146eaf3f0176/go.mod h1:1C3Bx0pQIsqLqC2SnqV7pJnGuLJsgYmar2NrD+CmVXw=
github.com/go-ruby-yaml/yaml v0.0.0-20260629093916-8035038027bd h1:4HGjgCdTIuIEM+iZXJ9hJJzt0IBMtxPqdJq72mr0Y64=
github.com/go-ruby-yaml/yaml v0.0.0-20260629093916-8035038027bd/go.mod h1:HtbQgnZpSTJBAhPg1jOKgHycZl3tXgf9ZdOu4dnHWjQ=
github.com/go-ruby-zlib/zlib v0.0.0-20260630052127-b4ac0c1ab281 h1:zOn3ro0WBggDR0xqvNSdOPxHEWzdR6iMy842CAyIL/g=
github.com/go-ruby-zlib/zlib v0.0.0-20260630052127-b4ac0c1ab281/go.mod h1:abizNd4NW4jTmJYNmfSIuLz0J3l7MAImkcZKlslLNRM=
github.com/go-ruby-zlib/zlib v0.0.0-20260703114753-dbf176c108fc h1:Gap/pSbjMktFKJQ4tcSmmL0JKBEQZ4TK/bEZ49pUp60=
github.com/go-ruby-zlib/zlib v0.0.0-20260703114753-dbf176c108fc/go.mod h1:WGW5hh1yjgYm98zeoraLu8DWJ0iRFSU0fNmK8PXQ43M=
github.com/go-simd/base64 v0.0.0-20260627054622-4058a7093f4c h1:iA1vHw+pR44TUtDlviXz3P8pAExO1nSm39PMZ7MsuYU=
github.com/go-simd/base64 v0.0.0-20260627054622-4058a7093f4c/go.mod h1:/nL/YHcchLkENbcFEEqAcfESIiwCM9/1H67LsSnd7EI=
github.com/go-simd/hex v0.0.0-20260627054622-d04d429c6aea h1:qVh9jV1QriPPfKtAb8au5pmVxKDk5Vl4nQUi/issQM0=
Expand All @@ -200,6 +200,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/klauspost/compress v1.18.7 h1:aUyZsS4kH3QTKurYhAOwAHxllVPnOthb3vPfnF1Ehjw=
github.com/klauspost/compress v1.18.7/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
Expand Down
25 changes: 24 additions & 1 deletion internal/vm/format_bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@ func (fv formatValue) Kind() format.Kind {
}
}

// Int64Fast reports a genuine int64-range Ruby Integer without allocating a
// *big.Int, letting the library's integer conversions (%d/%x/%o/%b/…) skip
// math/big for the common small-integer case. A Bignum reports its int64 value
// only when it fits; every other value (Float, String, etc.) reports ok=false so
// the formatter uses the precise Int() path with its coercion and error rules.
func (fv formatValue) Int64Fast() (int64, bool) {
switch x := fv.v.(type) {
case object.Integer:
return int64(x), true
case *object.Bignum:
if x.I.IsInt64() {
return x.I.Int64(), true
}
return 0, false
default:
return 0, false
}
}

// ToS is the Ruby to_s rendering (%s and the textual value of %{name}).
func (fv formatValue) ToS() string { return fv.v.ToS() }

Expand Down Expand Up @@ -173,9 +192,13 @@ func formatNamedArgs(args []object.Value) *format.NamedArgs {
// single entry point Kernel#sprintf / Kernel#format / IO#printf / String#% all
// funnel through, so their formatting behaviour is identical.
func formatString(fmtStr string, args []object.Value) string {
// One backing array of wrappers, referenced by pointer, so wrapping N
// operands costs a single allocation instead of one interface box per arg.
wraps := make([]formatValue, len(args))
vals := make([]format.Value, len(args))
for i, a := range args {
vals[i] = formatValue{a}
wraps[i].v = a
vals[i] = &wraps[i]
}
out, err := format.Format(fmtStr, vals, formatNamedArgs(args))
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions internal/vm/format_bind_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,31 @@ func TestFormatValueKind(t *testing.T) {
}
}

// TestFormatValueInt64Fast covers every arm of formatValue.Int64Fast, the
// allocation-free fast path the library's integer conversions take: a native
// Integer and an int64-range Bignum report their value; an out-of-range Bignum
// and any non-integer decline so the formatter uses the precise Int() path.
func TestFormatValueInt64Fast(t *testing.T) {
big64 := new(big.Int).Lsh(big.NewInt(1), 100) // 2^100, far beyond int64
cases := []struct {
v object.Value
wantN int64
wantOK bool
}{
{object.Integer(-42), -42, true},
{&object.Bignum{I: big.NewInt(7)}, 7, true}, // Bignum that fits int64
{&object.Bignum{I: big64}, 0, false}, // Bignum exceeding int64
{object.Float(1.5), 0, false}, // non-integer declines
{object.NewString("9"), 0, false}, // String declines (Int() parses it)
}
for _, c := range cases {
n, ok := (formatValue{c.v}).Int64Fast()
if n != c.wantN || ok != c.wantOK {
t.Errorf("Int64Fast(%T=%v) = (%d, %v), want (%d, %v)", c.v, c.v, n, ok, c.wantN, c.wantOK)
}
}
}

// TestFormatValueInspect covers formatValue.Inspect (the %p backing), which the
// library calls when rendering an inspected value.
func TestFormatValueInspect(t *testing.T) {
Expand Down
Loading