mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-15 08:48:52 +00:00
Sync from upstream
This commit is contained in:
158
src/flatc.cpp
158
src/flatc.cpp
@@ -17,6 +17,9 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <limits>
|
||||
|
||||
#define FLATC_VERSION "1.3.0 (" __DATE__ ")"
|
||||
|
||||
static void Error(const std::string &err, bool usage = false,
|
||||
bool show_exe_name = true);
|
||||
@@ -26,22 +29,26 @@ static void Error(const std::string &err, bool usage = false,
|
||||
struct Generator {
|
||||
bool (*generate)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
<<<<<<< HEAD
|
||||
const std::string &file_name,
|
||||
const flatbuffers::GeneratorOptions &opts);
|
||||
=======
|
||||
const std::string &file_name);
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
const char *generator_opt_short;
|
||||
const char *generator_opt_long;
|
||||
const char *lang_name;
|
||||
flatbuffers::GeneratorOptions::Language lang;
|
||||
flatbuffers::IDLOptions::Language lang;
|
||||
const char *generator_help;
|
||||
|
||||
std::string (*make_rule)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const flatbuffers::GeneratorOptions &opts);
|
||||
const std::string &file_name);
|
||||
};
|
||||
|
||||
const Generator generators[] = {
|
||||
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary",
|
||||
<<<<<<< HEAD
|
||||
flatbuffers::GeneratorOptions::kMAX,
|
||||
"Generate wire format binaries for any data definitions",
|
||||
flatbuffers::BinaryMakeRule },
|
||||
@@ -75,8 +82,47 @@ const Generator generators[] = {
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
|
||||
flatbuffers::GeneratorOptions::kMAX,
|
||||
=======
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate wire format binaries for any data definitions",
|
||||
flatbuffers::BinaryMakeRule },
|
||||
{ flatbuffers::GenerateTextFile, "-t", "--json", "text",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate text output for any data definitions",
|
||||
flatbuffers::TextMakeRule },
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate C++ headers for tables/structs",
|
||||
flatbuffers::CPPMakeRule },
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go",
|
||||
flatbuffers::IDLOptions::kGo,
|
||||
"Generate Go files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java",
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#",
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
"Generate PHP files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGRPC, nullptr, "--grpc", "GRPC",
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate GRPC interfaces",
|
||||
flatbuffers::CPPMakeRule },
|
||||
};
|
||||
|
||||
const char *program_name = nullptr;
|
||||
@@ -95,28 +141,33 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
: " ",
|
||||
generators[i].generator_help);
|
||||
printf(
|
||||
" -o PATH Prefix PATH to all generated files.\n"
|
||||
" -I PATH Search for includes in the specified path.\n"
|
||||
" -M Print make rules for generated files.\n"
|
||||
" --strict-json Strict JSON: field names must be / will be quoted,\n"
|
||||
" no trailing commas in tables/vectors.\n"
|
||||
" --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"
|
||||
" --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
|
||||
" also implies --no-prefix.\n"
|
||||
" --gen-includes (deprecated), this is the default behavior.\n"
|
||||
" If the original behavior is required (no include\n"
|
||||
" statements) use --no-includes.\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"
|
||||
" -o PATH Prefix PATH to all generated files.\n"
|
||||
" -I PATH Search for includes in the specified path.\n"
|
||||
" -M Print make rules for generated files.\n"
|
||||
" --version Print the version number of flatc and exit.\n"
|
||||
" --strict-json Strict JSON: field names must be / will be quoted,\n"
|
||||
" no trailing commas in tables/vectors.\n"
|
||||
" --defaults-json Output fields whose value is the default when\n"
|
||||
" writing JSON\n"
|
||||
" --unknown-json Allow fields in JSON that are not defined in the\n"
|
||||
" schema. These fields will be discared when generating\n"
|
||||
" binaries.\n"
|
||||
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
|
||||
" --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
|
||||
" also implies --no-prefix.\n"
|
||||
" --gen-includes (deprecated), this is the default behavior.\n"
|
||||
" If the original behavior is required (no include\n"
|
||||
" statements) use --no-includes.\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"
|
||||
" --gen-name-strings Generate type name functions 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 be schemas, or JSON files (conforming to preceding schema)\n"
|
||||
"FILEs after the -- must be binary flatbuffer format files.\n"
|
||||
"Output files are named using the base file name of the input,\n"
|
||||
"and written to the current directory or the path given by -o.\n"
|
||||
@@ -129,13 +180,12 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
program_name = argv[0];
|
||||
flatbuffers::GeneratorOptions opts;
|
||||
flatbuffers::IDLOptions opts;
|
||||
std::string output_path;
|
||||
const size_t num_generators = sizeof(generators) / sizeof(generators[0]);
|
||||
bool generator_enabled[num_generators] = { false };
|
||||
bool any_generator = false;
|
||||
bool print_make_rules = false;
|
||||
bool proto_mode = false;
|
||||
bool raw_binary = false;
|
||||
bool schema_binary = false;
|
||||
std::vector<std::string> filenames;
|
||||
@@ -158,6 +208,8 @@ int main(int argc, const char *argv[]) {
|
||||
opts.skip_js_exports = true;
|
||||
} else if(arg == "--defaults-json") {
|
||||
opts.output_default_scalars_in_json = true;
|
||||
} else if (arg == "--unknown-json") {
|
||||
opts.skip_unexpected_fields_in_json = true;
|
||||
} else if(arg == "--no-prefix") {
|
||||
opts.prefixed_enums = false;
|
||||
} else if(arg == "--scoped-enums") {
|
||||
@@ -165,6 +217,11 @@ int main(int argc, const char *argv[]) {
|
||||
opts.scoped_enums = true;
|
||||
} else if(arg == "--gen-mutable") {
|
||||
opts.mutable_buffer = true;
|
||||
} else if(arg == "--gen-name-strings") {
|
||||
opts.generate_name_strings = true;
|
||||
} else if(arg == "--gen-all") {
|
||||
opts.generate_all = true;
|
||||
opts.include_dependence_headers = false;
|
||||
} else if(arg == "--gen-includes") {
|
||||
// Deprecated, remove this option some time in the future.
|
||||
printf("warning: --gen-includes is deprecated (it is now default)\n");
|
||||
@@ -177,12 +234,14 @@ int main(int argc, const char *argv[]) {
|
||||
} else if(arg == "--") { // Separator between text and binary inputs.
|
||||
binary_files_from = filenames.size();
|
||||
} else if(arg == "--proto") {
|
||||
proto_mode = true;
|
||||
any_generator = true;
|
||||
opts.proto_mode = true;
|
||||
} else if(arg == "--schema") {
|
||||
schema_binary = true;
|
||||
} else if(arg == "-M") {
|
||||
print_make_rules = true;
|
||||
} else if(arg == "--version") {
|
||||
printf("flatc version %s\n", FLATC_VERSION);
|
||||
exit(0);
|
||||
} else {
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
if (arg == generators[i].generator_opt_long ||
|
||||
@@ -203,11 +262,19 @@ int main(int argc, const char *argv[]) {
|
||||
|
||||
if (!filenames.size()) Error("missing input files", false, true);
|
||||
|
||||
if (!any_generator)
|
||||
Error("no options: specify one of -c -g -j -t -b etc.", true);
|
||||
if (opts.proto_mode) {
|
||||
if (any_generator)
|
||||
Error("cannot generate code directly from .proto files", true);
|
||||
} else if (!any_generator) {
|
||||
Error("no options: specify at least one generator.", true);
|
||||
}
|
||||
|
||||
// Now process the files:
|
||||
<<<<<<< HEAD
|
||||
parser = new flatbuffers::Parser(opts.strict_json, proto_mode);
|
||||
=======
|
||||
parser = new flatbuffers::Parser(opts);
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
for (auto file_it = filenames.begin();
|
||||
file_it != filenames.end();
|
||||
++file_it) {
|
||||
@@ -243,12 +310,23 @@ int main(int argc, const char *argv[]) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
// Check if file contains 0 bytes.
|
||||
if (contents.length() != strlen(contents.c_str())) {
|
||||
Error("input file appears to be binary: " + *file_it, true);
|
||||
}
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
if (flatbuffers::GetExtension(*file_it) == "fbs") {
|
||||
// If we're processing multiple schemas, make sure to start each
|
||||
// one from scratch. If it depends on previous schemas it must do
|
||||
// so explicitly using an include.
|
||||
delete parser;
|
||||
<<<<<<< HEAD
|
||||
parser = new flatbuffers::Parser(opts.strict_json, proto_mode);
|
||||
=======
|
||||
parser = new flatbuffers::Parser(opts);
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
}
|
||||
auto local_include_directory = flatbuffers::StripFileName(*file_it);
|
||||
include_directories.push_back(local_include_directory.c_str());
|
||||
@@ -268,11 +346,15 @@ int main(int argc, const char *argv[]) {
|
||||
flatbuffers::StripExtension(*file_it));
|
||||
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
opts.lang = generators[i].lang;
|
||||
parser->opts.lang = generators[i].lang;
|
||||
if (generator_enabled[i]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
<<<<<<< HEAD
|
||||
if (!generators[i].generate(*parser, output_path, filebase, opts)) {
|
||||
=======
|
||||
if (!generators[i].generate(*parser, output_path, filebase)) {
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
Error(std::string("Unable to generate ") +
|
||||
generators[i].lang_name +
|
||||
" for " +
|
||||
@@ -280,7 +362,11 @@ int main(int argc, const char *argv[]) {
|
||||
}
|
||||
} else {
|
||||
std::string make_rule = generators[i].make_rule(
|
||||
<<<<<<< HEAD
|
||||
*parser, output_path, *file_it, opts);
|
||||
=======
|
||||
*parser, output_path, *file_it);
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
if (!make_rule.empty())
|
||||
printf("%s\n", flatbuffers::WordWrap(
|
||||
make_rule, 80, " ", " \\").c_str());
|
||||
@@ -288,7 +374,15 @@ int main(int argc, const char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
if (proto_mode) GenerateFBS(*parser, output_path, filebase, opts);
|
||||
=======
|
||||
if (opts.proto_mode) GenerateFBS(*parser, output_path, filebase);
|
||||
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
parser->MarkGenerated();
|
||||
>>>>>>> 48f37f9e0a04f2b60046dda7fef20a8b0ebc1a70
|
||||
}
|
||||
|
||||
delete parser;
|
||||
|
||||
1239
src/idl_gen_cpp.cpp
1239
src/idl_gen_cpp.cpp
File diff suppressed because it is too large
Load Diff
@@ -52,8 +52,7 @@ static void GenNameSpace(const Namespace &name_space, std::string *_schema,
|
||||
}
|
||||
|
||||
// Generate a flatbuffer schema from the Parser's internal representation.
|
||||
std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
// Proto namespaces may clash with table names, so we have to prefix all:
|
||||
for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
|
||||
++it) {
|
||||
@@ -65,7 +64,7 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
|
||||
std::string schema;
|
||||
schema += "// Generated from " + file_name + ".proto\n\n";
|
||||
if (opts.include_dependence_headers) {
|
||||
if (parser.opts.include_dependence_headers) {
|
||||
#ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
|
||||
int num_includes = 0;
|
||||
for (auto it = parser.included_files_.begin();
|
||||
@@ -120,10 +119,9 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name,
|
||||
|
||||
bool GenerateFBS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
const std::string &file_name) {
|
||||
return SaveFile((path + file_name + ".fbs").c_str(),
|
||||
GenerateFBS(parser, file_name, opts), false);
|
||||
GenerateFBS(parser, file_name), false);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
@@ -52,20 +53,6 @@ std::string OffsetPrefix(const FieldDef &field) {
|
||||
"))\n\tif o != 0 {\n";
|
||||
}
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
static void BeginFile(const std::string name_space_name,
|
||||
const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "// automatically generated, do not modify\n\n";
|
||||
code += "package " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import (\n";
|
||||
code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
|
||||
code += ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Begin a class declaration.
|
||||
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -588,32 +575,6 @@ static std::string GenMethod(const FieldDef &field) {
|
||||
: (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
|
||||
}
|
||||
|
||||
|
||||
// Save out the generated code for a Go Table type.
|
||||
static bool SaveType(const Parser &parser, const Definition &def,
|
||||
const std::string &classcode, const std::string &path,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_name;
|
||||
std::string namespace_dir = path; // Either empty or ends in separator.
|
||||
auto &namespaces = parser.namespaces_.back()->components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) {
|
||||
namespace_name += ".";
|
||||
}
|
||||
namespace_name = *it;
|
||||
namespace_dir += *it + kPathSeparator;
|
||||
}
|
||||
EnsureDirExists(namespace_dir);
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(namespace_name, needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename = namespace_dir + def.name + ".go";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
static std::string GenTypeBasic(const Type &type) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
@@ -660,29 +621,63 @@ static void GenStructBuilder(const StructDef &struct_def,
|
||||
EndBuilderBody(code_ptr);
|
||||
}
|
||||
|
||||
class GoGenerator : public BaseGenerator {
|
||||
public:
|
||||
GoGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used*/,
|
||||
"" /* not used */){};
|
||||
bool generate() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
std::string enumcode;
|
||||
go::GenEnum(**it, &enumcode);
|
||||
if (!SaveType(**it, enumcode, false)) return false;
|
||||
}
|
||||
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
go::GenStruct(**it, &declcode, parser_.root_struct_def_);
|
||||
if (!SaveType(**it, declcode, true)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Begin by declaring namespace and imports.
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code += "package " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import (\n";
|
||||
code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
|
||||
code += ")\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Save out the generated code for a Go Table type.
|
||||
bool SaveType(const Definition &def, const std::string &classcode,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename =
|
||||
NamespaceDir(*def.defined_namespace) + def.name + ".go";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
};
|
||||
} // namespace go
|
||||
|
||||
bool GenerateGo(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string & /*file_name*/,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
std::string enumcode;
|
||||
go::GenEnum(**it, &enumcode);
|
||||
if (!go::SaveType(parser, **it, enumcode, path, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
go::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!go::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool GenerateGo(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
go::GoGenerator generator(parser, path, file_name);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
216
src/idl_gen_grpc.cpp
Normal file
216
src/idl_gen_grpc.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2014 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
#include "src/compiler/cpp_generator.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
class FlatBufMethod : public grpc_cpp_generator::Method {
|
||||
public:
|
||||
enum Streaming { kNone, kClient, kServer, kBiDi };
|
||||
|
||||
FlatBufMethod(const RPCCall *method)
|
||||
: method_(method) {
|
||||
streaming_ = kNone;
|
||||
auto val = method_->attributes.Lookup("streaming");
|
||||
if (val) {
|
||||
if (val->constant == "client") streaming_ = kClient;
|
||||
if (val->constant == "server") streaming_ = kServer;
|
||||
if (val->constant == "bidi") streaming_ = kBiDi;
|
||||
}
|
||||
}
|
||||
|
||||
std::string name() const { return method_->name; }
|
||||
|
||||
std::string GRPCType(const StructDef &sd) const {
|
||||
return "flatbuffers::BufferRef<" + sd.name + ">";
|
||||
}
|
||||
|
||||
std::string input_type_name() const {
|
||||
return GRPCType(*method_->request);
|
||||
}
|
||||
std::string output_type_name() const {
|
||||
return GRPCType(*method_->response);
|
||||
}
|
||||
|
||||
bool NoStreaming() const { return streaming_ == kNone; }
|
||||
bool ClientOnlyStreaming() const { return streaming_ == kClient; }
|
||||
bool ServerOnlyStreaming() const { return streaming_ == kServer; }
|
||||
bool BidiStreaming() const { return streaming_ == kBiDi; }
|
||||
|
||||
private:
|
||||
const RPCCall *method_;
|
||||
Streaming streaming_;
|
||||
};
|
||||
|
||||
class FlatBufService : public grpc_cpp_generator::Service {
|
||||
public:
|
||||
FlatBufService(const ServiceDef *service) : service_(service) {}
|
||||
|
||||
std::string name() const { return service_->name; }
|
||||
|
||||
int method_count() const {
|
||||
return static_cast<int>(service_->calls.vec.size());
|
||||
};
|
||||
|
||||
std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
|
||||
return std::unique_ptr<const grpc_cpp_generator::Method>(
|
||||
new FlatBufMethod(service_->calls.vec[i]));
|
||||
};
|
||||
|
||||
private:
|
||||
const ServiceDef *service_;
|
||||
};
|
||||
|
||||
class FlatBufPrinter : public grpc_cpp_generator::Printer {
|
||||
public:
|
||||
FlatBufPrinter(std::string *str)
|
||||
: str_(str), escape_char_('$'), indent_(0) {}
|
||||
|
||||
void Print(const std::map<std::string, std::string> &vars,
|
||||
const char *string_template) {
|
||||
std::string s = string_template;
|
||||
// Replace any occurrences of strings in "vars" that are surrounded
|
||||
// by the escape character by what they're mapped to.
|
||||
size_t pos;
|
||||
while ((pos = s.find(escape_char_)) != std::string::npos) {
|
||||
// Found an escape char, must also find the closing one.
|
||||
size_t pos2 = s.find(escape_char_, pos + 1);
|
||||
// If placeholder not closed, ignore.
|
||||
if (pos2 == std::string::npos) break;
|
||||
auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
|
||||
// If unknown placeholder, ignore.
|
||||
if (it == vars.end()) break;
|
||||
// Subtitute placeholder.
|
||||
s.replace(pos, pos2 - pos + 1, it->second);
|
||||
}
|
||||
Print(s.c_str());
|
||||
}
|
||||
|
||||
void Print(const char *s) {
|
||||
// Add this string, but for each part separated by \n, add indentation.
|
||||
for (;;) {
|
||||
// Current indentation.
|
||||
str_->insert(str_->end(), indent_ * 2, ' ');
|
||||
// See if this contains more than one line.
|
||||
auto lf = strchr(s, '\n');
|
||||
if (lf) {
|
||||
(*str_) += std::string(s, lf + 1);
|
||||
s = lf + 1;
|
||||
if (!*s) break; // Only continue if there's more lines.
|
||||
} else {
|
||||
(*str_) += s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Indent() { indent_++; }
|
||||
void Outdent() { indent_--; assert(indent_ >= 0); }
|
||||
|
||||
private:
|
||||
std::string *str_;
|
||||
char escape_char_;
|
||||
int indent_;
|
||||
};
|
||||
|
||||
class FlatBufFile : public grpc_cpp_generator::File {
|
||||
public:
|
||||
FlatBufFile(const Parser &parser, const std::string &file_name)
|
||||
: parser_(parser), file_name_(file_name) {}
|
||||
|
||||
std::string filename() const { return file_name_; }
|
||||
std::string filename_without_ext() const {
|
||||
return StripExtension(file_name_);
|
||||
}
|
||||
|
||||
std::string message_header_ext() const { return "_generated.h"; }
|
||||
std::string service_header_ext() const { return ".grpc.fb.h"; }
|
||||
|
||||
std::string package() const {
|
||||
return parser_.namespaces_.back()->GetFullyQualifiedName("");
|
||||
}
|
||||
|
||||
std::vector<std::string> package_parts() const {
|
||||
return parser_.namespaces_.back()->components;
|
||||
}
|
||||
|
||||
std::string additional_headers() const {
|
||||
return "#include \"flatbuffers/grpc.h\"\n";
|
||||
}
|
||||
|
||||
int service_count() const {
|
||||
return static_cast<int>(parser_.services_.vec.size());
|
||||
};
|
||||
|
||||
std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
|
||||
return std::unique_ptr<const grpc_cpp_generator::Service> (
|
||||
new FlatBufService(parser_.services_.vec[i]));
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(std::string *str) const {
|
||||
return std::unique_ptr<grpc_cpp_generator::Printer>(
|
||||
new FlatBufPrinter(str));
|
||||
}
|
||||
|
||||
private:
|
||||
const Parser &parser_;
|
||||
const std::string &file_name_;
|
||||
};
|
||||
|
||||
bool GenerateGRPC(const Parser &parser,
|
||||
const std::string &/*path*/,
|
||||
const std::string &file_name) {
|
||||
|
||||
int nservices = 0;
|
||||
for (auto it = parser.services_.vec.begin();
|
||||
it != parser.services_.vec.end(); ++it) {
|
||||
if (!(*it)->generated) nservices++;
|
||||
}
|
||||
if (!nservices) return true;
|
||||
|
||||
grpc_cpp_generator::Parameters generator_parameters;
|
||||
// TODO(wvo): make the other parameters in this struct configurable.
|
||||
generator_parameters.use_system_headers = true;
|
||||
|
||||
FlatBufFile fbfile(parser, file_name);
|
||||
|
||||
std::string header_code =
|
||||
grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
|
||||
|
||||
std::string source_code =
|
||||
grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
|
||||
|
||||
return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
|
||||
header_code, false) &&
|
||||
flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
|
||||
source_code, false);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -19,16 +19,74 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace js {
|
||||
|
||||
static void GenNamespaces(const Parser &parser, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name) {
|
||||
return path + file_name + "_generated.js";
|
||||
}
|
||||
|
||||
namespace js {
|
||||
// Iterate through all definitions we haven't generate code for (enums, structs,
|
||||
// and tables) and output them to a single file.
|
||||
class JsGenerator : public BaseGenerator {
|
||||
public:
|
||||
JsGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "."){};
|
||||
// Iterate through all definitions we haven't generate code for (enums,
|
||||
// structs, and tables) and output them to a single file.
|
||||
bool generate() {
|
||||
if (IsEverythingGenerated()) return true;
|
||||
|
||||
std::string enum_code, struct_code, exports_code, code;
|
||||
generateEnums(&enum_code, &exports_code);
|
||||
generateStructs(&struct_code, &exports_code);
|
||||
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
|
||||
// Generate code for all the namespace declarations.
|
||||
GenNamespaces(&code, &exports_code);
|
||||
|
||||
// Output the main declaration code from above.
|
||||
code += enum_code;
|
||||
code += struct_code;
|
||||
|
||||
if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
|
||||
}
|
||||
|
||||
private:
|
||||
// Generate code for all enums.
|
||||
void generateEnums(std::string *enum_code_ptr,
|
||||
std::string *exports_code_ptr) {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
auto &enum_def = **it;
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate code for all structs.
|
||||
void generateStructs(std::string *decl_code_ptr,
|
||||
std::string *exports_code_ptr) {
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
auto &struct_def = **it;
|
||||
GenStruct(struct_def, decl_code_ptr, exports_code_ptr);
|
||||
}
|
||||
}
|
||||
void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
|
||||
std::set<std::string> namespaces;
|
||||
|
||||
for (auto it = parser.namespaces_.begin();
|
||||
it != parser.namespaces_.end(); ++it) {
|
||||
for (auto it = parser_.namespaces_.begin();
|
||||
it != parser_.namespaces_.end(); ++it) {
|
||||
std::string namespace_so_far;
|
||||
|
||||
// Gather all parent namespaces for this namespace
|
||||
@@ -61,22 +119,6 @@ static void GenNamespaces(const Parser &parser, std::string *code_ptr,
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
static std::string WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) {
|
||||
std::string qualified_name;
|
||||
for (auto it = ns->components.begin();
|
||||
it != ns->components.end(); ++it) {
|
||||
qualified_name += *it + ".";
|
||||
}
|
||||
return qualified_name + name;
|
||||
}
|
||||
|
||||
static std::string WrapInNameSpace(const Definition &def) {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
|
||||
// Generate a documentation comment, if available.
|
||||
static void GenDocComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
@@ -122,7 +164,7 @@ static void GenDocComment(std::string *code_ptr,
|
||||
}
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
if (enum_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
@@ -169,7 +211,7 @@ static std::string GenType(const Type &type) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenGetter(const Type &type, const std::string &arguments) {
|
||||
std::string GenGetter(const Type &type, const std::string &arguments) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_STRING: return "this.bb.__string" + arguments;
|
||||
case BASE_TYPE_STRUCT: return "this.bb.__struct" + arguments;
|
||||
@@ -189,7 +231,7 @@ static std::string GenGetter(const Type &type, const std::string &arguments) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const Value &value) {
|
||||
std::string GenDefaultValue(const Value &value, const std::string &context) {
|
||||
if (value.type.enum_def) {
|
||||
if (auto val = value.type.enum_def->ReverseLookup(
|
||||
atoi(value.constant.c_str()), false)) {
|
||||
@@ -205,20 +247,18 @@ static std::string GenDefaultValue(const Value &value) {
|
||||
return "null";
|
||||
|
||||
case BASE_TYPE_LONG:
|
||||
case BASE_TYPE_ULONG:
|
||||
if (value.constant != "0") {
|
||||
int64_t constant = StringToInt(value.constant.c_str());
|
||||
return "new flatbuffers.Long(" + NumToString((int32_t)constant) +
|
||||
", " + NumToString((int32_t)(constant >> 32)) + ")";
|
||||
}
|
||||
return "flatbuffers.Long.ZERO";
|
||||
case BASE_TYPE_ULONG: {
|
||||
int64_t constant = StringToInt(value.constant.c_str());
|
||||
return context + ".createLong(" + NumToString((int32_t)constant) +
|
||||
", " + NumToString((int32_t)(constant >> 32)) + ")";
|
||||
}
|
||||
|
||||
default:
|
||||
return value.constant;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenTypeName(const Type &type, bool input) {
|
||||
std::string GenTypeName(const Type &type, bool input) {
|
||||
if (!input) {
|
||||
if (type.base_type == BASE_TYPE_STRING) {
|
||||
return "string|Uint8Array";
|
||||
@@ -270,7 +310,7 @@ static std::string MaybeScale(T value) {
|
||||
return value != 1 ? " * " + NumToString(value) : "";
|
||||
}
|
||||
|
||||
static void GenStructArgs(const StructDef &struct_def,
|
||||
void GenStructArgs(const StructDef &struct_def,
|
||||
std::string *annotations,
|
||||
std::string *arguments,
|
||||
const std::string &nameprefix) {
|
||||
@@ -321,8 +361,7 @@ static void GenStructBody(const StructDef &struct_def,
|
||||
}
|
||||
|
||||
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||
static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
std::string *code_ptr, std::string *exports_ptr) {
|
||||
void GenStruct(StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
|
||||
if (struct_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
@@ -376,13 +415,13 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate the identifier check method
|
||||
if (parser.root_struct_def_ == &struct_def &&
|
||||
!parser.file_identifier_.empty()) {
|
||||
if (parser_.root_struct_def_ == &struct_def &&
|
||||
!parser_.file_identifier_.empty()) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@returns {boolean}");
|
||||
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
|
||||
code += " return bb.__has_identifier('" + parser.file_identifier_;
|
||||
code += " return bb.__has_identifier('" + parser_.file_identifier_;
|
||||
code += "');\n};\n\n";
|
||||
}
|
||||
}
|
||||
@@ -417,7 +456,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
index += ", optionalEncoding";
|
||||
}
|
||||
code += offset_prefix + GenGetter(field.value.type,
|
||||
"(" + index + ")") + " : " + GenDefaultValue(field.value);
|
||||
"(" + index + ")") + " : " + GenDefaultValue(field.value, "this.bb");
|
||||
code += ";\n";
|
||||
}
|
||||
}
|
||||
@@ -485,7 +524,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
code += "false";
|
||||
} else if (field.value.type.element == BASE_TYPE_LONG ||
|
||||
field.value.type.element == BASE_TYPE_ULONG) {
|
||||
code += "flatbuffers.Long.ZERO";
|
||||
code += "this.bb.createLong(0, 0)";
|
||||
} else if (IsScalar(field.value.type.element)) {
|
||||
code += "0";
|
||||
} else {
|
||||
@@ -511,12 +550,24 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
}
|
||||
code += "};\n\n";
|
||||
|
||||
// Emit a length helper
|
||||
// Emit vector helpers
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
// Emit a length helper
|
||||
GenDocComment(code_ptr, "@returns {number}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Length = function() {\n" + offset_prefix;
|
||||
code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
|
||||
|
||||
// For scalar types, emit a typed array helper
|
||||
auto vectorType = field.value.type.VectorType();
|
||||
if (IsScalar(vectorType.base_type)) {
|
||||
GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Array = function() {\n" + offset_prefix;
|
||||
code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
|
||||
"this.bb.__vector(this.bb_pos + offset), "
|
||||
"this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +621,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
if (field.value.type.base_type == BASE_TYPE_BOOL) {
|
||||
code += "+";
|
||||
}
|
||||
code += GenDefaultValue(field.value);
|
||||
code += GenDefaultValue(field.value, "builder");
|
||||
}
|
||||
code += ");\n};\n\n";
|
||||
|
||||
@@ -633,86 +684,33 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
|
||||
code += "};\n\n";
|
||||
|
||||
// Generate the method to complete buffer construction
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
if (parser_.root_struct_def_ == &struct_def) {
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {flatbuffers.Offset} offset");
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
code += " builder.finish(offset";
|
||||
if (!parser.file_identifier_.empty()) {
|
||||
code += ", '" + parser.file_identifier_ + "'";
|
||||
if (!parser_.file_identifier_.empty()) {
|
||||
code += ", '" + parser_.file_identifier_ + "'";
|
||||
}
|
||||
code += ");\n";
|
||||
code += "};\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace js
|
||||
|
||||
// Iterate through all definitions we haven't generate code for (enums, structs,
|
||||
// and tables) and output them to a single file.
|
||||
std::string GenerateJS(const Parser &parser,
|
||||
const GeneratorOptions &opts) {
|
||||
using namespace js;
|
||||
|
||||
// Generate code for all the enum declarations.
|
||||
std::string enum_code, exports_code;
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
GenEnum(**it, &enum_code, &exports_code);
|
||||
}
|
||||
|
||||
// Generate code for all structs, then all tables.
|
||||
std::string decl_code;
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
GenStruct(parser, **it, &decl_code, &exports_code);
|
||||
}
|
||||
|
||||
// Only output file-level code if there were any declarations.
|
||||
if (enum_code.length() || decl_code.length()) {
|
||||
std::string code;
|
||||
code = "// automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify\n\n";
|
||||
|
||||
// Generate code for all the namespace declarations.
|
||||
GenNamespaces(parser, &code, &exports_code);
|
||||
|
||||
// Output the main declaration code from above.
|
||||
code += enum_code;
|
||||
code += decl_code;
|
||||
|
||||
if (!exports_code.empty() && !opts.skip_js_exports) {
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name) {
|
||||
return path + file_name + "_generated.js";
|
||||
}
|
||||
|
||||
bool GenerateJS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
auto code = GenerateJS(parser, opts);
|
||||
return !code.length() ||
|
||||
SaveFile(GeneratedFileName(path, file_name).c_str(), code, false);
|
||||
bool GenerateJS(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
js::JsGenerator generator(parser, path, file_name);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
const std::string &file_name) {
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
std::string make_rule = GeneratedFileName(path, filebase) + ": ";
|
||||
|
||||
@@ -21,56 +21,78 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace php {
|
||||
|
||||
static std::string GenGetter(const Type &type);
|
||||
static std::string GenDefaultValue(const Value &value);
|
||||
static std::string GenMethod(const FieldDef &field);
|
||||
static void GenStructBuilder(const StructDef &struct_def,
|
||||
std::string *code_ptr);
|
||||
static std::string GenTypeBasic(const Type &type);
|
||||
static std::string GenTypeGet(const Type &type);
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
static std::string WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) {
|
||||
std::string qualified_name = "\\";
|
||||
for (auto it = ns->components.begin();
|
||||
it != ns->components.end(); ++it) {
|
||||
qualified_name += *it + "\\";
|
||||
}
|
||||
return qualified_name + name;
|
||||
}
|
||||
|
||||
static std::string WrapInNameSpace(const Definition &def) {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
|
||||
|
||||
// Hardcode spaces per indentation.
|
||||
const std::string Indent = " ";
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
static void BeginFile(const std::string name_space_name,
|
||||
const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "<?php\n";
|
||||
code += "// automatically generated, do not modify\n\n";
|
||||
code += "namespace " + name_space_name + ";\n\n";
|
||||
|
||||
if (needs_imports) {
|
||||
code += "use \\Google\\FlatBuffers\\Struct;\n";
|
||||
code += "use \\Google\\FlatBuffers\\Table;\n";
|
||||
code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
|
||||
code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
|
||||
code += "\n";
|
||||
class PhpGenerator : public BaseGenerator {
|
||||
public:
|
||||
PhpGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "\\", "\\"){};
|
||||
bool generate() {
|
||||
if (!generateEnums()) return false;
|
||||
if (!generateStructs()) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool generateEnums() {
|
||||
for (auto it = parser_.enums_.vec.begin();
|
||||
it != parser_.enums_.vec.end(); ++it) {
|
||||
auto &enum_def = **it;
|
||||
std::string enumcode;
|
||||
GenEnum(enum_def, &enumcode);
|
||||
if (!SaveType(enum_def, enumcode, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generateStructs() {
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
auto &struct_def = **it;
|
||||
std::string declcode;
|
||||
GenStruct(struct_def, &declcode);
|
||||
if (!SaveType(struct_def, declcode, true)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
void BeginFile(const std::string name_space_name,
|
||||
const bool needs_imports, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "<?php\n";
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code += "namespace " + name_space_name + ";\n\n";
|
||||
|
||||
if (needs_imports) {
|
||||
code += "use \\Google\\FlatBuffers\\Struct;\n";
|
||||
code += "use \\Google\\FlatBuffers\\Table;\n";
|
||||
code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
|
||||
code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
|
||||
code += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Save out the generated code for a Php Table type.
|
||||
bool SaveType(const Definition &def, const std::string &classcode,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(FullNamespace("\\", *def.defined_namespace),
|
||||
needs_imports, &code);
|
||||
code += classcode;
|
||||
|
||||
std::string filename = NamespaceDir(*def.defined_namespace) +
|
||||
kPathSeparator + def.name + ".php";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
// Begin a class declaration.
|
||||
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -140,8 +162,8 @@ namespace php {
|
||||
code += Indent + " * @return " + struct_def.name + "\n";
|
||||
code += Indent + " **/\n";
|
||||
code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$this->bb_pos = $_i;\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$this->bb_pos = $_i;\n";
|
||||
code += Indent + Indent + "$this->bb = $_bb;\n";
|
||||
code += Indent + Indent + "return $this;\n";
|
||||
code += Indent + "}\n\n";
|
||||
@@ -165,6 +187,22 @@ namespace php {
|
||||
code += Indent + "}\n\n";
|
||||
}
|
||||
|
||||
// Get a [ubyte] vector as a byte array.
|
||||
static void GetUByte(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += Indent + "/**\n";
|
||||
code += Indent + " * @return string\n";
|
||||
code += Indent + " */\n";
|
||||
code += Indent + "public function get";
|
||||
code += MakeCamel(field.name) + "Bytes()\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "return $this->__vector_as_bytes(";
|
||||
code += NumToString(field.value.offset) + ");\n";
|
||||
code += Indent + "}\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a struct's scalar.
|
||||
static void GetScalarFieldOfStruct(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
@@ -190,8 +228,7 @@ namespace php {
|
||||
}
|
||||
|
||||
// Get the value of a table's scalar.
|
||||
static void GetScalarFieldOfTable(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
std::string getter = GenGetter(field.value.type);
|
||||
|
||||
@@ -214,8 +251,7 @@ namespace php {
|
||||
|
||||
// Get a struct by initializing an existing struct.
|
||||
// Specific to Struct.
|
||||
static void GetStructFieldOfStruct(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += Indent + "/**\n";
|
||||
@@ -234,14 +270,13 @@ namespace php {
|
||||
|
||||
// Get a struct by initializing an existing struct.
|
||||
// Specific to Table.
|
||||
static void GetStructFieldOfTable(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += Indent + "public function get";
|
||||
code += MakeCamel(field.name);
|
||||
code += "()\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$obj = new ";
|
||||
code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
|
||||
code += Indent + Indent +
|
||||
@@ -249,21 +284,24 @@ namespace php {
|
||||
NumToString(field.value.offset) +
|
||||
");\n";
|
||||
code += Indent + Indent;
|
||||
code += "return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : ";
|
||||
code += "return $o != 0 ? $obj->init(";
|
||||
if (field.value.type.struct_def->fixed)
|
||||
{
|
||||
code += "$o + $this->bb_pos, $this->bb) : ";
|
||||
} else {
|
||||
code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
|
||||
}
|
||||
code += GenDefaultValue(field.value) + ";\n";
|
||||
|
||||
|
||||
code += Indent + "}\n\n";
|
||||
}
|
||||
|
||||
// Get the value of a string.
|
||||
static void GetStringField(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetStringField(const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += Indent + "public function get";
|
||||
code += MakeCamel(field.name);
|
||||
code += "()\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent +
|
||||
"$o = $this->__offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
@@ -275,8 +313,7 @@ namespace php {
|
||||
}
|
||||
|
||||
// Get the value of a union from an object.
|
||||
static void GetUnionField(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetUnionField(const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
code += Indent + "/**\n";
|
||||
@@ -295,9 +332,8 @@ namespace php {
|
||||
}
|
||||
|
||||
// Get the value of a vector's struct member.
|
||||
static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
|
||||
const FieldDef &field, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
|
||||
@@ -307,7 +343,7 @@ namespace php {
|
||||
code += Indent + "public function get";
|
||||
code += MakeCamel(field.name);
|
||||
code += "($j)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent +
|
||||
"$o = $this->__offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
@@ -359,7 +395,7 @@ namespace php {
|
||||
|
||||
// Get the value of a vector's non-struct member. Uses a named return
|
||||
// argument to conveniently set the zero value for the result.
|
||||
static void GetMemberOfVectorOfNonStruct(const FieldDef &field,
|
||||
void GetMemberOfVectorOfNonStruct(const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
auto vectortype = field.value.type.VectorType();
|
||||
@@ -371,7 +407,7 @@ namespace php {
|
||||
code += Indent + "public function get";
|
||||
code += MakeCamel(field.name);
|
||||
code += "($j)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent +
|
||||
"$o = $this->__offset(" +
|
||||
NumToString(field.value.offset) +
|
||||
@@ -456,7 +492,7 @@ namespace php {
|
||||
code += Indent + " */\n";
|
||||
code += Indent + "public static function start" + struct_def.name;
|
||||
code += "(FlatBufferBuilder $builder)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->StartObject(";
|
||||
code += NumToString(struct_def.fields.vec.size());
|
||||
code += ");\n";
|
||||
@@ -528,7 +564,7 @@ namespace php {
|
||||
code += "(FlatBufferBuilder $builder, ";
|
||||
code += "$" + MakeCamel(field.name, false);
|
||||
code += ")\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->add";
|
||||
code += GenMethod(field) + "X(";
|
||||
code += NumToString(offset) + ", ";
|
||||
@@ -562,7 +598,7 @@ namespace php {
|
||||
code += Indent + "public static function create";
|
||||
code += MakeCamel(field.name);
|
||||
code += "Vector(FlatBufferBuilder $builder, array $data)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->startVector(";
|
||||
code += NumToString(elem_size);
|
||||
code += ", count($data), " + NumToString(alignment);
|
||||
@@ -591,7 +627,7 @@ namespace php {
|
||||
code += Indent + "public static function start";
|
||||
code += MakeCamel(field.name);
|
||||
code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->startVector(";
|
||||
code += NumToString(elem_size);
|
||||
code += ", $numElems, " + NumToString(alignment);
|
||||
@@ -600,9 +636,7 @@ namespace php {
|
||||
}
|
||||
|
||||
// Get the offset of the end of a table.
|
||||
static void GetEndOffsetOnTable(const Parser &parser,
|
||||
const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
|
||||
|
||||
@@ -612,7 +646,7 @@ namespace php {
|
||||
code += Indent + " */\n";
|
||||
code += Indent + "public static function end" + struct_def.name;
|
||||
code += "(FlatBufferBuilder $builder)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$o = $builder->endObject();\n";
|
||||
|
||||
|
||||
@@ -629,7 +663,7 @@ namespace php {
|
||||
code += Indent + Indent + "return $o;\n";
|
||||
code += Indent + "}\n";
|
||||
|
||||
if (parser.root_struct_def_ == &struct_def) {
|
||||
if (parser_.root_struct_def_ == &struct_def) {
|
||||
code += "\n";
|
||||
code += Indent + "public static function finish";
|
||||
code += struct_def.name;
|
||||
@@ -637,16 +671,15 @@ namespace php {
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->finish($offset";
|
||||
|
||||
if (parser.file_identifier_.length())
|
||||
code += ", \"" + parser.file_identifier_ + "\"";
|
||||
if (parser_.file_identifier_.length())
|
||||
code += ", \"" + parser_.file_identifier_ + "\"";
|
||||
code += ");\n";
|
||||
code += Indent + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a struct field, conditioned on its child type(s).
|
||||
static void GenStructAccessor(const StructDef &struct_def,
|
||||
const FieldDef &field,
|
||||
// Generate a struct field, conditioned on its child type(s).
|
||||
void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
|
||||
std::string *code_ptr) {
|
||||
GenComment(field.doc_comment, code_ptr, nullptr);
|
||||
|
||||
@@ -686,13 +719,14 @@ namespace php {
|
||||
}
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR) {
|
||||
GetVectorLen(field, code_ptr);
|
||||
if (field.value.type.element == BASE_TYPE_UCHAR) {
|
||||
GetUByte(field, code_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate table constructors, conditioned on its members' types.
|
||||
static void GenTableBuilders(const Parser &parser,
|
||||
const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
|
||||
GetStartOfTable(struct_def, code_ptr);
|
||||
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
@@ -707,7 +741,7 @@ namespace php {
|
||||
code += Indent + "public static function add";
|
||||
code += MakeCamel(field.name);
|
||||
code += "(FlatBufferBuilder $builder, $offset)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "$builder->addOffsetX(";
|
||||
code += NumToString(offset) + ", $offset, 0);\n";
|
||||
code += Indent + "}\n\n";
|
||||
@@ -719,11 +753,11 @@ namespace php {
|
||||
}
|
||||
}
|
||||
|
||||
GetEndOffsetOnTable(parser, struct_def, code_ptr);
|
||||
GetEndOffsetOnTable(struct_def, code_ptr);
|
||||
}
|
||||
|
||||
// Generate struct or table methods.
|
||||
static void GenStruct(const Parser &parser, const StructDef &struct_def,
|
||||
void GenStruct(const StructDef &struct_def,
|
||||
std::string *code_ptr) {
|
||||
if (struct_def.generated) return;
|
||||
|
||||
@@ -738,13 +772,13 @@ namespace php {
|
||||
|
||||
std::string &code = *code_ptr;
|
||||
if (!struct_def.fixed) {
|
||||
if (parser.file_identifier_.length()) {
|
||||
if (parser_.file_identifier_.length()) {
|
||||
// Return the identifier
|
||||
code += Indent + "public static function " + struct_def.name;
|
||||
code += "Identifier()\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "return \"";
|
||||
code += parser.file_identifier_ + "\";\n";
|
||||
code += parser_.file_identifier_ + "\";\n";
|
||||
code += Indent + "}\n\n";
|
||||
|
||||
// Check if a buffer has the identifier.
|
||||
@@ -757,12 +791,12 @@ namespace php {
|
||||
code += Indent + "}\n\n";
|
||||
}
|
||||
|
||||
if (parser.file_extension_.length()) {
|
||||
if (parser_.file_extension_.length()) {
|
||||
// Return the extension
|
||||
code += Indent + "public static function " + struct_def.name;
|
||||
code += "Extension()\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "return \"" + parser.file_extension_;
|
||||
code += Indent + Indent + "return \"" + parser_.file_extension_;
|
||||
code += "\";\n";
|
||||
code += Indent + "}\n\n";
|
||||
}
|
||||
@@ -785,7 +819,7 @@ namespace php {
|
||||
GenStructBuilder(struct_def, code_ptr);
|
||||
} else {
|
||||
// Create a set of functions that allow table construction.
|
||||
GenTableBuilders(parser, struct_def, code_ptr);
|
||||
GenTableBuilders(struct_def, code_ptr);
|
||||
}
|
||||
EndClass(code_ptr);
|
||||
}
|
||||
@@ -815,7 +849,7 @@ namespace php {
|
||||
|
||||
code += Indent + ");\n\n";
|
||||
code += Indent + "public static function Name($e)\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
|
||||
code += Indent + Indent + Indent + "throw new \\Exception();\n";
|
||||
code += Indent + Indent + "}\n";
|
||||
@@ -843,35 +877,6 @@ namespace php {
|
||||
: (IsStruct(field.value.type) ? "Struct" : "Offset");
|
||||
}
|
||||
|
||||
|
||||
// Save out the generated code for a Php Table type.
|
||||
static bool SaveType(const Parser &parser, const Definition &def,
|
||||
const std::string &classcode, const std::string &path,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_name;
|
||||
std::string namespace_dir = path;
|
||||
|
||||
auto &namespaces = parser.namespaces_.back()->components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) {
|
||||
namespace_name += "\\";
|
||||
namespace_dir += kPathSeparator;
|
||||
}
|
||||
namespace_name += *it;
|
||||
namespace_dir += *it;
|
||||
EnsureDirExists(namespace_dir.c_str());
|
||||
}
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(namespace_name, needs_imports, &code);
|
||||
code += classcode;
|
||||
|
||||
std::string filename = namespace_dir + kPathSeparator + def.name + ".php";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
static std::string GenTypeBasic(const Type &type) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
@@ -882,7 +887,7 @@ namespace php {
|
||||
return ctypename[type.base_type];
|
||||
}
|
||||
|
||||
static std::string GenDefaultValue(const Value &value) {
|
||||
std::string GenDefaultValue(const Value &value) {
|
||||
if (value.type.enum_def) {
|
||||
if (auto val = value.type.enum_def->ReverseLookup(
|
||||
atoi(value.constant.c_str()), false)) {
|
||||
@@ -943,38 +948,20 @@ namespace php {
|
||||
code += "(FlatBufferBuilder $builder";
|
||||
StructBuilderArgs(struct_def, "", code_ptr);
|
||||
code += ")\n";
|
||||
code += Indent + "{\n";
|
||||
code += Indent + "{\n";
|
||||
|
||||
StructBuilderBody(struct_def, "", code_ptr);
|
||||
|
||||
code += Indent + Indent + "return $builder->offset();\n";
|
||||
code += Indent + "}\n";
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace php
|
||||
|
||||
} // namespace php
|
||||
|
||||
bool GeneratePhp(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string & /*file_name*/,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
std::string enumcode;
|
||||
php::GenEnum(**it, &enumcode);
|
||||
|
||||
if (!php::SaveType(parser, **it, enumcode, path, false))
|
||||
return false;
|
||||
bool GeneratePhp(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
php::PhpGenerator generator(parser, path, file_name);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
php::GenStruct(parser, **it, &declcode);
|
||||
|
||||
if (!php::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace flatbuffers
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
namespace python {
|
||||
@@ -48,18 +49,6 @@ std::string OffsetPrefix(const FieldDef &field) {
|
||||
"))\n" + Indent + Indent + "if o != 0:\n";
|
||||
}
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
static void BeginFile(const std::string name_space_name,
|
||||
const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "# automatically generated, do not modify\n\n";
|
||||
code += "# namespace: " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import flatbuffers\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Begin a class declaration.
|
||||
static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -557,37 +546,6 @@ static std::string GenMethod(const FieldDef &field) {
|
||||
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
|
||||
}
|
||||
|
||||
|
||||
// Save out the generated code for a Python Table type.
|
||||
static bool SaveType(const Parser &parser, const Definition &def,
|
||||
const std::string &classcode, const std::string &path,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_name;
|
||||
std::string namespace_dir = path;
|
||||
auto &namespaces = parser.namespaces_.back()->components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (namespace_name.length()) {
|
||||
namespace_name += ".";
|
||||
namespace_dir += kPathSeparator;
|
||||
}
|
||||
namespace_name = *it;
|
||||
namespace_dir += *it;
|
||||
EnsureDirExists(namespace_dir.c_str());
|
||||
|
||||
std::string init_py_filename = namespace_dir + "/__init__.py";
|
||||
SaveFile(init_py_filename.c_str(), "", false);
|
||||
}
|
||||
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(namespace_name, needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename = namespace_dir + kPathSeparator + def.name + ".py";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
static std::string GenTypeBasic(const Type &type) {
|
||||
static const char *ctypename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
@@ -634,29 +592,81 @@ static void GenStructBuilder(const StructDef &struct_def,
|
||||
EndBuilderBody(code_ptr);
|
||||
}
|
||||
|
||||
class PythonGenerator : public BaseGenerator {
|
||||
public:
|
||||
PythonGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used */,
|
||||
"" /* not used */){};
|
||||
bool generate() {
|
||||
if (!generateEnums()) return false;
|
||||
if (!generateStructs()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool generateEnums() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
auto &enum_def = **it;
|
||||
std::string enumcode;
|
||||
GenEnum(enum_def, &enumcode);
|
||||
if (!SaveType(enum_def, enumcode, false)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generateStructs() {
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
auto &struct_def = **it;
|
||||
std::string declcode;
|
||||
GenStruct(struct_def, &declcode, parser_.root_struct_def_);
|
||||
if (!SaveType(struct_def, declcode, true)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Begin by declaring namespace and imports.
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "# " + FlatBuffersGeneratedWarning();
|
||||
code += "# namespace: " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import flatbuffers\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Save out the generated code for a Python Table type.
|
||||
bool SaveType(const Definition &def, const std::string &classcode,
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string namespace_dir = path_;
|
||||
auto &namespaces = parser_.namespaces_.back()->components;
|
||||
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
|
||||
if (it != namespaces.begin()) namespace_dir += kPathSeparator;
|
||||
namespace_dir += *it;
|
||||
std::string init_py_filename = namespace_dir + "/__init__.py";
|
||||
SaveFile(init_py_filename.c_str(), "", false);
|
||||
}
|
||||
|
||||
std::string code = "";
|
||||
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename = NamespaceDir(*def.defined_namespace) +
|
||||
kPathSeparator + def.name + ".py";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace python
|
||||
|
||||
bool GeneratePython(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string & /*file_name*/,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
for (auto it = parser.enums_.vec.begin();
|
||||
it != parser.enums_.vec.end(); ++it) {
|
||||
std::string enumcode;
|
||||
python::GenEnum(**it, &enumcode);
|
||||
if (!python::SaveType(parser, **it, enumcode, path, false))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = parser.structs_.vec.begin();
|
||||
it != parser.structs_.vec.end(); ++it) {
|
||||
std::string declcode;
|
||||
python::GenStruct(**it, &declcode, parser.root_struct_def_);
|
||||
if (!python::SaveType(parser, **it, declcode, path, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool GeneratePython(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
python::PythonGenerator generator(parser, path, file_name);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -23,21 +23,21 @@
|
||||
namespace flatbuffers {
|
||||
|
||||
static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
int indent, const GeneratorOptions &opts,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text);
|
||||
|
||||
// If indentation is less than 0, that indicates we don't want any newlines
|
||||
// either.
|
||||
const char *NewLine(const GeneratorOptions &opts) {
|
||||
const char *NewLine(const IDLOptions &opts) {
|
||||
return opts.indent_step >= 0 ? "\n" : "";
|
||||
}
|
||||
|
||||
int Indent(const GeneratorOptions &opts) {
|
||||
int Indent(const IDLOptions &opts) {
|
||||
return std::max(opts.indent_step, 0);
|
||||
}
|
||||
|
||||
// Output an identifier with or without quotes depending on strictness.
|
||||
void OutputIdentifier(const std::string &name, const GeneratorOptions &opts,
|
||||
void OutputIdentifier(const std::string &name, const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
if (opts.strict_json) text += "\"";
|
||||
@@ -50,7 +50,7 @@ void OutputIdentifier(const std::string &name, const GeneratorOptions &opts,
|
||||
// The general case for scalars:
|
||||
template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
StructDef * /*union_sd*/,
|
||||
const GeneratorOptions &opts,
|
||||
const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
if (type.enum_def && opts.output_enum_identifiers) {
|
||||
@@ -70,7 +70,7 @@ template<typename T> void Print(T val, Type type, int /*indent*/,
|
||||
|
||||
// Print a vector a sequence of JSON values, comma separated, wrapped in "[]".
|
||||
template<typename T> void PrintVector(const Vector<T> &v, Type type,
|
||||
int indent, const GeneratorOptions &opts,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
text += "[";
|
||||
@@ -136,7 +136,7 @@ static void EscapeString(const String &s, std::string *_text) {
|
||||
template<> void Print<const void *>(const void *val,
|
||||
Type type, int indent,
|
||||
StructDef *union_sd,
|
||||
const GeneratorOptions &opts,
|
||||
const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
switch (type.base_type) {
|
||||
case BASE_TYPE_UNION:
|
||||
@@ -181,7 +181,7 @@ template<> void Print<const void *>(const void *val,
|
||||
// Generate text for a scalar field.
|
||||
template<typename T> static void GenField(const FieldDef &fd,
|
||||
const Table *table, bool fixed,
|
||||
const GeneratorOptions &opts,
|
||||
const IDLOptions &opts,
|
||||
int indent,
|
||||
std::string *_text) {
|
||||
Print(fixed ?
|
||||
@@ -193,7 +193,7 @@ template<typename T> static void GenField(const FieldDef &fd,
|
||||
// Generate text for non-scalar field.
|
||||
static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent, StructDef *union_sd,
|
||||
const GeneratorOptions &opts, std::string *_text) {
|
||||
const IDLOptions &opts, std::string *_text) {
|
||||
const void *val = nullptr;
|
||||
if (fixed) {
|
||||
// The only non-scalar fields in structs are structs.
|
||||
@@ -211,7 +211,7 @@ static void GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
// Generate text for a struct or table, values separated by commas, indented,
|
||||
// and bracketed by "{}"
|
||||
static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
int indent, const GeneratorOptions &opts,
|
||||
int indent, const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
text += "{";
|
||||
@@ -273,16 +273,16 @@ static void GenStruct(const StructDef &struct_def, const Table *table,
|
||||
|
||||
// Generate a text representation of a flatbuffer in JSON format.
|
||||
void GenerateText(const Parser &parser, const void *flatbuffer,
|
||||
const GeneratorOptions &opts, std::string *_text) {
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
assert(parser.root_struct_def_); // call SetRootType()
|
||||
text.reserve(1024); // Reduce amount of inevitable reallocs.
|
||||
GenStruct(*parser.root_struct_def_,
|
||||
GetRoot<Table>(flatbuffer),
|
||||
0,
|
||||
opts,
|
||||
parser.opts,
|
||||
_text);
|
||||
text += NewLine(opts);
|
||||
text += NewLine(parser.opts);
|
||||
}
|
||||
|
||||
std::string TextFileName(const std::string &path,
|
||||
@@ -292,12 +292,10 @@ std::string TextFileName(const std::string &path,
|
||||
|
||||
bool GenerateTextFile(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions &opts) {
|
||||
const std::string &file_name) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
|
||||
std::string text;
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), opts,
|
||||
&text);
|
||||
GenerateText(parser, parser.builder_.GetBufferPointer(), &text);
|
||||
return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(),
|
||||
text,
|
||||
false);
|
||||
@@ -305,8 +303,7 @@ bool GenerateTextFile(const Parser &parser,
|
||||
|
||||
std::string TextMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name,
|
||||
const GeneratorOptions & /*opts*/) {
|
||||
const std::string &file_name) {
|
||||
if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(file_name));
|
||||
|
||||
1603
src/idl_parser.cpp
1603
src/idl_parser.cpp
File diff suppressed because it is too large
Load Diff
@@ -287,14 +287,17 @@ void SetString(const reflection::Schema &schema, const std::string &val,
|
||||
const String *str, std::vector<uint8_t> *flatbuf,
|
||||
const reflection::Object *root_table) {
|
||||
auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
|
||||
auto start = static_cast<uoffset_t>(reinterpret_cast<const uint8_t *>(str) -
|
||||
flatbuf->data() +
|
||||
sizeof(uoffset_t));
|
||||
auto str_start = static_cast<uoffset_t>(
|
||||
reinterpret_cast<const uint8_t *>(str) - flatbuf->data());
|
||||
auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
|
||||
if (delta) {
|
||||
// Clear the old string, since we don't want parts of it remaining.
|
||||
memset(flatbuf->data() + start, 0, str->Length());
|
||||
// Different size, we must expand (or contract).
|
||||
ResizeContext(schema, start, delta, flatbuf, root_table);
|
||||
// Set the new length.
|
||||
WriteScalar(flatbuf->data() + str_start,
|
||||
static_cast<uoffset_t>(val.size()));
|
||||
}
|
||||
// Copy new data. Safe because we created the right amount of space.
|
||||
memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
|
||||
@@ -351,7 +354,8 @@ void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
|
||||
Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
const reflection::Schema &schema,
|
||||
const reflection::Object &objectdef,
|
||||
const Table &table) {
|
||||
const Table &table,
|
||||
bool use_string_pooling) {
|
||||
// Before we can construct the table, we have to first generate any
|
||||
// subobjects, and collect their offsets.
|
||||
std::vector<uoffset_t> offsets;
|
||||
@@ -363,7 +367,9 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
uoffset_t offset = 0;
|
||||
switch (fielddef.type()->base_type()) {
|
||||
case reflection::String: {
|
||||
offset = fbb.CreateString(GetFieldS(table, fielddef)).o;
|
||||
offset = use_string_pooling
|
||||
? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
|
||||
: fbb.CreateString(GetFieldS(table, fielddef)).o;
|
||||
break;
|
||||
}
|
||||
case reflection::Obj: {
|
||||
@@ -392,7 +398,9 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
std::vector<Offset<const String *>> elements(vec->size());
|
||||
auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
|
||||
for (uoffset_t i = 0; i < vec_s->size(); i++) {
|
||||
elements[i] = fbb.CreateString(vec_s->Get(i)).o;
|
||||
elements[i] = use_string_pooling
|
||||
? fbb.CreateSharedString(vec_s->Get(i)).o
|
||||
: fbb.CreateString(vec_s->Get(i)).o;
|
||||
}
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
|
||||
86
src/util.cpp
Normal file
86
src/util.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/util.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
bool FileExistsRaw(const char *name) {
|
||||
std::ifstream ifs(name);
|
||||
return ifs.good();
|
||||
}
|
||||
|
||||
bool LoadFileRaw(const char *name, bool binary, std::string *buf) {
|
||||
if (DirExists(name)) return false;
|
||||
std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
|
||||
if (!ifs.is_open()) return false;
|
||||
if (binary) {
|
||||
// The fastest way to read a file into a string.
|
||||
ifs.seekg(0, std::ios::end);
|
||||
auto size = ifs.tellg();
|
||||
(*buf).resize(static_cast<size_t>(size));
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
ifs.read(&(*buf)[0], (*buf).size());
|
||||
} else {
|
||||
// This is slower, but works correctly on all platforms for text files.
|
||||
std::ostringstream oss;
|
||||
oss << ifs.rdbuf();
|
||||
*buf = oss.str();
|
||||
}
|
||||
return !ifs.bad();
|
||||
}
|
||||
|
||||
static LoadFileFunction g_load_file_function = LoadFileRaw;
|
||||
static FileExistsFunction g_file_exists_function = FileExistsRaw;
|
||||
|
||||
bool LoadFile(const char *name, bool binary, std::string *buf) {
|
||||
assert(g_load_file_function);
|
||||
return g_load_file_function(name, binary, buf);
|
||||
}
|
||||
|
||||
bool FileExists(const char *name) {
|
||||
assert(g_file_exists_function);
|
||||
return g_file_exists_function(name);
|
||||
}
|
||||
|
||||
bool DirExists(const char *name) {
|
||||
#ifdef _WIN32
|
||||
#define flatbuffers_stat _stat
|
||||
#define FLATBUFFERS_S_IFDIR _S_IFDIR
|
||||
#else
|
||||
#define flatbuffers_stat stat
|
||||
#define FLATBUFFERS_S_IFDIR S_IFDIR
|
||||
#endif
|
||||
struct flatbuffers_stat file_info;
|
||||
if (flatbuffers_stat(name, &file_info) != 0) return false;
|
||||
return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0;
|
||||
}
|
||||
|
||||
LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) {
|
||||
LoadFileFunction previous_function = g_load_file_function;
|
||||
g_load_file_function = load_file_function ? load_file_function : LoadFileRaw;
|
||||
return previous_function;
|
||||
}
|
||||
|
||||
FileExistsFunction SetFileExistsFunction(
|
||||
FileExistsFunction file_exists_function) {
|
||||
FileExistsFunction previous_function = g_file_exists_function;
|
||||
g_file_exists_function = file_exists_function ?
|
||||
file_exists_function : FileExistsRaw;
|
||||
return previous_function;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
Reference in New Issue
Block a user