mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
api: auto generate api function wrappers for viml
This commit is contained in:
parent
de3a515123
commit
3bd3b3b768
@ -41,18 +41,20 @@ c_proto = Ct(
|
||||
)
|
||||
grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1)
|
||||
|
||||
-- we need at least 2 arguments since the last one is the output file
|
||||
assert(#arg >= 1)
|
||||
-- we need at least 3 arguments since the last two are output files
|
||||
assert(#arg >= 2)
|
||||
functions = {}
|
||||
|
||||
-- names of all headers relative to the source root (for inclusion in the
|
||||
-- generated file)
|
||||
headers = {}
|
||||
-- output file(dispatch function + metadata serialized with msgpack)
|
||||
outputf = arg[#arg]
|
||||
-- output c file(dispatch function + metadata serialized with msgpack)
|
||||
outputf = arg[#arg-1]
|
||||
-- output mpack file (metadata)
|
||||
mpack_outputf = arg[#arg]
|
||||
|
||||
-- read each input file, parse and append to the api metadata
|
||||
for i = 1, #arg - 1 do
|
||||
for i = 1, #arg - 2 do
|
||||
local full_path = arg[i]
|
||||
local parts = {}
|
||||
for part in string.gmatch(full_path, '[^/]+') do
|
||||
@ -165,7 +167,7 @@ for i = 1, #functions do
|
||||
local fn = functions[i]
|
||||
local args = {}
|
||||
|
||||
output:write('static Object handle_'..fn.name..'(uint64_t channel_id, uint64_t request_id, Array args, Error *error)')
|
||||
output:write('Object handle_'..fn.name..'(uint64_t channel_id, uint64_t request_id, Array args, Error *error)')
|
||||
output:write('\n{')
|
||||
output:write('\n Object ret = NIL;')
|
||||
-- Declare/initialize variables that will hold converted arguments
|
||||
@ -311,3 +313,7 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
|
||||
]])
|
||||
|
||||
output:close()
|
||||
|
||||
mpack_output = io.open(mpack_outputf, 'wb')
|
||||
mpack_output:write(packed)
|
||||
mpack_output:close()
|
||||
|
@ -1,5 +1,8 @@
|
||||
mpack = require('mpack')
|
||||
|
||||
local nvimsrcdir = arg[1]
|
||||
local autodir = arg[2]
|
||||
local metadata_file = arg[3]
|
||||
|
||||
if nvimsrcdir == '--help' then
|
||||
print([[
|
||||
@ -18,9 +21,20 @@ local funcsfname = autodir .. '/funcs.generated.h'
|
||||
|
||||
local funcspipe = io.open(funcsfname .. '.hsh', 'w')
|
||||
|
||||
local funcs = require('eval')
|
||||
local funcs = require('eval').funcs
|
||||
|
||||
for name, def in pairs(funcs.funcs) do
|
||||
local metadata = mpack.unpack(io.open(arg[3], 'rb'):read("*all"))
|
||||
|
||||
for i,fun in ipairs(metadata) do
|
||||
funcs['api_'..fun.name] = {
|
||||
args=#fun.parameters,
|
||||
func='api_wrapper',
|
||||
data='handle_'..fun.name,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
for name, def in pairs(funcs) do
|
||||
args = def.args or 0
|
||||
if type(args) == 'number' then
|
||||
args = {args, args}
|
||||
@ -28,7 +42,8 @@ for name, def in pairs(funcs.funcs) do
|
||||
args[2] = 'MAX_FUNC_ARGS'
|
||||
end
|
||||
func = def.func or ('f_' .. name)
|
||||
local val = ('{ %s, %s, &%s }'):format(args[1], args[2], func)
|
||||
data = def.data or "NULL"
|
||||
local val = ('{ %s, %s, &%s, %s }'):format(args[1], args[2], func, data)
|
||||
funcspipe:write(name .. '\n' .. val .. '\n')
|
||||
end
|
||||
funcspipe:close()
|
||||
|
@ -14,6 +14,7 @@ set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
|
||||
set(DISPATCH_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendispatch.lua)
|
||||
file(GLOB API_HEADERS api/*.h)
|
||||
file(GLOB MSGPACK_RPC_HEADERS msgpack_rpc/*.h)
|
||||
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
|
||||
set(HEADER_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendeclarations.lua)
|
||||
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
|
||||
set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch.c)
|
||||
@ -192,8 +193,8 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES}
|
||||
${EASTASIANWIDTH_FILE}
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_API_DISPATCH}
|
||||
COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${API_HEADERS} ${GENERATED_API_DISPATCH}
|
||||
add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${API_METADATA}
|
||||
COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${API_HEADERS} ${GENERATED_API_DISPATCH} ${API_METADATA}
|
||||
DEPENDS
|
||||
${API_HEADERS}
|
||||
${MSGPACK_RPC_HEADERS}
|
||||
@ -220,10 +221,10 @@ add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_FUNCS}
|
||||
COMMAND ${LUA_PRG} ${FUNCS_GENERATOR}
|
||||
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_DIR}
|
||||
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_DIR} ${API_METADATA}
|
||||
COMMAND $<TARGET_FILE:genhash>
|
||||
${GENERATED_FUNCS_HASH_INPUT} ${GENERATED_FUNCS} functions functions VimLFuncDef "NOFUNC"
|
||||
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} genhash
|
||||
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA} genhash
|
||||
)
|
||||
|
||||
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
#include "nvim/api/private/defs.h"
|
||||
|
||||
typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
|
||||
uint64_t request_id,
|
||||
Array args,
|
||||
Error *error);
|
||||
|
||||
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
|
||||
/// functions of this type.
|
||||
typedef struct {
|
||||
Object (*fn)(uint64_t channel_id,
|
||||
uint64_t request_id,
|
||||
Array args,
|
||||
Error *error);
|
||||
ApiDispatchWrapper fn;
|
||||
bool async; // function is always safe to run immediately instead of being
|
||||
// put in a request queue for handling when nvim waits for input.
|
||||
} MsgpackRpcRequestHandler;
|
||||
|
@ -445,13 +445,14 @@ typedef struct {
|
||||
} timer_T;
|
||||
|
||||
/// Prototype of C function that implements VimL function
|
||||
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar);
|
||||
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, void *data);
|
||||
|
||||
/// Structure holding VimL function definition
|
||||
typedef struct fst {
|
||||
uint8_t min_argc; ///< Minimal number of arguments.
|
||||
uint8_t max_argc; ///< Maximal number of arguments.
|
||||
VimLFunc func; ///< Function implementation.
|
||||
void *data; ///< Userdata for function implementation.
|
||||
} VimLFuncDef;
|
||||
|
||||
KHASH_MAP_INIT_STR(functions, VimLFuncDef)
|
||||
@ -6981,7 +6982,7 @@ call_func (
|
||||
}
|
||||
} else {
|
||||
// Find the function name in the table, call its implementation.
|
||||
VimLFuncDef *const fdef = find_internal_func((char *) fname);
|
||||
VimLFuncDef *const fdef = find_internal_func((char *)fname);
|
||||
if (fdef != NULL) {
|
||||
if (argcount < fdef->min_argc) {
|
||||
error = ERROR_TOOFEW;
|
||||
@ -6989,7 +6990,7 @@ call_func (
|
||||
error = ERROR_TOOMANY;
|
||||
} else {
|
||||
argvars[argcount].v_type = VAR_UNKNOWN;
|
||||
fdef->func(argvars, rettv);
|
||||
fdef->func(argvars, rettv, fdef->data);
|
||||
error = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
@ -7100,13 +7101,10 @@ static inline int get_float_arg(typval_T *argvars, float_T *f)
|
||||
// Some versions of glibc on i386 have an optimization that makes it harder to
|
||||
// call math functions indirectly from inside an inlined function, causing
|
||||
// compile-time errors. Avoid `inline` in that case. #3072
|
||||
#ifndef ARCH_32
|
||||
inline
|
||||
#endif
|
||||
static void float_op_wrapper(typval_T *argvars, typval_T *rettv,
|
||||
float_T (*function)(float_T))
|
||||
static void float_op_wrapper(typval_T *argvars, typval_T *rettv, void *data)
|
||||
{
|
||||
float_T f;
|
||||
float_T (*function)(float_T) = data;
|
||||
|
||||
rettv->v_type = VAR_FLOAT;
|
||||
if (get_float_arg(argvars, &f) == OK) {
|
||||
@ -7116,6 +7114,34 @@ static void float_op_wrapper(typval_T *argvars, typval_T *rettv,
|
||||
}
|
||||
}
|
||||
|
||||
static void api_wrapper(typval_T *argvars, typval_T *rettv, void *data)
|
||||
{
|
||||
ApiDispatchWrapper fn = data;
|
||||
|
||||
Array args = ARRAY_DICT_INIT;
|
||||
|
||||
for (typval_T *tv = argvars; tv->v_type != VAR_UNKNOWN; tv++) {
|
||||
ADD(args, vim_to_object(tv));
|
||||
}
|
||||
|
||||
Error err = ERROR_INIT;
|
||||
Object result = fn(-1, -1, args, &err);
|
||||
|
||||
if (err.set) {
|
||||
vim_report_error(cstr_as_string(err.msg));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!object_to_vim(result, rettv, &err)) {
|
||||
EMSG2(_("Error converting the call result: %s"), err.msg);
|
||||
}
|
||||
|
||||
end:
|
||||
// All arguments were freed already, but we still need to free the array
|
||||
xfree(args.items);
|
||||
api_free_object(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* "abs(expr)" function
|
||||
*/
|
||||
@ -7515,14 +7541,6 @@ static void f_asin(typval_T *argvars, typval_T *rettv)
|
||||
float_op_wrapper(argvars, rettv, &asin);
|
||||
}
|
||||
|
||||
/*
|
||||
* "atan()" function
|
||||
*/
|
||||
static void f_atan(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
float_op_wrapper(argvars, rettv, &atan);
|
||||
}
|
||||
|
||||
/*
|
||||
* "atan2()" function
|
||||
*/
|
||||
@ -20115,7 +20133,7 @@ void free_all_functions(void)
|
||||
int translated_function_exists(char_u *name)
|
||||
{
|
||||
if (builtin_function(name, -1)) {
|
||||
return find_internal_func((char *) name) != NULL;
|
||||
return find_internal_func((char *)name) != NULL;
|
||||
}
|
||||
return find_func(name) != NULL;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ return {
|
||||
assert_notequal={args={2, 3}},
|
||||
assert_notmatch={args={2, 3}},
|
||||
assert_true={args={1, 2}},
|
||||
atan={args=1},
|
||||
atan={args=1, func="float_op_wrapper", data="atan"},
|
||||
atan2={args=2},
|
||||
browse={args=4},
|
||||
browsedir={args=2},
|
||||
|
Loading…
Reference in New Issue
Block a user