This commit is contained in:
Amol Deshpande
2015-06-15 20:26:10 -07:00
parent 40fffc8fff
commit ad3fd6ecbf
24 changed files with 1188 additions and 58 deletions

View File

@@ -90,13 +90,15 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" --defaults-json Output fields whose value is the default when\n"
" writing JSON\n"
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
" --gen-includes Generate include statements for included schemas the\n"
" generated file depends on (C++).\n"
" --gen-includes (deprecated), instead use:\n"
" --no-includes Don\'t generate include statements for included\n"
" schemas the generated file depends on (C++).\n"
" --gen-mutable Generate accessors that can mutate buffers in-place.\n"
" --gen-onefile Generate single output file for C#\n"
" --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n"
" --schema Serialize schemas instead of JSON (use with -b)\n"
"FILEs may depend on declarations in earlier files.\n"
"FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
@@ -117,6 +119,7 @@ int main(int argc, const char *argv[]) {
bool print_make_rules = false;
bool proto_mode = false;
bool raw_binary = false;
bool schema_binary = false;
std::vector<std::string> filenames;
std::vector<const char *> include_directories;
size_t binary_files_from = std::numeric_limits<size_t>::max();
@@ -140,7 +143,10 @@ int main(int argc, const char *argv[]) {
} else if(arg == "--gen-mutable") {
opts.mutable_buffer = true;
} else if(arg == "--gen-includes") {
opts.include_dependence_headers = true;
// Deprecated, remove this option some time in the future.
printf("warning: --gen-includes is deprecated (it is now default)\n");
} else if(arg == "--no-includes") {
opts.include_dependence_headers = false;
} else if (arg == "--gen-onefile") {
opts.one_file = true;
} else if (arg == "--raw-binary") {
@@ -150,6 +156,8 @@ int main(int argc, const char *argv[]) {
} else if(arg == "--proto") {
proto_mode = true;
any_generator = true;
} else if(arg == "--schema") {
schema_binary = true;
} else if(arg == "-M") {
print_make_rules = true;
} else {
@@ -216,6 +224,10 @@ int main(int argc, const char *argv[]) {
if (!parser.Parse(contents.c_str(), &include_directories[0],
file_it->c_str()))
Error(parser.error_, false, false);
if (schema_binary) {
parser.Serialize();
parser.file_extension_ = reflection::SchemaExtension();
}
include_directories.pop_back();
include_directories.pop_back();
}

View File

@@ -701,8 +701,8 @@ std::string GenerateCPP(const Parser &parser,
code += enum_code_post;
// Generate convenient global helper functions:
if (parser.root_struct_def) {
auto &name = parser.root_struct_def->name;
if (parser.root_struct_def_) {
auto &name = parser.root_struct_def_->name;
std::string qualified_name = parser.GetFullyQualifiedName(name);
std::string cpp_qualified_name = TranslateNameSpace(qualified_name);

View File

@@ -527,7 +527,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
code += ") + _bb.";
code += lang.get_bb_position;
code += ", _bb)); }\n";
if (parser.root_struct_def == &struct_def) {
if (parser.root_struct_def_ == &struct_def) {
if (parser.file_identifier_.length()) {
// Check if a buffer has the identifier.
code += " public static ";
@@ -842,7 +842,7 @@ static void GenStruct(const LanguageParameters &lang, const Parser &parser,
}
}
code += " return o;\n }\n";
if (parser.root_struct_def == &struct_def) {
if (parser.root_struct_def_ == &struct_def) {
code += " public static void ";
code += FunctionStart(lang, 'F') + "inish" + struct_def.name;
code += "Buffer(FlatBufferBuilder builder, int offset) { ";
@@ -878,11 +878,13 @@ static bool SaveClass(const LanguageParameters &lang, const Parser &parser,
EnsureDirExists(namespace_dir);
std::string code = "// automatically generated, do not modify\n\n";
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
code += "\n\n";
if (!namespace_general.empty()) {
code += lang.namespace_ident + namespace_general + lang.namespace_begin;
code += "\n\n";
}
if (needs_includes) code += lang.includes;
code += classcode;
code += lang.namespace_end;
if (!namespace_general.empty()) code += lang.namespace_end;
auto filename = namespace_dir + defname + lang.file_extension;
return SaveFile(filename.c_str(), code, false);
}
@@ -1007,7 +1009,7 @@ std::string BinaryMakeRule(const Parser &parser,
std::string make_rule = BinaryFileName(parser, path, filebase) + ": " +
file_name;
auto included_files = parser.GetIncludedFilesRecursive(
parser.root_struct_def->file);
parser.root_struct_def_->file);
for (auto it = included_files.begin();
it != included_files.end(); ++it) {
make_rule += " " + *it;

View File

@@ -677,7 +677,7 @@ bool GenerateGo(const Parser &parser,
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
go::GenStruct(**it, &declcode, parser.root_struct_def);
go::GenStruct(**it, &declcode, parser.root_struct_def_);
if (!go::SaveType(parser, **it, declcode, path, true))
return false;
}

View File

@@ -651,7 +651,7 @@ bool GeneratePython(const Parser &parser,
for (auto it = parser.structs_.vec.begin();
it != parser.structs_.vec.end(); ++it) {
std::string declcode;
python::GenStruct(**it, &declcode, parser.root_struct_def);
python::GenStruct(**it, &declcode, parser.root_struct_def_);
if (!python::SaveType(parser, **it, declcode, path, true))
return false;
}

View File

@@ -270,9 +270,9 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
void GenerateText(const Parser &parser, const void *flatbuffer,
const GeneratorOptions &opts, std::string *_text) {
std::string &text = *_text;
assert(parser.root_struct_def); // call SetRootType()
assert(parser.root_struct_def_); // call SetRootType()
text.reserve(1024); // Reduce amount of inevitable reallocs.
GenStruct(*parser.root_struct_def,
GenStruct(*parser.root_struct_def_,
GetRoot<Table>(flatbuffer),
0,
opts,
@@ -289,7 +289,7 @@ bool GenerateTextFile(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions &opts) {
if (!parser.builder_.GetSize() || !parser.root_struct_def) return true;
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
std::string text;
GenerateText(parser, parser.builder_.GetBufferPointer(), opts,
&text);
@@ -302,12 +302,12 @@ std::string TextMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name,
const GeneratorOptions & /*opts*/) {
if (!parser.builder_.GetSize() || !parser.root_struct_def) return "";
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
std::string filebase = flatbuffers::StripPath(
flatbuffers::StripExtension(file_name));
std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
auto included_files = parser.GetIncludedFilesRecursive(
parser.root_struct_def->file);
parser.root_struct_def_->file);
for (auto it = included_files.begin();
it != included_files.end(); ++it) {
make_rule += " " + *it;

View File

@@ -17,8 +17,6 @@
#include <algorithm>
#include <list>
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/hash.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -39,6 +37,12 @@ const char kTypeSizes[] = {
#undef FLATBUFFERS_TD
};
// The enums in the reflection schema should match the ones we use internally.
// Compare the last element to check if these go out of sync.
static_assert(BASE_TYPE_UNION ==
static_cast<BaseType>(reflection::Union),
"enums don't match");
static void Error(const std::string &msg) {
throw msg;
}
@@ -198,7 +202,7 @@ void Parser::Next() {
}
// fall thru
default:
if (isalpha(static_cast<unsigned char>(c))) {
if (isalpha(static_cast<unsigned char>(c)) || c == '_') {
// Collect all chars of an identifier:
const char *start = cursor_ - 1;
while (isalnum(static_cast<unsigned char>(*cursor_)) ||
@@ -981,8 +985,8 @@ void Parser::ParseDecl() {
}
bool Parser::SetRootType(const char *name) {
root_struct_def = structs_.Lookup(GetFullyQualifiedName(name));
return root_struct_def != nullptr;
root_struct_def_ = structs_.Lookup(GetFullyQualifiedName(name));
return root_struct_def_ != nullptr;
}
std::string Parser::GetFullyQualifiedName(const std::string &name) const {
@@ -1200,11 +1204,11 @@ bool Parser::Parse(const char *source, const char **include_paths,
} else if (token_ == kTokenNameSpace) {
ParseNamespace();
} else if (token_ == '{') {
if (!root_struct_def) Error("no root type set to parse json with");
if (!root_struct_def_) Error("no root type set to parse json with");
if (builder_.GetSize()) {
Error("cannot have more than one json object in a file");
}
builder_.Finish(Offset<Table>(ParseTable(*root_struct_def)),
builder_.Finish(Offset<Table>(ParseTable(*root_struct_def_)),
file_identifier_.length() ? file_identifier_.c_str() : nullptr);
} else if (token_ == kTokenEnum) {
ParseEnum(false);
@@ -1216,7 +1220,7 @@ bool Parser::Parse(const char *source, const char **include_paths,
Expect(kTokenIdentifier);
if (!SetRootType(root_type.c_str()))
Error("unknown root type: " + root_type);
if (root_struct_def->fixed)
if (root_struct_def_->fixed)
Error("root type must be a table");
Expect(';');
} else if (token_ == kTokenFileIdentifier) {
@@ -1302,4 +1306,105 @@ std::set<std::string> Parser::GetIncludedFilesRecursive(
return included_files;
}
// Schema serialization functionality:
template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
// Pre-sort these vectors, such that we can set the correct indices for them.
auto vec = defvec;
std::sort(vec.begin(), vec.end(),
[](const T *a, const T *b) { return a->name < b->name; });
for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
}
void Parser::Serialize() {
builder_.Clear();
AssignIndices(structs_.vec);
AssignIndices(enums_.vec);
std::vector<Offset<reflection::Object>> object_offsets;
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_);
object_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
}
std::vector<Offset<reflection::Enum>> enum_offsets;
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_);
enum_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
}
auto schema_offset = reflection::CreateSchema(
builder_,
builder_.CreateVectorOfSortedTables(&object_offsets),
builder_.CreateVectorOfSortedTables(&enum_offsets),
builder_.CreateString(file_identifier_),
builder_.CreateString(file_extension_),
root_struct_def_->serialized_location);
builder_.Finish(schema_offset, reflection::SchemaIdentifier());
}
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder)
const {
std::vector<Offset<reflection::Field>> field_offsets;
for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
field_offsets.push_back(
(*it)->Serialize(builder,
static_cast<uint16_t>(it - fields.vec.begin())));
}
return reflection::CreateObject(*builder,
builder->CreateString(name),
builder->CreateVectorOfSortedTables(
&field_offsets),
fixed);
}
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
uint16_t id) const {
return reflection::CreateField(*builder,
builder->CreateString(name),
value.type.Serialize(builder),
id,
value.offset,
IsInteger(value.type.base_type)
? StringToInt(value.constant.c_str())
: 0,
IsFloat(value.type.base_type)
? strtod(value.constant.c_str(), nullptr)
: 0.0,
deprecated,
required,
key);
// TODO: value.constant is almost always "0", we could save quite a bit of
// space by sharing it. Same for common values of value.type.
}
Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder) const {
std::vector<Offset<reflection::EnumVal>> enumval_offsets;
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder));
}
return reflection::CreateEnum(*builder,
builder->CreateString(name),
builder->CreateVector(enumval_offsets),
is_union,
underlying_type.Serialize(builder));
}
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
{
return reflection::CreateEnumVal(*builder,
builder->CreateString(name),
value,
struct_def
? struct_def->serialized_location
: 0);
}
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
return reflection::CreateType(*builder,
static_cast<reflection::BaseType>(base_type),
static_cast<reflection::BaseType>(element),
struct_def ? struct_def->index :
(enum_def ? enum_def->index : -1));
}
} // namespace flatbuffers