Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

debugger.lua's where command can't see the last line of Lua code loaded from a string #86

Open
nicholasdavies opened this issue Oct 15, 2024 · 6 comments

Comments

@nicholasdavies
Copy link

nicholasdavies commented Oct 15, 2024

#85

In debugger.lua, the where command uses string.gmatch to split Lua source loaded as a string into separate lines:

for line in info.source:gmatch("(.-)\n") do table.insert(source, line) end

If the string doesn't end with a newline, though, this doesn't include the last line and the where command fails to print anything when the debugger reaches that line.

My solution in the pull request is to explicitly add the last line of the string to source by following the above with:

table.insert(source, info.source:match("([^\n]*)$"))

I'm thinking now that instead of the * in the pattern, I ought to have used a + instead; that way if the string ends with a \n there isn't an empty "final line" added to source (instead, the match fails and nil gets inserted into the table, which does nothing).

@slembcke
Copy link
Owner

slembcke commented Oct 15, 2024

Hrm. All my editors default to inserting newlines (had to figure this out with a hex editor >_<), but VSCode did have an option to let me omit it. Even after that I've been unable to reproduce the issue though.

@nicholasdavies
Copy link
Author

nicholasdavies commented Oct 15, 2024

Sorry, should have been clearer! This could arise with a case like:

luaL_dostring(L, "print(1 + 'two')") // or some other buggy statement 

... with the debugger.lua error handler (msgh) activated. That's obviously kind of made up, but something like that might arise in e.g. a handrolled REPL taking one command at a time from the user. The easy solution is to add a newline to all the input, but one might wish to avoid allocating a new string to add a newline to the input if it's already allocated and we want to keep the code base streamlined.

In my specific case, this is for luajr which I e-mailed you about a few months back. luajr is an R wrapper to allow Lua code to be executed from the R statistical language. It came up in some test code along the lines of:

lua_mode(debug = "error") # trigger debugger.lua on Lua error
lua("local a = 1
local b = 'two'
return a + b")

where the last line wasn't showing up in the debugger.

@slembcke
Copy link
Owner

Gotcha. Actually I was wondering why load()ed strings didn't show their source sometimes, and it seems to be when they are one-liners. Apparently I never figured that out...

So I didn't have anything against your fix, but it was bugging me that there wasn't a single pattern that would work. I ended up coming up with this instead: 6e2fac8

Passes my existing tests, and works for strings executed using load(). Lemme know if that works for you too.

@nicholasdavies
Copy link
Author

nicholasdavies commented Oct 16, 2024

It bothered me too that there wasn't a single pattern, but I think what you have done here won't work for a different reason — if there are any "empty" lines in the input, they will be skipped over and not recognized as lines. For example, "print(hello)\n\nprint(goodbye)" will only get read as two lines rather than three. If empty lines occur multiple times in a long file or snippet I think that will mess up line locating.

I looked on Stack Overflow to see if anyone had come up with a way of doing this in a single pattern, and couldn't find anything. (There were questions, but the consensus was that it couldn't be done with Lua's patterns syntax.)

@nicholasdavies
Copy link
Author

nicholasdavies commented Oct 16, 2024

There are a couple of alternatives:

local start, stop = 1, nil
repeat
    stop = info.source:find('\n', start, true) or 0
    table.insert(source, info.source:sub(start, stop - 1))
    start = stop + 1
until stop == 0

or with an iterator defined elsewhere:

function lines(str)
    local start, stop = 1, -1
    return function()
        if stop == 0 then return nil end
        stop = str:find('\n', start, true) or 0
        start, line = stop + 1, str:sub(start, stop - 1)
        return line
    end
end
-- ...
for line in lines(info.source) do table.insert(source, line) end

but the iterator code I came up with is sort of long and involves making a closure. Although it's wordy, I think the repeat/until construct, or the original PR (though with + instead of *) are more elegant.

@nicholasdavies
Copy link
Author

Hello,

Just wanted to "bump" this as the fix you pushed breaks the debugger when there are empty lines in the input (see above), which will be very common when debugging e.g. Lua scripts from a file.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants