Allow transpile.lua to be run directly.

• Fix `async for` loops inside asynchronous functions.
 • Allow transpile.lua to be called directly.
This commit is contained in:
luk3yx 2019-08-24 21:10:10 +12:00
parent d2ac8715cf
commit d15e43528e
5 changed files with 55 additions and 12 deletions

View File

@ -173,6 +173,21 @@ The following functions only work inside coroutines:
The custom lua syntax introduced by this mod is "transpiled" back into regular
lua, and can only be used with `asyncio.dofile` etc.
### Pre-runtime transpiling
**If you are going to be using Minetest's insecure environment from a file
using this custom syntax, I strongly recommend avoiding `asyncio.loadfile`
etc.**
To invoke the transpiler outside of Minetest, you can simply run
`lua transpile.lua /path/to/file.async.lua`. This should print the transpiled
code. If you want it to write the transpiled code to a different file, provided
you are on a UNIX-like OS, you can run
`lua transpile.lua file.async.lua > file.lua`.
*Note that `async for` loops will always be mangled ensure compatibility with
Lua 5.1.*
## Coroutines
asyncio coroutines can be created in one of two ways:

View File

@ -200,6 +200,7 @@ local function iter(func, ...)
end
end
asyncio.iter = iter
asyncio._iter_start = iter
-- Lua 5.1 (excluding LuaJIT) compatibility
asyncio.lua51 = _VERSION < 'Lua 5.2'

View File

@ -10,8 +10,8 @@
local lock_states = {}
local lock_callbacks = {}
setmetatable(lock_states, {__mode = 'kv'})
setmetatable(lock_callbacks, {__mode = 'k'})
setmetatable(lock_states, {__mode = 'kv'})
setmetatable(lock_callbacks, {__mode = 'k'})
-- Create the functions
-- https://docs.python.org/3/library/asyncio-sync.html#lock

View File

@ -7,10 +7,6 @@ local rawequal = rawequal
minetest.log('warning', '[asyncio] LuaJIT not installed, asyncio.iter() ' ..
'will be less efficient.')
-- Keep the original asyncio.iter accessible, this is used in the workaround
-- iter function and in the transpiler.
asyncio._iter_start = asyncio.iter
-- Helper functions
local function pack_len(...)
local res = {...}

View File

@ -18,6 +18,7 @@ end
-- Matches
-- These take 2-3 arguments (code, res, char) and should return code and res.
local lua51 = not asyncio or asyncio.lua51
local matches
matches = {
-- Handle multi-line strings and comments
@ -121,6 +122,12 @@ matches = {
local func = matches[char] or matches[pattern]
assert(func, 'No function found for pattern!')
code, res = func(code:sub(e + 1), res, char)
-- Increase the level for async for loops
if lua51 and (pattern == '^async for ' or
pattern == '[%s;%[]async for ') then
lvl = lvl + 1
end
end
end
@ -147,7 +154,7 @@ matches = {
}
-- A workaround for Lua 5.1's iterator limitations.
if not asyncio or asyncio.lua51 then
if lua51 then
local orig = matches['async for ']
matches['async for '] = function(code, res, char)
if char:sub(1, 1) ~= 'a' then res = res .. char:sub(1, 1) end
@ -209,12 +216,36 @@ local function transpile(code)
return res .. code
end
-- Testing
if not asyncio then
local f = io.open('test.lua')
print(transpile(f:read '*a'))
-- Handle being called outside of Minetest.
if not asyncio or not minetest then
-- If this is called via dofile(), just return the function.
if not arg or debug.getinfo(3) then
return transpile
end
return transpile
if not arg[1] or arg[1] == '' then
print('Invalid usage.')
print('Usage: transpile.lua <file>')
os.exit(1)
end
-- Read the file
local f, err, errcode = io.open(arg[1], 'r')
if not f then
print(err)
os.exit(errcode)
end
local code, err, errcode = f:read('*a')
f:close()
if not code then
print(err)
os.exit(errcode)
end
-- Print the output
print(transpile(code))
os.exit(0)
end
-- Lua 5.2+ compatibility