diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2017-05-09 00:39:17 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-05-09 00:39:17 +0200 | 
| commit | 0e873a30f3072dbacfb700f1e331a8c8396f2e1f (patch) | |
| tree | 557792d454fef510a90975bed4e7d1650ee26c4f /scripts | |
| parent | a9981e0e7e9439340bb8c0162f860b78d8002559 (diff) | |
| parent | 5b6d598ca8301682d931539ecd6da6a9fabae569 (diff) | |
| download | rneovim-0e873a30f3072dbacfb700f1e331a8c8396f2e1f.tar.gz rneovim-0e873a30f3072dbacfb700f1e331a8c8396f2e1f.tar.bz2 rneovim-0e873a30f3072dbacfb700f1e331a8c8396f2e1f.zip | |
Merge #4411 from ZyX-I/luaviml'/lua
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/gencharblob.lua | 48 | ||||
| -rwxr-xr-x | scripts/gendeclarations.lua | 64 | ||||
| -rw-r--r-- | scripts/genmsgpack.lua (renamed from scripts/gendispatch.lua) | 196 | 
3 files changed, 278 insertions, 30 deletions
| diff --git a/scripts/gencharblob.lua b/scripts/gencharblob.lua new file mode 100644 index 0000000000..d860375e26 --- /dev/null +++ b/scripts/gencharblob.lua @@ -0,0 +1,48 @@ +if arg[1] == '--help' then +  print('Usage:') +  print('  gencharblob.lua source target varname') +  print('') +  print('Generates C file with big uint8_t blob.') +  print('Blob will be stored in a static const array named varname.') +  os.exit() +end + +assert(#arg == 3) + +local source_file = arg[1] +local target_file = arg[2] +local varname = arg[3] + +source = io.open(source_file, 'r') +target = io.open(target_file, 'w') + +target:write('#include <stdint.h>\n\n') +target:write(('static const uint8_t %s[] = {\n'):format(varname)) + +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 source: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') + +source:close() +target:close() diff --git a/scripts/gendeclarations.lua b/scripts/gendeclarations.lua index ff69b18ae4..e999e53e4a 100755 --- a/scripts/gendeclarations.lua +++ b/scripts/gendeclarations.lua @@ -69,17 +69,18 @@ local word = branch(      right_word    )  ) +local inline_comment = concat( +  lit('/*'), +  any_amount(concat( +    neg_look_ahead(lit('*/')), +    any_character +  )), +  lit('*/') +)  local spaces = any_amount(branch(    s,    -- Comments are really handled by preprocessor, so the following is not needed -  concat( -    lit('/*'), -    any_amount(concat( -      neg_look_ahead(lit('*/')), -      any_character -    )), -    lit('*/') -  ), +  inline_comment,    concat(      lit('//'),      any_amount(concat( @@ -110,6 +111,7 @@ local typ = one_or_more(typ_part)  local typ_id = two_or_more(typ_part)  local arg = typ_id         -- argument name is swallowed by typ  local pattern = concat( +  any_amount(branch(set(' ', '\t'), inline_comment)),    typ_id,                  -- return type with function name    spaces,    lit('('), @@ -188,24 +190,44 @@ local footer = [[  local non_static = header  local static = header -local filepattern = '^#%a* %d+ "[^"]-/?([^"/]+)"' +local filepattern = '^#%a* (%d+) "([^"]-)/?([^"/]+)"'  local curfile -init = 0 -curfile = nil -neededfile = fname:match('[^/]+$') +local init = 0 +local curfile = nil +local neededfile = fname:match('[^/]+$') +local declline = 0 +local declendpos = 0 +local curdir = nil +local is_needed_file = false  while init ~= nil do -  init = text:find('\n', init) +  init = text:find('[\n;}]', init)    if init == nil then      break    end +  local init_is_nl = text:sub(init, init) == '\n'    init = init + 1 -  if text:sub(init, init) == '#' then -    file = text:match(filepattern, init) +  if init_is_nl and is_needed_file then +    declline = declline + 1 +  end +  if init_is_nl and text:sub(init, init) == '#' then +    local line, dir, file = text:match(filepattern, init)      if file ~= nil then        curfile = file +      is_needed_file = (curfile == neededfile) +      declline = tonumber(line) - 1 +      local curdir_start = dir:find('src/nvim/') +      if curdir_start ~= nil then +        curdir = dir:sub(curdir_start + #('src/nvim/')) +      else +        curdir = dir +      end +    else +      declline = declline - 1      end -  elseif curfile == neededfile then +  elseif init < declendpos then +    -- Skipping over declaration +  elseif is_needed_file then      s = init      e = pattern:match(text, init)      if e ~= nil then @@ -225,13 +247,17 @@ while init ~= nil do        declaration = declaration:gsub(' ?(%*+) ?', ' %1')        declaration = declaration:gsub(' ?(FUNC_ATTR_)', ' %1')        declaration = declaration:gsub(' $', '') -      declaration = declaration .. ';\n' -      if text:sub(s, s + 5) == 'static' then +      declaration = declaration:gsub('^ ', '') +      declaration = declaration .. ';' +      declaration = declaration .. ('  // %s/%s:%u'):format( +          curdir, curfile, declline) +      declaration = declaration .. '\n' +      if declaration:sub(1, 6) == 'static' then          static = static .. declaration        else          non_static = non_static .. declaration        end -      init = e +      declendpos = e      end    end  end diff --git a/scripts/gendispatch.lua b/scripts/genmsgpack.lua index c0291c55d3..86a051fb4c 100644 --- a/scripts/gendispatch.lua +++ b/scripts/genmsgpack.lua @@ -47,7 +47,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] @@ -58,17 +67,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 @@ -119,7 +129,9 @@ local deprecated_aliases = require("api.dispatch_deprecated")  for i,f in ipairs(shallowcopy(functions)) do    local ismethod = false    if startswith(f.name, "nvim_") then -    if f.since == nil then +    if startswith(f.name, "nvim__") then +      f.since = -1 +    elseif f.since == nil then        print("Function "..f.name.." lacks since field.\n")        os.exit(1)      end @@ -170,11 +182,13 @@ exported_attributes = {'name', 'parameters', 'return_type', 'method',                         'since', 'deprecated_since'}  exported_functions = {}  for _,f in ipairs(functions) do -  local f_exported = {} -  for _,attr in ipairs(exported_attributes) do -    f_exported[attr] = f[attr] +  if not startswith(f.name, "nvim__") then +    local f_exported = {} +    for _,attr in ipairs(exported_attributes) do +      f_exported[attr] = f[attr] +    end +    exported_functions[#exported_functions+1] = f_exported    end -  exported_functions[#exported_functions+1] = f_exported  end @@ -212,6 +226,14 @@ local function real_type(type)    return rv  end +local function attr_name(rt) +  if rt == 'Float' then +    return 'floating' +  else +    return rt:lower() +  end +end +  -- start the handler functions. Visit each function metadata to build the  -- handler function with code generated for validating arguments and calling to  -- the real API. @@ -248,7 +270,7 @@ for i = 1, #functions do            output:write('\n    '..converted..' = (handle_T)args.items['..(j - 1)..'].data.integer;')          else            output:write('\n  if (args.items['..(j - 1)..'].type == kObjectType'..rt..') {') -          output:write('\n    '..converted..' = args.items['..(j - 1)..'].data.'..rt:lower()..';') +          output:write('\n    '..converted..' = args.items['..(j - 1)..'].data.'..attr_name(rt)..';')          end          if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') or rt:match('^Boolean$') then            -- accept nonnegative integers for Booleans, Buffers, Windows and Tabpages @@ -336,3 +358,155 @@ 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/api/private/helpers.h" +#include "nvim/lua/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 = ERROR_INIT; +    if (lua_gettop(lstate) != %i) { +      api_set_error(&err, kErrorTypeValidation, "Expected %i argument%s"); +      goto exit_0; +    } +  ]], lua_c_function_name, #fn.parameters, #fn.parameters, +      (#fn.parameters == 1) and '' or 's')) +  lua_c_functions[#lua_c_functions + 1] = { +    binding=lua_c_function_name, +    api=fn.name +  } +  local cparams = '' +  local free_code = {} +  for j = #fn.parameters,1,-1 do +    param = fn.parameters[j] +    cparam = string.format('arg%u', j) +    param_type = real_type(param[1]) +    lc_param_type = param_type:lower() +    write_shifted_output(output, string.format([[ +    const %s %s = nlua_pop_%s(lstate, &err); + +    if (ERROR_SET(&err)) { +      goto exit_%u; +    } +    ]], param[1], cparam, param_type, #fn.parameters - j)) +    free_code[#free_code + 1] = ('api_free_%s(%s);'):format( +      lc_param_type, cparam) +    cparams = cparam .. ', ' .. cparams +  end +  if fn.receives_channel_id then +    cparams = 'LUA_INTERNAL_CALL, ' .. cparams +  end +  if fn.can_fail then +    cparams = cparams .. '&err' +  else +    cparams = cparams:gsub(', $', '') +  end +  local free_at_exit_code = '' +  for i = 1, #free_code do +    local rev_i = #free_code - i + 1 +    local code = free_code[rev_i] +    if i == 1 then +      free_at_exit_code = free_at_exit_code .. ('\n    %s'):format(code) +    else +      free_at_exit_code = free_at_exit_code .. ('\n  exit_%u:\n    %s'):format( +        rev_i, code) +    end +  end +  local err_throw_code = [[ + +  exit_0: +    if (ERROR_SET(&err)) { +      luaL_where(lstate, 1); +      lua_pushstring(lstate, err.msg); +      api_clear_error(&err); +      lua_concat(lstate, 2); +      return lua_error(lstate); +    } +  ]] +  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([[ +    const %s ret = %s(%s); +    nlua_push_%s(lstate, ret); +    api_free_%s(ret); +  %s +  %s +    return 1; +    ]], fn.return_type, fn.name, cparams, return_type, return_type:lower(), +        free_at_exit_code, err_throw_code)) +  else +    write_shifted_output(output, string.format([[ +    %s(%s); +  %s +  %s +    return 0; +    ]], fn.name, cparams, free_at_exit_code, err_throw_code)) +  end +  write_shifted_output(output, [[ +  } +  ]]) +end + +for _, fn in ipairs(functions) do +  if not fn.noeval or fn.name:sub(1, 4) == '_vim' 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() | 
