eval: Add luaeval function

No tests yet, no documentation update, no :lua* stuff, no vim module.

converter.c should also work with typval_T, not Object.

Known problem: luaeval("1", {}) results in

    PANIC: unprotected error in call to Lua API (attempt to index a nil value)

Ref #3823
This commit is contained in:
ZyX
2016-03-04 21:55:28 +03:00
parent f9a31e9850
commit e7bbd8256b
11 changed files with 1100 additions and 14 deletions

View File

@@ -0,0 +1,38 @@
assert(#arg == 2)
module_file = arg[1]
target_file = arg[2]
module = io.open(module_file, 'r')
target = io.open(target_file, 'w')
target:write('#include <stdint.h>\n\n')
target:write('static const uint8_t vim_module[] = {\n')
num_bytes = 0
MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line
target:write(' ')
increase_num_bytes = function()
num_bytes = num_bytes + 1
if num_bytes == MAX_NUM_BYTES then
num_bytes = 0
target:write('\n ')
end
end
for line in module:lines() do
for i = 1,string.len(line) do
byte = string.byte(line, i)
assert(byte ~= 0)
target:write(string.format(' %3u,', byte))
increase_num_bytes()
end
target:write(string.format(' %3u,', string.byte('\n', 1)))
increase_num_bytes()
end
target:write(' 0};\n')
module:close()
target:close()

View File

@@ -45,7 +45,16 @@ c_proto = Ct(
grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1)
-- we need at least 4 arguments since the last two are output files
assert(#arg >= 3)
if arg[1] == '--help' then
print('Usage: genmsgpack.lua args')
print('Args: 1: source directory')
print(' 2: dispatch output file (dispatch_wrappers.generated.h)')
print(' 3: functions metadata output file (funcs_metadata.generated.h)')
print(' 4: API metadata output file (api_metadata.mpack)')
print(' 5: lua C bindings output file (msgpack_lua_c_bindings.generated.c)')
print(' rest: C files where API functions are defined')
end
assert(#arg >= 4)
functions = {}
local nvimsrcdir = arg[1]
@@ -56,17 +65,18 @@ package.path = nvimsrcdir .. '/?.lua;' .. package.path
headers = {}
-- output h file with generated dispatch functions
dispatch_outputf = arg[#arg-2]
dispatch_outputf = arg[2]
-- output h file with packed metadata
funcs_metadata_outputf = arg[#arg-1]
funcs_metadata_outputf = arg[3]
-- output metadata mpack file, for use by other build scripts
mpack_outputf = arg[#arg]
mpack_outputf = arg[4]
lua_c_bindings_outputf = arg[5]
-- set of function names, used to detect duplicates
function_names = {}
-- read each input file, parse and append to the api metadata
for i = 2, #arg - 3 do
for i = 6, #arg do
local full_path = arg[i]
local parts = {}
for part in string.gmatch(full_path, '[^/]+') do
@@ -332,3 +342,128 @@ output:close()
mpack_output = io.open(mpack_outputf, 'wb')
mpack_output:write(mpack.pack(functions))
mpack_output:close()
local function include_headers(output, headers)
for i = 1, #headers do
if headers[i]:sub(-12) ~= '.generated.h' then
output:write('\n#include "nvim/'..headers[i]..'"')
end
end
end
local function write_shifted_output(output, str)
str = str:gsub('\n ', '\n')
str = str:gsub('^ ', '')
str = str:gsub(' +$', '')
output:write(str)
end
-- start building lua output
output = io.open(lua_c_bindings_outputf, 'wb')
output:write([[
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "nvim/func_attr.h"
#include "nvim/api/private/defs.h"
#include "nvim/viml/executor/converter.h"
]])
include_headers(output, headers)
output:write('\n')
lua_c_functions = {}
local function process_function(fn)
lua_c_function_name = ('nlua_msgpack_%s'):format(fn.name)
write_shifted_output(output, string.format([[
static int %s(lua_State *lstate)
{
Error err = {.set = false};
]], lua_c_function_name))
lua_c_functions[#lua_c_functions + 1] = {
binding=lua_c_function_name,
api=fn.name
}
cparams = ''
for j, param in ipairs(fn.parameters) do
cparam = string.format('arg%u', j)
if param[1]:match('^ArrayOf') then
param_type = 'Array'
else
param_type = param[1]
end
write_shifted_output(output, string.format([[
%s %s = nlua_pop_%s(lstate, &err);
if (err.set) {
lua_pushstring(lstate, err.msg);
return lua_error(lstate);
}
]], param[1], cparam, param_type))
cparams = cparams .. cparam .. ', '
end
if fn.receives_channel_id then
cparams = 'INTERNAL_CALL, ' .. cparams
end
if fn.can_fail then
cparams = cparams .. '&err'
else
cparams = cparams:gsub(', $', '')
end
local name = fn.impl_name or fn.name
if fn.return_type ~= 'void' then
if fn.return_type:match('^ArrayOf') then
return_type = 'Array'
else
return_type = fn.return_type
end
write_shifted_output(output, string.format([[
%s ret = %s(%s);
if (err.set) {
lua_pushstring(lstate, err.msg);
return lua_error(lstate);
}
nlua_push_%s(lstate, ret);
return 1;
]], fn.return_type, name, cparams, return_type))
else
write_shifted_output(output, string.format([[
%s(%s);
if (err.set) {
lua_pushstring(lstate, err.msg);
return lua_error(lstate);
}
return 0;
]], name, cparams))
end
write_shifted_output(output, [[
}
]])
end
for _, fn in ipairs(functions) do
if not fn.noeval then
process_function(fn)
end
end
output:write(string.format([[
void nlua_add_api_functions(lua_State *lstate)
FUNC_ATTR_NONNULL_ALL
{
lua_createtable(lstate, 0, %u);
]], #lua_c_functions))
for _, func in ipairs(lua_c_functions) do
output:write(string.format([[
lua_pushcfunction(lstate, &%s);
lua_setfield(lstate, -2, "%s");
]], func.binding, func.api))
end
output:write([[
lua_setfield(lstate, -2, "api");
}
]])
output:close()