support multiple simultaneous breakpoints in coroutines
This commit is contained in:
@@ -3,7 +3,13 @@
|
|||||||
|
|
||||||
local fs = _G.fs
|
local fs = _G.fs
|
||||||
|
|
||||||
local dbg = { }
|
local dbg = {
|
||||||
|
hooks = { },
|
||||||
|
waits = { },
|
||||||
|
debugger = nil,
|
||||||
|
breakpoints = nil,
|
||||||
|
}
|
||||||
|
_G._dbg = dbg -- for testing purposes
|
||||||
|
|
||||||
local function breakpointHook(info)
|
local function breakpointHook(info)
|
||||||
if dbg.breakpoints then
|
if dbg.breakpoints then
|
||||||
@@ -22,15 +28,12 @@ local function functionHook(fn)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function stepHook()
|
local function stepHook()
|
||||||
local co = coroutine.running()
|
return function()
|
||||||
return function(info)
|
return true
|
||||||
return co == coroutine.running()
|
|
||||||
or breakpointHook(info)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function stackSizeHook(n)
|
local function stackSizeHook(n)
|
||||||
local co = coroutine.running()
|
|
||||||
local i = 2
|
local i = 2
|
||||||
while true do
|
while true do
|
||||||
local info = debug.getinfo(i)
|
local info = debug.getinfo(i)
|
||||||
@@ -40,8 +43,7 @@ local function stackSizeHook(n)
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
return function(info)
|
return function(info)
|
||||||
return co == coroutine.running()
|
return not debug.getinfo(i - n)
|
||||||
and not debug.getinfo(i - n)
|
|
||||||
or breakpointHook(info)
|
or breakpointHook(info)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -54,8 +56,6 @@ local function stepOverHook()
|
|||||||
return stackSizeHook(0)
|
return stackSizeHook(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local hookEval = function() end
|
|
||||||
|
|
||||||
-- Create a table of all the locally accessible variables.
|
-- Create a table of all the locally accessible variables.
|
||||||
local function local_bindings(offset, stack_inspect_offset)
|
local function local_bindings(offset, stack_inspect_offset)
|
||||||
offset = offset + 1 + stack_inspect_offset -- add this function to the offset
|
offset = offset + 1 + stack_inspect_offset -- add this function to the offset
|
||||||
@@ -133,14 +133,12 @@ local function get_trace(offset, stack_inspect_offset)
|
|||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
local inHook = false
|
|
||||||
|
|
||||||
local function hook()
|
local function hook()
|
||||||
local info = debug.getinfo(2)
|
local info = debug.getinfo(2)
|
||||||
|
|
||||||
if not inHook and hookEval(info) then
|
local h = dbg.hooks[coroutine.running()]
|
||||||
inHook = true
|
|
||||||
|
|
||||||
|
if h and h.eval(info) then
|
||||||
local inspectOffset = 0
|
local inspectOffset = 0
|
||||||
|
|
||||||
repeat
|
repeat
|
||||||
@@ -153,6 +151,10 @@ local function hook()
|
|||||||
}
|
}
|
||||||
inspectOffset = 0 -- reset
|
inspectOffset = 0 -- reset
|
||||||
|
|
||||||
|
table.insert(dbg.waits, h)
|
||||||
|
while dbg.waits[1] ~= h do
|
||||||
|
os.sleep(.1)
|
||||||
|
end
|
||||||
os.queueEvent('debuggerX', dbg.debugger.uid, snapshot)
|
os.queueEvent('debuggerX', dbg.debugger.uid, snapshot)
|
||||||
|
|
||||||
local e, cmd, param
|
local e, cmd, param
|
||||||
@@ -160,25 +162,24 @@ local function hook()
|
|||||||
e, cmd, param = os.pullEvent('debugger')
|
e, cmd, param = os.pullEvent('debugger')
|
||||||
until e == 'debugger'
|
until e == 'debugger'
|
||||||
|
|
||||||
|
table.remove(dbg.waits, 1)
|
||||||
|
|
||||||
if cmd == 's' then
|
if cmd == 's' then
|
||||||
hookEval = stepHook()
|
h.eval = stepHook()
|
||||||
elseif cmd == 'n' then
|
elseif cmd == 'n' then
|
||||||
hookEval = stepOverHook()
|
h.eval = stepOverHook()
|
||||||
elseif cmd == 'f' then
|
elseif cmd == 'f' then
|
||||||
hookEval = stepOutHook()
|
h.eval = stepOutHook()
|
||||||
elseif cmd == 'c' then
|
elseif cmd == 'c' then
|
||||||
hookEval = breakpointHook
|
h.eval = breakpointHook
|
||||||
elseif cmd == 'i' then
|
elseif cmd == 'i' then
|
||||||
-- get snapshot of stack at this offset
|
-- get snapshot of stack at this offset
|
||||||
inspectOffset = param
|
inspectOffset = param
|
||||||
done = false
|
done = false
|
||||||
else
|
else
|
||||||
os.sleep(1)
|
|
||||||
done = false
|
done = false
|
||||||
end
|
end
|
||||||
until done
|
until done
|
||||||
|
|
||||||
inHook = false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -189,19 +190,23 @@ function dbg.call(fn, ...)
|
|||||||
fn(table.unpack(args))
|
fn(table.unpack(args))
|
||||||
end,
|
end,
|
||||||
function(err)
|
function(err)
|
||||||
hookEval = stepHook()
|
dbg.hooks[coroutine.running()].eval = stepHook()
|
||||||
|
|
||||||
-- An error has occurred
|
-- An error has occurred
|
||||||
return err
|
return err
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
_ENV.coroutine = setmetatable({
|
dbg.stopIn = function(fn)
|
||||||
|
dbg.hooks[coroutine.running()].eval = functionHook(fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
_ENV.coroutine = setmetatable({
|
||||||
create = function(fn)
|
create = function(fn)
|
||||||
local co = _G.coroutine.create(function(...)
|
local co = _G.coroutine.create(function(...)
|
||||||
local r = { dbg.call(fn, ...) }
|
local r = { dbg.call(fn, ...) }
|
||||||
|
|
||||||
|
dbg.hooks[coroutine.running()] = nil
|
||||||
if not r[1] then
|
if not r[1] then
|
||||||
error(r[2], -1)
|
error(r[2], -1)
|
||||||
end
|
end
|
||||||
@@ -209,24 +214,19 @@ _ENV.coroutine = setmetatable({
|
|||||||
return table.unpack(r, 2)
|
return table.unpack(r, 2)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
dbg.hooks[co] = {
|
||||||
|
co = co,
|
||||||
|
eval = breakpointHook,
|
||||||
|
}
|
||||||
debug.sethook(co, hook, 'l')
|
debug.sethook(co, hook, 'l')
|
||||||
return co
|
return co
|
||||||
end
|
end
|
||||||
--[[
|
|
||||||
create = function(f)
|
|
||||||
local co = _G.coroutine.create(f)
|
|
||||||
debug.sethook(co, hook, 'l')
|
|
||||||
return co
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
}, { __index = coroutine })
|
}, { __index = coroutine })
|
||||||
|
|
||||||
|
dbg.hooks[coroutine.running()] = {
|
||||||
|
co = coroutine.running(),
|
||||||
|
eval = function() return false end,
|
||||||
|
}
|
||||||
|
|
||||||
debug.sethook(hook, 'l')
|
debug.sethook(hook, 'l')
|
||||||
|
|
||||||
-- Expose the debugger's functions
|
|
||||||
dbg.stopIn = function(fn)
|
|
||||||
hookEval = functionHook(fn)
|
|
||||||
end
|
|
||||||
dbg.debugger = nil
|
|
||||||
|
|
||||||
return dbg
|
return dbg
|
||||||
|
|||||||
@@ -10,6 +10,28 @@ local function method(times)
|
|||||||
return m2(a)
|
return m2(a)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local Event = require('opus.event')
|
||||||
|
|
||||||
|
Event.on('event1', function()
|
||||||
|
print('event1')
|
||||||
|
end)
|
||||||
|
|
||||||
|
Event.on('event2', function()
|
||||||
|
print('event2')
|
||||||
|
end)
|
||||||
|
|
||||||
|
Event.onTimeout(10, function()
|
||||||
|
Event.exitPullEvents()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function xx()
|
||||||
|
os.queueEvent('event1')
|
||||||
|
os.queueEvent('event2')
|
||||||
|
|
||||||
|
Event.pullEvents()
|
||||||
|
end
|
||||||
|
xx()
|
||||||
|
|
||||||
local chunk = load([[
|
local chunk = load([[
|
||||||
local j = 5
|
local j = 5
|
||||||
for i = 1, 5 do
|
for i = 1, 5 do
|
||||||
|
|||||||
Reference in New Issue
Block a user