Repository navigation
fix(stringlib): implement string.format with Lua 5.4 conversion rules - #80
Merged
Merged
Conversation
string.format handed raw Lua values to Go's fmt.Sprintf, so a conversion
never converted its argument: string.format("%.1f", 0) produced
"%!f(lua.LInteger=0)", %d of 3.0 printed a float, %x of -1 printed "-1",
%q used Go quoting, inf/nan printed Go spellings, %s widths counted runes,
missing arguments printed %!v(MISSING) and invalid specifiers passed through.
Each specification is now validated as lstrlib's checkformat does (per
conversion flags, two-digit width and precision) and its argument is
converted the way the reference implementation converts it:
luaL_checkinteger for c/d/i/u/o/x/X, luaL_checknumber for a/e/f/g, tostring
for s, and addliteral for q. Errors match Lua 5.4: no value, number has no
integer representation, invalid conversion, specifier '%q' cannot have
modifiers, value has no literal form.
Expectations come from the Lua 5.4 reference interpreter; a randomized
comparison of 2,895 specifier/value pairs against lua5.4 matches except %s
of floats, where %s is tostring and tostring's float spelling differs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
string.formatpassed raw Lua values to Go'sfmt.Sprintf, so no conversion ever converted its argument:string.format("%.1f", 0)%!f(lua.LInteger=0)0.0string.format("%d", 3.0)%!d(lua.LNumber=3)3string.format("%x", -1)-1ffffffffffffffffstring.format("%f", 1/0)+Infinfstring.format("%q", "a\nb")"a\newlineb"string.format("%d")%!d(MISSING)string.format("%y", 1)%!y(...)Any Lua code that formats integer-valued numbers with
%fhit this. JSON-decoded numbers and literal0areLInteger.Fix
stringlib_format.goports lstrlib'sstr_format:checkformatchecks it: the flags each conversion allows, and width and precision of at most two digits.luaL_checkintegerforc d i u o x X(unsigned foru o x X),luaL_checknumberfora A e E f F g G,tostring(with__tostring) fors, andaddliteralforq.%a), inf/nan and string widths are formatted directly, byte-based as in C.e f guse Go's fmt with the precision C defaults to, which matches C for every flag.Tests
stringlib_format_test.gohas 94 cases. Every expected value comes from the Lua 5.4 reference interpreter. They cover conversions, flags, widths, precision, inf/nan,%arounding,%qescapes, and every error path.I also compared 2,895 random flag/width/precision/conversion/value combinations against
lua5.4. They all match except%sof floats.%sistostring, andtostringspells floats differently from Lua 5.4 (3.0→3,1/0→+Inf,2^53). That is a separate defect inLNumber.Stringand is not changed here.go test .passes.