summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJosh Haberman <jhaberman@gmail.com>2014-07-02 15:41:10 -0700
committerJosh Haberman <jhaberman@gmail.com>2014-07-02 15:41:10 -0700
commit47b5e0968aa0ec47f522ba357c159b2450645806 (patch)
treed8cd2e7d518b1d6572a6002843446c9e6ee8ef89 /tools
parent2d10fa33071d52d7a35ce3b13bc459cd16a0aa33 (diff)
Sync from internal Google development.
Diffstat (limited to 'tools')
-rw-r--r--tools/dump_cinit.lua139
1 files changed, 127 insertions, 12 deletions
diff --git a/tools/dump_cinit.lua b/tools/dump_cinit.lua
index 86d605b..2988082 100644
--- a/tools/dump_cinit.lua
+++ b/tools/dump_cinit.lua
@@ -37,6 +37,16 @@ function export.file_appender(file)
return append
end
+function handler_types(base)
+ local ret = {}
+ for k, _ in pairs(base) do
+ if string.find(k, "^" .. "HANDLER_") then
+ ret[#ret + 1] = k
+ end
+ end
+ return ret
+end
+
-- const(f, label) -> UPB_LABEL_REPEATED, where f:label() == upb.LABEL_REPEATED
function const(obj, name, base)
local val = obj[name]
@@ -65,6 +75,19 @@ function sortedkeys(tab)
return arr
end
+function sorted_defs(defs)
+ local sorted = {}
+
+ for def in defs do
+ sorted[#sorted + 1] = def
+ end
+
+ table.sort(sorted,
+ function(a, b) return a:full_name() < b:full_name() end)
+
+ return sorted
+end
+
function constlist(pattern)
local ret = {}
for k, v in pairs(upb) do
@@ -274,6 +297,8 @@ local function to_preproc(...)
return string.upper(to_cident(...))
end
+-- Strips away last path element, ie:
+-- foo.Bar.Baz -> foo.Bar
local function getpackage(name)
local package_end = 0
for i=1,string.len(name) do
@@ -284,11 +309,19 @@ local function getpackage(name)
return string.sub(name, 1, package_end)
end
+-- Returns only the last path element, ie:
+-- foo.Bar.Baz -> Baz
local function relname(name)
local package = getpackage(name)
return string.sub(name, string.len(package) + 2)
end
+local function strip_prefix(prefix, str)
+ assert(string.sub(str, 1, string.len(prefix)) == prefix)
+ return string.sub(str, string.len(prefix) + 1)
+end
+
+
local function start_namespace(package, append)
local package_components = split(package)
for _, component in ipairs(package_components) do
@@ -495,19 +528,96 @@ local function dump_defs_c(symtab, basename, namespace, append)
end
local function dump_defs_for_type(format, defs, namespace, append)
- local sorted_defs = {}
-
- for def in defs do
- sorted_defs[#sorted_defs + 1] = def
+ local sorted = sorted_defs(defs)
+ for _, def in ipairs(sorted) do
+ append(format, namespace, to_cident(def:full_name()), def:full_name())
end
- table.sort(sorted_defs,
- function(a, b) return a:full_name() < b:full_name() end)
+ append("\n")
+end
- for _, def in ipairs(sorted_defs) do
- append(format, namespace, to_cident(def:full_name()), def:full_name())
+local function dump_enum_vals(enumdef, append)
+ local enum_vals = {}
+
+ for k, v in enumdef:values() do
+ enum_vals[#enum_vals + 1] = {k, v}
+ end
+
+ table.sort(enum_vals, function(a, b) return a[2] < b[2] end)
+
+ -- protobuf convention is that enum values are scoped at the level of the
+ -- enum itself, to follow C++. Ie, if you have the enum:
+ -- message Foo {
+ -- enum E {
+ -- VAL1 = 1;
+ -- VAL2 = 2;
+ -- }
+ -- }
+ --
+ -- The name of VAL1 is Foo.VAL1, not Foo.E.VAL1.
+ --
+ -- This seems a bit sketchy, but people often name their enum values
+ -- accordingly, ie:
+ --
+ -- enum Foo {
+ -- FOO_VAL1 = 1;
+ -- FOO_VAL2 = 2;
+ -- }
+ --
+ -- So if we don't respect this also, we end up with constants that look like:
+ --
+ -- GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_DOUBLE = 1
+ --
+ -- (notice the duplicated "TYPE").
+ local cident = to_cident(getpackage(enumdef:full_name()))
+ for _, pair in ipairs(enum_vals) do
+ k, v = pair[1], pair[2]
+ append(' %s = %d,\n', to_preproc(cident, k), v)
+ end
+end
+
+local function dump_selectors(msgdef, append, base)
+ local selectors = {}
+ local types = handler_types(base)
+
+ for f in msgdef:fields() do
+ for _, handler_type in ipairs(types) do
+ local sel = f:getsel(base[handler_type])
+ if sel then
+ selectors[#selectors + 1] = {
+ f:name() .. "_" .. strip_prefix("HANDLER_", handler_type),
+ sel
+ }
+ end
+ end
end
+ table.sort(selectors, function(a, b) return a[2] < b[2] end)
+
+ -- This is kind of gross, but unless we add something to selectors to
+ -- distinguish them from enum values, we get conflicts like this:
+ --
+ -- // This can be either the enum value:
+ -- package google.protobuf;
+ -- message FieldDescriptorProto {
+ -- enum Type {
+ -- TYPE_INT32 = X;
+ -- }
+ -- optional Type type = 1;
+ -- }
+ --
+ -- // Now this can be either the enum value or the selector for the
+ -- // int32 handler for the "type" field.
+ -- GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32
+ --
+ -- // So instead we make the latter the very beautiful:
+ -- SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32
+ append("// %s\n", msgdef:full_name())
+ local cident = to_cident(msgdef:full_name())
+ for _, pair in ipairs(selectors) do
+ k, v = pair[1], pair[2]
+ append('#define SEL_%s %d\n', to_preproc(cident, k), v)
+ end
append("\n")
end
@@ -538,16 +648,21 @@ local function dump_defs_h(symtab, basename, namespace, append, linktab)
end
-- Dump C enums for proto enums.
+
append("// Enums\n\n")
- for def in symtab:defs(upb.DEF_ENUM) do
+ for _, def in ipairs(sorted_defs(symtab:defs(upb.DEF_ENUM))) do
local cident = to_cident(def:full_name())
append('typedef enum {\n')
- for k, v in def:values() do
- append(' %s = %d,\n', to_preproc(cident, k), v)
- end
+ dump_enum_vals(def, append)
append('} %s;\n\n', cident)
end
+ -- selectors
+ append("// Selectors\n\n")
+ for _, def in ipairs(sorted_defs(symtab:defs(upb.DEF_MSG))) do
+ dump_selectors(def, append, upb)
+ end
+
append("const upb_symtab *%s_%s(const void *owner);" ..
"\n\n", namespace, to_cident(basename))
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback