refactor(api): use typed keysets

Initially this is just for geting rid of boilerplate,
but eventually the types could get exposed as metadata
This commit is contained in:
bfredl
2023-08-01 14:01:19 +02:00
parent c01e624b07
commit 7bc93e0e2f
23 changed files with 771 additions and 866 deletions

View File

@@ -67,13 +67,27 @@ local keysets = {}
local function add_keyset(val)
local keys = {}
for _,field in ipairs(val.fields) do
local types = {}
local is_set_name = 'is_set__' .. val.keyset_name .. '_'
local has_optional = false
for i,field in ipairs(val.fields) do
if field.type ~= 'Object' then
error 'not yet implemented: types other than Object'
types[field.name] = field.type
end
if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then
table.insert(keys, field.name)
else
if i > 1 then
error("'is_set__{type}_' must be first if present")
elseif field.name ~= is_set_name then
error(val.keyset_name..": name of first key should be "..is_set_name)
elseif field.type ~= 'OptionalKeys' then
error("'"..is_set_name.."' must have type 'OptionalKeys'")
end
has_optional = true
end
table.insert(keys, {field.name, field.type})
end
table.insert(keysets, {val.keyset_name, keys})
table.insert(keysets, {name=val.keyset_name, keys=keys, types=types, has_optional=has_optional})
end
-- read each input file, parse and append to the api metadata
@@ -232,53 +246,60 @@ output:write([[
]])
for _,keyset in ipairs(keysets) do
local name, keys = unpack(keyset)
local special = {}
local function sanitize(key)
if special[key] then
return key .. "_"
for _,k in ipairs(keysets) do
local c_name = {}
for i = 1,#k.keys do
-- some keys, like "register" are c keywords and get
-- escaped with a trailing _ in the struct.
if vim.endswith(k.keys[i], "_") then
local orig = k.keys[i]
k.keys[i] = string.sub(k.keys[i],1, #(k.keys[i]) - 1)
c_name[k.keys[i]] = orig
k.types[k.keys[i]] = k.types[orig]
end
return key
end
local key_names = {}
for i = 1,#keys do
local kname = keys[i][1]
if vim.endswith(kname, "_") then
kname = string.sub(kname,1, #kname - 1)
special[kname] = true
end
key_names[i] = kname
end
local neworder, hashfun = hashy.hashy_hash(name, key_names, function (idx)
return name.."_table["..idx.."].str"
local neworder, hashfun = hashy.hashy_hash(k.name, k.keys, function (idx)
return k.name.."_table["..idx.."].str"
end)
keysets_defs:write("extern KeySetLink "..name.."_table[];\n")
keysets_defs:write("extern KeySetLink "..k.name.."_table[];\n")
output:write("KeySetLink "..name.."_table[] = {\n")
for _, key in ipairs(neworder) do
output:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..sanitize(key)..")},\n")
local function typename(type)
if type ~= nil then
return "kObjectType"..type
else
return "kObjectTypeNil"
end
end
output:write(' {NULL, 0},\n')
output:write("KeySetLink "..k.name.."_table[] = {\n")
for i, key in ipairs(neworder) do
local ind = -1
if k.has_optional then
ind = i
keysets_defs:write("#define KEYSET_OPTIDX_"..k.name.."__"..key.." "..ind.."\n")
end
output:write(' {"'..key..'", offsetof(KeyDict_'..k.name..", "..(c_name[key] or key).."), "..typename(k.types[key])..", "..ind.."},\n")
end
output:write(' {NULL, 0, kObjectTypeNil, -1},\n')
output:write("};\n\n")
output:write(hashfun)
output:write([[
Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len)
KeySetLink *KeyDict_]]..k.name..[[_get_field(const char *str, size_t len)
{
int hash = ]]..name..[[_hash(str, len);
int hash = ]]..k.name..[[_hash(str, len);
if (hash == -1) {
return NULL;
}
return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off);
return &]]..k.name..[[_table[hash];
}
]])
keysets_defs:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n")
keysets_defs:write("#define api_free_keydict_"..k.name.."(x) api_free_keydict(x, "..k.name.."_table)\n")
end
local function real_type(type)
@@ -666,7 +687,7 @@ local function process_function(fn)
if (ERROR_SET(&err)) {
luaL_where(lstate, 1);
if (err_param) {
lua_pushstring(lstate, "param '");
lua_pushstring(lstate, "Invalid '");
lua_pushstring(lstate, err_param);
lua_pushstring(lstate, "': ");
}