Skip to content

Feature/formatting#143

Closed
pgundlach wants to merge 29 commits intoShopify:mainfrom
speedata:feature/formatting
Closed

Feature/formatting#143
pgundlach wants to merge 29 commits intoShopify:mainfrom
speedata:feature/formatting

Conversation

@pgundlach
Copy link
Copy Markdown

No description provided.

- Native 64-bit integer support (int64)
  - Bitwise operators: &, |, ~, <<, >>
  - Integer division: //
  - UTF-8 library
  - String packing (string.pack/unpack)
  - Math extensions (math.tointeger, math.type, etc.)
  - Fixed for-loop integer semantics
  - Fixed vararg stack overflow
  - 10/11 official Lua 5.3 tests pass"
- error() now preserves any value as error object (not just strings)
  In Lua 5.3, error(value) can be called with tables, nil, etc.
  The value stays on the stack and is returned by pcall.

- table.sort: add "array too big" check for __len > INT_MAX
  Prevents hang when metatable returns huge length values.

- table.move: add "too many elements to move" validation
  Matches Lua 5.3 reference implementation bounds checking.
Add debug.getinfo function that returns introspection data about
functions and stack frames. Supports all standard options:
- 'S': source, short_src, linedefined, lastlinedefined, what
- 'l': currentline
- 'u': nups, nparams, isvararg
- 'n': name, namewhat
- 't': istailcall
- 'f': func (the function itself)
- 'L': activelines table

The core Info() Go function already existed - this adds the Lua-facing
wrapper that builds the result table.

calls.lua and constructs.lua now progress further but fail on other
issues (load reader function, operator precedence).
In Lua 5.3, ipairs{} must return the same iterator function each time
(ipairs{} == ipairs{}). Previously, each call created a new Go function.

Now the iterator is cached in the registry on first use and reused for
all subsequent ipairs calls. Uses a unique pointer key to avoid
collisions with user data.

This enables the nextvar.lua test to progress further (now fails on
a different issue: "invalid key to next").
Lua 5.3 requires strings to be coerced to integers for bitwise
operations. This commit implements that behavior:

- Add toIntegerString() method in types.go for string coercion
- Change coerceToIntegers to State method using toIntegerString
- Update all bitwise op call sites in vm.go (BAND, BOR, BXOR,
  SHL, SHR, BNOT)
- Fix functionName() to use savedPC-1 for correct call instruction
- Enable bitwise and constructs tests in vm_test.go

The bitwise and constructs Lua 5.3 tests now pass.
Scanner:
- Add readHexFraction for fractional hex digits without overflow
- Track overflow digits as exponent adjustment in readHexNumber

Types:
- Add 4th return value (ok) to parseNumberEx for validation
- Fix tonumber('0x') returning 0 instead of nil

Math library:
- math.abs: preserve integer type, overflow wrapping for minint
- math.atan: support optional second argument (atan2)
- math.tointeger: range check before int64 conversion
- math.fmod: preserve integer type, "zero" error for div by 0
- math.max/min: preserve integer type, "value expected" error
- math.random: return integers, proper range handling up to 2^63

Debug:
- bitwiseError includes field/upvalue names from debug info
The test had a loop waiting for weak references to be GC'd,
but go-lua doesn't support weak refs (__mode metatables).

Added _noweakref flag to skip the weak reference loop.
This enables the closure test in the test suite.
- Format all source files with go fmt
- Fix undump.go shift warning (instruction is always 32-bit)
- Remove dead code in io.go (err was always nil)
- Update TestIntegerValues for strict integerValues behavior
The next() function would throw "invalid key to 'next'" when the
current key was deleted from the hash table during iteration.

Fix: Check if the key matches our position marker before checking
if it was deleted. This allows iteration to continue correctly
even when keys are removed mid-iteration.
table.insert, table.remove, table.sort now respect __index/__newindex
metamethods, allowing them to work with proxy tables.

Changes:
- table.insert: Use Table/SetTable instead of RawGetInt/RawSetInt
- table.remove: Use Table/SetTable for element shifting
- table.sort: Update sortHelper.Swap/Less to use metamethods
- table.concat: Use Table for reading elements
- table.unpack: Use Table for reading elements, fix integer overflow
  bug when iterating near maxInt

Also adds comprehensive tests for metamethod support.
EncodeConstant was using opLoadConstant instead of opLoadConstantEx
when constant index exceeded maxArgBx (262143). The VM expects
opLoadConstantEx to read the index from the following EXTRAARG
instruction.

Adds TestLargeTableExtraArg to verify tables with >262143 elements.
Add full f:read() support for file handles:
- read("l")/read("*l"): line without EOL (default)
- read("L")/read("*L"): line with EOL
- read("n")/read("*n"): number (integer, float, hex)
- read("a")/read("*a"): entire file
- read(n): n bytes
- read(0): EOF test

Also fixes write() to preserve string content exactly (was
incorrectly converting numeric-looking strings through number
conversion, losing newlines like "123\n" -> "123").
Add io.popen(command, mode) support:
- Read mode ("r"): capture command stdout
- Write mode ("w"): pipe to command stdin
- close() returns true on success, or nil/error/exitcode on failure

Uses os.Pipe() to get real file descriptors compatible with
existing stream infrastructure.
- ioutil.ReadAll → io.ReadAll
- ioutil.ReadFile → os.ReadFile
- ioutil.TempFile → os.CreateTemp

Also fix popen to use /bin/sh and ensure PATH includes
standard locations for subprocess commands.
Use cmd.exe /c on Windows, /bin/sh -c on Unix.
PATH extension only needed on Unix due to sandbox environments.
Supports all standard format specifiers (%a, %d, %Y, etc.),
"*t" table output, "!" prefix for UTC, and os.time table input fix.
- Restore lua-tests/checktable.lua (lost during fixtures/ to lua-tests/ migration)
- Guard coroutine.wrap usage in strings.lua with _nocoroutine flag
- Fix dump encoding: empty string constants now correctly write 0x01 instead of 0x00
- Implement setlocale
- Error messags
- string.dump
... and some more bug fixes and missing pieces
table.concat used repeated string concatenation (s += str), causing
quadratic copying. Replaced with strings.Builder for O(n) performance.

pairs/next linearly scanned iterationKeys to find the current key on
every call, making iteration O(n²). Added an index map for O(1) key
lookup.

Added benchmarks/ directory with Lua scripts and a Go runner to compare
go-lua against C-Lua 5.3.
* Add CI tests
* Fixed a few minor issues
@pgundlach pgundlach closed this Mar 24, 2026
@pgundlach
Copy link
Copy Markdown
Author

Sorry, opened this by mistake

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant