diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/dump_cinit.lua | 414 | ||||
-rw-r--r-- | tools/test_cinit.lua | 78 | ||||
-rw-r--r-- | tools/upbc.c | 197 | ||||
-rw-r--r-- | tools/upbc.lua | 50 |
4 files changed, 542 insertions, 197 deletions
diff --git a/tools/dump_cinit.lua b/tools/dump_cinit.lua new file mode 100644 index 0000000..1447d58 --- /dev/null +++ b/tools/dump_cinit.lua @@ -0,0 +1,414 @@ +--[[ + + upb - a minimalist implementation of protocol buffers. + + Copyright (c) 2012 Google Inc. See LICENSE for details. + Author: Josh Haberman <jhaberman@gmail.com> + + Routines for dumping internal data structures into C initializers + that can be compiled into a .o file. + +--]] + +local upbtable = require "upbtable" +local upb = require "upb" +local export = {} + +-- A tiny little abstraction that decouples the dump_* functions from +-- what they're writing to (appending to a string, writing to file I/O, etc). +-- This could possibly matter since naive string building is O(n^2) in the +-- number of appends. +function export.str_appender() + local str = "" + local function append(fmt, ...) + str = str .. string.format(fmt, ...) + end + local function get() + return str + end + return append, get +end + +function export.file_appender(file) + local f = file + local function append(fmt, ...) + f:write(string.format(fmt, ...)) + end + return append +end + +-- const(f, label) -> UPB_LABEL_REPEATED, where f:label() == upb.LABEL_REPEATED +function const(obj, name) + local val = obj[name](obj) + for k, v in pairs(upb) do + if v == val and string.find(k, "^" .. string.upper(name)) then + return "UPB_" .. k + end + end + assert(false, "Couldn't find constant") +end + +--[[ + + LinkTable: an object that tracks all linkable objects and their offsets to + facilitate linking. + +--]] + +local LinkTable = {} +function LinkTable:new(basename, types) + local linktab = { + basename = basename, + types = types, + table = {}, -- ptr -> {type, 0-based offset} + obj_arrays = {} -- Establishes the ordering for each object type + } + for type, _ in pairs(types) do + linktab.obj_arrays[type] = {} + end + setmetatable(linktab, {__index = LinkTable}) -- Inheritance + return linktab +end + +-- Adds a new object to the sequence of objects of this type. +function LinkTable:add(objtype, ptr, obj) + obj = obj or ptr + assert(self.table[obj] == nil) + assert(self.types[objtype]) + local arr = self.obj_arrays[objtype] + self.table[ptr] = {objtype, #arr} + arr[#arr + 1] = obj +end + +-- Returns a C symbol name for the given objtype and offset. +function LinkTable:csym(objtype, offset) + local typestr = assert(self.types[objtype]) + return string.format("%s_%s[%d]", self.basename, typestr, offset) +end + +-- Returns the address of the given C object. +function LinkTable:addr(obj) + if obj == upbtable.NULL then + return "NULL" + else + local tabent = assert(self.table[obj], "unknown object") + return "&" .. self:csym(tabent[1], tabent[2]) + end +end + +-- Returns an array declarator indicating how many objects have been added. +function LinkTable:cdecl(objtype) + return self:csym(objtype, #self.obj_arrays[objtype]) +end + +function LinkTable:objs(objtype) + -- Return iterator function, allowing use as: + -- for obj in linktable:objs(type) do + -- -- ... + -- done + local array = self.obj_arrays[objtype] + local i = 0 + return function() + i = i + 1 + if array[i] then return array[i] end + end +end + +--[[ + + Dumper: an object that can dump C initializers for several constructs. + Uses a LinkTable to resolve references when necessary. + +--]] + +local Dumper = {} +function Dumper:new(linktab) + local obj = {linktab = linktab} + setmetatable(obj, {__index = Dumper}) -- Inheritance + return obj +end + +-- Dumps a upb_value, eg: +-- UPB_VALUE_INIT_INT32(5) +function Dumper:value(val, upbtype) + if type(val) == "nil" then + return "UPB_VALUE_INIT_NONE" + elseif type(val) == "number" then + -- Use upbtype to disambiguate what kind of number it is. + if upbtype == upbtable.CTYPE_INT32 then + return string.format("UPB_VALUE_INIT_INT32(%d)", val) + else + -- TODO(haberman): add support for these so we can properly support + -- default values. + error("Unsupported number type " .. upbtype) + end + elseif type(val) == "string" then + return string.format('UPB_VALUE_INIT_CONSTPTR("%s")', val) + else + -- We take this as an object reference that has an entry in the link table. + return string.format("UPB_VALUE_INIT_CONSTPTR(%s)", self.linktab:addr(val)) + end +end + +-- Dumps a table key. +function Dumper:tabkey(key) + if type(key) == "nil" then + return "UPB_TABKEY_NONE" + elseif type(key) == "string" then + return string.format('UPB_TABKEY_STR("%s")', key) + else + return string.format("UPB_TABKEY_NUM(%d)", key) + end +end + +-- Dumps a table entry. +function Dumper:tabent(ent) + local key = self:tabkey(ent.key) + local val = self:value(ent.value, ent.valtype) + local next = self.linktab:addr(ent.next) + return string.format(' {%s, %s, %s},\n', key, val, next) +end + +-- Dumps an inttable array entry. This is almost the same as value() above, +-- except that nil values have a special value to indicate "empty". +function Dumper:arrayval(val) + if val.val then + return string.format(" %s,\n", self:value(val.val, val.valtype)) + else + return " UPB_ARRAY_EMPTYENT,\n" + end +end + +-- Dumps an initializer for the given strtable/inttable (respectively). Its +-- entries must have previously been added to the linktable. +function Dumper:strtable(t) + -- UPB_STRTABLE_INIT(count, mask, type, size_lg2, entries) + return string.format( + "UPB_STRTABLE_INIT(%d, %d, %d, %d, %s)", + t.count, t.mask, t.type, t.size_lg2, self.linktab:addr(t.entries[1].ptr)) +end + +function Dumper:inttable(t) + local lt = assert(self.linktab) + -- UPB_INTTABLE_INIT(count, mask, type, size_lg2, ent, a, asize, acount) + local entries = "NULL" + if #t.entries > 0 then + entries = lt:addr(t.entries[1].ptr) + end + return string.format( + "UPB_INTTABLE_INIT(%d, %d, %d, %d, %s, %s, %d, %d)", + t.count, t.mask, t.type, t.size_lg2, entries, + lt:addr(t.array[1].ptr), t.array_size, t.array_count) +end + +-- A visitor for visiting all tables of a def. Used first to count entries +-- and later to dump them. +local function gettables(def) + if def:def_type() == upb.DEF_MSG then + return {int = upbtable.msgdef_itof(def), str = upbtable.msgdef_ntof(def)} + elseif def:def_type() == upb.DEF_ENUM then + return {int = upbtable.enumdef_iton(def), str = upbtable.enumdef_ntoi(def)} + end +end + +local function emit_file_warning(append) + append('// This file was generated by upbc (the upb compiler).\n') + append('// Do not edit -- your changes will be discarded when the file is\n') + append('// regenerated.\n\n') +end + +--[[ + + Top-level, exported dumper functions + +--]] + +local function dump_defs_c(symtab, basename, append) + -- Add fielddefs for any msgdefs passed in. + local fielddefs = {} + for _, def in ipairs(symtab:getdefs(upb.DEF_MSG)) do + for field in def:fields() do + fielddefs[#fielddefs + 1] = field + end + end + + -- Get a list of all defs and add fielddefs to it. + local defs = symtab:getdefs(upb.DEF_ANY) + for _, fielddef in ipairs(fielddefs) do + defs[#defs + 1] = fielddef + end + + -- Sort all defs by (type, name). + -- This gives us a linear ordering that we can use to create offsets into + -- shared arrays like REFTABLES, hash table entries, and arrays. + table.sort(defs, function(a, b) + if a:def_type() ~= b:def_type() then + return a:def_type() < b:def_type() + else + return a:full_name() < b:full_name() end + end + ) + + -- Perform pre-pass to build the link table. + local linktab = LinkTable:new(basename, { + [upb.DEF_MSG] = "msgs", + [upb.DEF_FIELD] = "fields", + [upb.DEF_ENUM] = "enums", + intentries = "intentries", + strentries = "strentries", + arrays = "arrays", + }) + for _, def in ipairs(defs) do + assert(def:is_frozen(), "can only dump frozen defs.") + linktab:add(def:def_type(), def) + local tables = gettables(def) + if tables then + for _, e in ipairs(tables.str.entries) do + linktab:add("strentries", e.ptr, e) + end + for _, e in ipairs(tables.int.entries) do + linktab:add("intentries", e.ptr, e) + end + for _, e in ipairs(tables.int.array) do + linktab:add("arrays", e.ptr, e) + end + end + end + + -- Emit forward declarations. + emit_file_warning(append) + append('#include "upb/def.h"\n\n') + append("const upb_msgdef %s;\n", linktab:cdecl(upb.DEF_MSG)) + append("const upb_fielddef %s;\n", linktab:cdecl(upb.DEF_FIELD)) + append("const upb_enumdef %s;\n", linktab:cdecl(upb.DEF_ENUM)) + append("const upb_tabent %s;\n", linktab:cdecl("strentries")) + append("const upb_tabent %s;\n", linktab:cdecl("intentries")) + append("const upb_value %s;\n", linktab:cdecl("arrays")) + append("\n") + + -- Emit defs. + local dumper = Dumper:new(linktab) + + append("const upb_msgdef %s = {\n", linktab:cdecl(upb.DEF_MSG)) + for m in linktab:objs(upb.DEF_MSG) do + local tables = gettables(m) + -- UPB_MSGDEF_INIT(name, itof, ntof) + append(' UPB_MSGDEF_INIT("%s", %s, %s, %s),\n', + m:full_name(), + dumper:inttable(tables.int), + dumper:strtable(tables.str), + m:_selector_count()) + end + append("};\n\n") + + append("const upb_fielddef %s = {\n", linktab:cdecl(upb.DEF_FIELD)) + for f in linktab:objs(upb.DEF_FIELD) do + local subdef = "NULL" + if f:has_subdef() then + subdef = string.format("upb_upcast(%s)", linktab:addr(f:subdef())) + end + -- UPB_FIELDDEF_INIT(label, type, name, num, msgdef, subdef, + -- selector_base, default_value) + append(' UPB_FIELDDEF_INIT(%s, %s, "%s", %d, %s, %s, %d, %s),\n', + const(f, "label"), const(f, "type"), f:name(), + f:number(), linktab:addr(f:msgdef()), subdef, + f:_selector_base(), + dumper:value(nil) -- TODO + ) + end + append("};\n\n") + + append("const upb_enumdef %s = {\n", linktab:cdecl(upb.DEF_ENUM)) + for e in linktab:objs(upb.DEF_ENUM) do + local tables = gettables(e) + -- UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval) + append(' UPB_ENUMDEF_INIT("%s", %s, %s, %d),\n', + e:full_name(), + dumper:strtable(tables.str), + dumper:inttable(tables.int), + --e:default()) + 0) + end + append("};\n\n") + + append("const upb_tabent %s = {\n", linktab:cdecl("strentries")) + for ent in linktab:objs("strentries") do + append(dumper:tabent(ent)) + end + append("};\n\n"); + + append("const upb_tabent %s = {\n", linktab:cdecl("intentries")) + for ent in linktab:objs("intentries") do + append(dumper:tabent(ent)) + end + append("};\n\n"); + + append("const upb_value %s = {\n", linktab:cdecl("arrays")) + for ent in linktab:objs("arrays") do + append(dumper:arrayval(ent)) + end + append("};\n\n"); + + return linktab +end + +local function join(...) + return table.concat({...}, ".") +end + +local function to_cident(...) + return string.gsub(join(...), "%.", "_") +end + +local function to_preproc(...) + return string.upper(to_cident(...)) +end + +local function dump_defs_h(symtab, basename, append, linktab) + local ucase_basename = string.upper(basename) + emit_file_warning(append) + append('#ifndef %s_UPB_H_\n', ucase_basename) + append('#define %s_UPB_H_\n\n', ucase_basename) + append('#include "upb/def.h"\n\n') + append('#ifdef __cplusplus\n') + append('extern "C" {\n') + append('#endif\n\n') + + -- Dump C enums for proto enums. + append("// Enums\n\n") + for _, def in ipairs(symtab:getdefs(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 + append('} %s;\n\n', cident) + end + + -- Dump macros for referring to specific defs. + append("// Do not refer to these forward declarations; use the constants\n") + append("// below.\n") + append("extern const upb_msgdef %s;\n", linktab:cdecl(upb.DEF_MSG)) + append("extern const upb_fielddef %s;\n", linktab:cdecl(upb.DEF_FIELD)) + append("extern const upb_enumdef %s;\n\n", linktab:cdecl(upb.DEF_ENUM)) + append("// Constants for references to defs.\n") + append("// We hide these behind macros to decouple users from the\n") + append("// details of how we have statically defined them (ie. whether\n") + append("// each def has its own symbol or lives in an array of defs).\n") + for def in linktab:objs(upb.DEF_MSG) do + append("#define %s %s\n", to_preproc(def:full_name()), linktab:addr(def)) + end + append("\n") + + append('#ifdef __cplusplus\n') + append('}; // extern "C"\n') + append('#endif\n\n') + append('#endif // %s_UPB_H_\n', ucase_basename) +end + +function export.dump_defs(symtab, basename, append_h, append_c) + local linktab = dump_defs_c(symtab, basename, append_c) + dump_defs_h(symtab, basename, append_h, linktab) +end + +return export diff --git a/tools/test_cinit.lua b/tools/test_cinit.lua new file mode 100644 index 0000000..bb7977f --- /dev/null +++ b/tools/test_cinit.lua @@ -0,0 +1,78 @@ +--[[ + + upb - a minimalist implementation of protocol buffers. + + Copyright (c) 2012 Google Inc. See LICENSE for details. + Author: Josh Haberman <jhaberman@gmail.com> + + Tests for dump_cinit.lua. Runs first in a mode that generates + some C code for an extension. The C code is compiled and then + loaded by a second invocation of the test which checks that the + generated defs are as expected. + +--]] + +local dump_cinit = require "dump_cinit" +local upb = require "upb" + +-- Once APIs for loading descriptors are fleshed out, we should replace this +-- with a descriptor for a meaty protobuf like descriptor.proto. +local symtab = upb.SymbolTable{ + upb.EnumDef{full_name = "MyEnum", + values = { + {"FOO", 1}, + {"BAR", 77} + } + }, + upb.MessageDef{full_name = "MyMessage", + fields = { + upb.FieldDef{label = upb.LABEL_REQUIRED, name = "field1", number = 1, + type = upb.TYPE_INT32}, + upb.FieldDef{label = upb.LABEL_REPEATED, name = "field2", number = 2, + type = upb.TYPE_ENUM, subdef_name = ".MyEnum"}, + upb.FieldDef{name = "field3", number = 3, type = upb.TYPE_MESSAGE, + subdef_name = ".MyMessage"} + } + } +} + +if arg[1] == "generate" then + local f = assert(io.open(arg[2], "w")) + local f_h = assert(io.open(arg[2] .. ".h", "w")) + local appendc = dump_cinit.file_appender(f) + local appendh = dump_cinit.file_appender(f_h) + f:write('#include "lua.h"\n') + f:write('#define ELEMENTS(array) (sizeof(array)/sizeof(*array))\n') + f:write('#include "bindings/lua/upb.h"\n') + dump_cinit.dump_defs(symtab, "test", appendh, appendc) + f:write([[int luaopen_staticdefs(lua_State *L) { + lua_newtable(L); + for (int i = 0; i < ELEMENTS(test_msgs); i++) { + lupb_def_pushnewrapper(L, upb_upcast(&test_msgs[i]), NULL); + lua_rawseti(L, -2, i + 1); + } + for (int i = 0; i < ELEMENTS(test_enums); i++) { + lupb_def_pushnewrapper(L, upb_upcast(&test_enums[i]), NULL); + lua_rawseti(L, -2, ELEMENTS(test_msgs) + i + 1); + } + return 1; + }]]) + f_h:close() + f:close() +elseif arg[1] == "test" then + local staticdefs = require "staticdefs" + + local msg = assert(staticdefs[1]) + local enum = assert(staticdefs[2]) + local f2 = assert(msg:field("field2")) + assert(msg:def_type() == upb.DEF_MSG) + assert(msg:full_name() == "MyMessage") + assert(enum:def_type() == upb.DEF_ENUM) + assert(enum:full_name() == "MyEnum") + assert(enum:value("FOO") == 1) + assert(f2:name() == "field2") + assert(f2:msgdef() == msg) + assert(f2:subdef() == enum) +else + error("Unknown operation " .. arg[1]) +end diff --git a/tools/upbc.c b/tools/upbc.c deleted file mode 100644 index 4b25f3e..0000000 --- a/tools/upbc.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Google Inc. See LICENSE for details. - * Author: Josh Haberman <jhaberman@gmail.com> - * - * upbc is the upb compiler, which at the moment simply takes a - * protocol descriptor and outputs a header file containing the - * names and types of the fields. - */ - -#include <ctype.h> -#include <inttypes.h> -#include <stdarg.h> -#include <stdlib.h> -#include "upb/bytestream.h" -#include "upb/def.h" -#include "upb/msg.h" -#include "upb/pb/glue.h" - -/* These are in-place string transformations that do not change the length of - * the string (and thus never need to re-allocate). */ - -// Convert to C identifier: foo.bar.Baz -> foo_bar_Baz. -static void to_cident(char *str) { - for (; *str; ++str) { - if(*str == '.' || *str == '/') *str = '_'; - } -} - -// Convert to C proprocessor identifier: foo.bar.Baz -> FOO_BAR_BAZ. -static void to_preproc(char *str) { - to_cident(str); - for (; *str; ++str) *str = toupper(*str); -} - -/* The _const.h file defines the constants (enums) defined in the .proto - * file. */ -static void write_const_h(const upb_def *defs[], int num_entries, - char *outfile_name, FILE *stream) { - /* Header file prologue. */ - char *include_guard_name = strdup(outfile_name); - to_preproc(include_guard_name); - - fputs("/* This file was generated by upbc (the upb compiler). " - "Do not edit. */\n\n", stream), - fprintf(stream, "#ifndef %s\n", include_guard_name); - fprintf(stream, "#define %s\n\n", include_guard_name); - fputs("#ifdef __cplusplus\n", stream); - fputs("extern \"C\" {\n", stream); - fputs("#endif\n\n", stream); - - /* Enums. */ - fprintf(stream, "/* Enums. */\n\n"); - for(int i = 0; i < num_entries; i++) { /* Foreach enum */ - if(defs[i]->type != UPB_DEF_ENUM) continue; - const upb_enumdef *enumdef = upb_downcast_enumdef_const(defs[i]); - char *enum_name = strdup(upb_def_fullname(UPB_UPCAST(enumdef))); - char *enum_val_prefix = strdup(enum_name); - to_cident(enum_name); - to_preproc(enum_val_prefix); - - fprintf(stream, "typedef enum %s {\n", enum_name); - bool first = true; - /* Foreach enum value. */ - upb_enum_iter iter; - for (upb_enum_begin(&iter, enumdef); - !upb_enum_done(&iter); - upb_enum_next(&iter)) { - char *value_name = strdup(upb_enum_iter_name(&iter)); - uint32_t value = upb_enum_iter_number(&iter); - to_preproc(value_name); - /* " GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_TYPE_UINT32 = 13," */ - if (!first) fputs(",\n", stream); - first = false; - fprintf(stream, " %s_%s = %" PRIu32, enum_val_prefix, value_name, value); - free(value_name); - } - fprintf(stream, "\n} %s;\n\n", enum_name); - free(enum_name); - free(enum_val_prefix); - } - - /* Constants for field names and numbers. */ - fprintf(stream, "/* Constants for field names and numbers. */\n\n"); - for(int i = 0; i < num_entries; i++) { /* Foreach enum */ - const upb_msgdef *m = upb_dyncast_msgdef_const(defs[i]); - if(!m) continue; - char *msg_name = strdup(upb_def_fullname(UPB_UPCAST(m))); - char *msg_val_prefix = strdup(msg_name); - to_preproc(msg_val_prefix); - upb_msg_iter i; - for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - char *preproc_field_name = strdup(upb_fielddef_name(f)); - to_preproc(preproc_field_name); - fprintf(stream, "#define %s_%s__FIELDNUM %d\n", - msg_val_prefix, preproc_field_name, upb_fielddef_number(f)); - fprintf(stream, "#define %s_%s__FIELDNAME \"%s\"\n", - msg_val_prefix, preproc_field_name, upb_fielddef_name(f)); - fprintf(stream, "#define %s_%s__FIELDTYPE %d\n\n", - msg_val_prefix, preproc_field_name, upb_fielddef_type(f)); - free(preproc_field_name); - } - free(msg_val_prefix); - free(msg_name); - } - - /* Epilogue. */ - fputs("#ifdef __cplusplus\n", stream); - fputs("} /* extern \"C\" */\n", stream); - fputs("#endif\n\n", stream); - fprintf(stream, "#endif /* %s */\n", include_guard_name); - free(include_guard_name); -} - -const char usage[] = - "upbc -- upb compiler.\n" - "upb v0.1 http://blog.reverberate.org/upb/\n" - "\n" - "Usage: upbc [options] descriptor-file\n" - "\n" - " -o OUTFILE-BASE Write to OUTFILE-BASE.h and OUTFILE-BASE.c instead\n" - " of using the input file as a basename.\n" -; - -void usage_err(const char *err) { - fprintf(stderr, "upbc: %s\n\n", err); - fputs(usage, stderr); - exit(1); -} - -void error(const char *err, ...) { - va_list args; - va_start(args, err); - fprintf(stderr, "upbc: "); - vfprintf(stderr, err, args); - va_end(args); - exit(1); -} - -int main(int argc, char *argv[]) { - /* Parse arguments. */ - char *outfile_base = NULL, *input_file = NULL; - for(int i = 1; i < argc; i++) { - if(strcmp(argv[i], "-o") == 0) { - if(++i == argc) - usage_err("-o must be followed by a FILE-BASE."); - else if(outfile_base) - usage_err("-o was specified multiple times."); - outfile_base = argv[i]; - } else { - if(input_file) - usage_err("You can only specify one input file."); - input_file = argv[i]; - } - } - if(!input_file) usage_err("You must specify an input file."); - if(!outfile_base) outfile_base = input_file; - - // Read and parse input file. - size_t len; - char *descriptor = upb_readfile(input_file, &len); - if(!descriptor) - error("Couldn't read input file."); - - // TODO: make upb_parsedesc use a separate symtab, so we can use it here when - // importing descriptor.proto. - upb_symtab *s = upb_symtab_new(); - upb_status status = UPB_STATUS_INIT; - upb_load_descriptor_into_symtab(s, descriptor, len, &status); - if(!upb_ok(&status)) { - error("Failed to parse input file descriptor: %s\n", - upb_status_getstr(&status)); - } - upb_status_uninit(&status); - - /* Emit output files. */ - char h_const_filename[256]; - const int maxsize = sizeof(h_const_filename); - if(snprintf(h_const_filename, maxsize, "%s_const.h", outfile_base) >= maxsize) - error("File base too long.\n"); - - FILE *h_const_file = fopen(h_const_filename, "w"); - if(!h_const_file) error("Failed to open _const.h output file\n"); - - int symcount; - const upb_def **defs = upb_symtab_getdefs(s, &symcount, UPB_DEF_ANY, &defs); - write_const_h(defs, symcount, h_const_filename, h_const_file); - for (int i = 0; i < symcount; i++) upb_def_unref(defs[i], &defs); - free(defs); - free(descriptor); - upb_symtab_unref(s); - fclose(h_const_file); - - return 0; -} diff --git a/tools/upbc.lua b/tools/upbc.lua new file mode 100644 index 0000000..f68d25f --- /dev/null +++ b/tools/upbc.lua @@ -0,0 +1,50 @@ +--[[ + + upb - a minimalist implementation of protocol buffers. + + Copyright (c) 2012 Google Inc. See LICENSE for details. + Author: Josh Haberman <jhaberman@gmail.com> + + The upb compiler. Unlike the proto2 compiler, this does + not output any parsing code or generated classes or anything + specific to the protobuf binary format at all. At the moment + it only dumps C initializers for upb_defs, so that a .proto + file can be represented in a .o file. + +--]] + +local dump_cinit = require "dump_cinit" +local upb = require "upb" + +local src = arg[1] +local outbase = arg[2] +local basename = arg[3] +local hfilename = outbase .. ".upb.h" +local cfilename = outbase .. ".upb.c" + +if os.getenv("UPBC_VERBOSE") then + print("upbc:") + print(string.format(" source file=%s", src)) + print(string.format(" output file base=%s", outbase)) + print(string.format(" hfilename=%s", hfilename)) + print(string.format(" cfilename=%s", cfilename)) +end + +-- Open input/output files. +local f = assert(io.open(src, "r"), "couldn't open input file " .. src) +local descriptor = f:read("*all") +local symtab = upb.SymbolTable() +symtab:load_descriptor(descriptor) + +os.execute(string.format("mkdir -p `dirname %s`", outbase)) +local hfile = assert(io.open(hfilename, "w"), "couldn't open " .. hfilename) +local cfile = assert(io.open(cfilename, "w"), "couldn't open " .. cfilename) + +local happend = dump_cinit.file_appender(hfile) +local cappend = dump_cinit.file_appender(cfile) + +-- Dump defs +dump_cinit.dump_defs(symtab, basename, happend, cappend) + +hfile:close() +cfile:close() |