If args is valid, assert it's a table.
Provides a clear and immediate error message when you convert
add_timeout() to call().
Also add type_or_nil. Very useful for optional parameters like this one.
Seems clearer than checking the arg first:
if args then assert:type() end
See Davidobot/love.js#54.
lovejs crashes love with "attempt to yield across metamethod/C-call
boundary" when you try to yield in a coroutine, so we skip wrapping.
We lose the coroutine-local callstack, but at least it works.
Here's my repro:
local color = {
purple = {0.25, 0.09, 0.28, 1},
white = {0.89, 0.91, 0.90, 1},
}
local ball = {
x = 100,
y = 100,
r = 20,
}
local S = {}
local input = {
vanilla = 'v',
async = 'c',
quit = 'escape',
}
function love.load()
S.coro = async()
end
local function coro_fn()
S.async_running = true
for i=1,100 do
color.purple[4] = i / 100
coroutine.yield()
end
color.purple[4] = 1
S.async_running = false
return true
end
function love.update(dt)
S.coro:update(dt)
if S.vanilla then
local success, result = coroutine.resume(S.vanilla)
if result then
print("coroutine cleared")
S.vanilla = nil
end
end
if not S.async_running then
if love.keyboard.isDown(input.vanilla) then
S.vanilla = coroutine.create(coro_fn)
print("raw coroutine started")
elseif love.keyboard.isDown(input.async) then
print("Starting async call coroutine from update")
S.coro:call(coro_fn)
elseif love.keyboard.isDown(input.quit) then
love.event.quit()
end
end
end
function love.draw()
love.graphics.setColor(color.purple)
love.graphics.circle("fill", ball.x, ball.y, ball.r)
love.graphics.setColor(color.white)
local str = "To start a coroutine:"
for key,val in pairs(input) do
str = ("%s\n%s: %s"):format(str, key, val)
end
love.graphics.printf(str, 5,5, 200, "left")
end
Instead of only capturing 8 temps, pass resume to a function so we can
capture all returned values as ...
I might be missing a reason why you wouldn't do it like this.
Test
-- coro is an async() updated in love.update
coro:call(
function()
coro.wait(1)
print("jump")
self.gravity.y = -900
coro.wait(1)
print("fall")
self.gravity.y = 900
coroutine.yield "hello"
return "done"
end,
nil,
function(...)
print("complete", ...)
end)
tl;dr is that new no longer needs to call init, calling :new() directly in user code is not allowed, properties are copied, metamethods work, and a config table is needed rather than a class to extend from, so use {extends = superclass} if you want a minimal fix