Files
flatbuffers-bigfoot/src/idl_gen_python.cpp
lu-wang-g fd4ff23da0 Keep methods with struct name and switch them to default (#6879)
* Keep methods with struct name and switch them to default

This PR can help fix the following two issues:
1): A set of simplified API (without struct name) was added in
https://github.com/google/flatbuffers/pull/6336. It causes name
conflict when merging all generated python file into a single one
(the primary usage senario in Google).
2): Flatbuffers 2.0 generates absolute import path, which may cause
name space conflicts. See more details in
https://github.com/google/flatbuffers/issues/5840.

The solution for both is to generate the merged Python code, similar
C++. The merged code will not contain the simplied API, but only the
method with struct name. For issue (1), it will mimic the exactly
usage pattern for Google internal. For issue (2), users can generate
the merged flatbuffer code, without worrying about the imports.

The above idea will be implemented in the following steps:
Step 1 (this PR): revert changes in https://github.com/google/flatbuffers/pull/6336
that set the simplified API as default. Remove statements that the
original API will be deprecated, and reset the original API as default.
Step 2 (the following PR): create a flag to generate the merged code.
The Simplified API will be removed from the merged code, otherwise it
will cause name conflict.

* Update the generated sample code

* Update the generated example code

* Reverst the changes of GetRootAs

* Update examples from grpc/example/generate.sh
2021-11-04 15:12:25 -07:00

1847 lines
69 KiB
C++

/*
* 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 <cctype>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
namespace python {
// Hardcode spaces per indentation.
const CommentConfig def_comment = {nullptr, "#", nullptr};
const std::string Indent = " ";
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 */, "py"),
float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
static const char *const keywords[] = {
"False", "None", "True", "and", "as", "assert", "break",
"class", "continue", "def", "del", "elif", "else", "except",
"finally", "for", "from", "global", "if", "import", "in",
"is", "lambda", "nonlocal", "not", "or", "pass", "raise",
"return", "try", "while", "with", "yield"};
keywords_.insert(std::begin(keywords), std::end(keywords));
}
// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
std::string OffsetPrefix(const FieldDef &field) {
return "\n" + Indent + Indent +
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
"(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
Indent + Indent + "if o != 0:\n";
}
// Begin a class declaration.
void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
code += "class " + NormalizedName(struct_def) + "(object):\n";
code += Indent + "__slots__ = ['_tab']";
code += "\n\n";
}
// Begin enum code with a class declaration.
void BeginEnum(const std::string &class_name, std::string *code_ptr) {
auto &code = *code_ptr;
code += "class " + class_name + "(object):\n";
}
std::string EscapeKeyword(const std::string &name) const {
return keywords_.find(name) == keywords_.end() ? name : name + "_";
}
std::string NormalizedName(const Definition &definition) const {
return EscapeKeyword(definition.name);
}
std::string NormalizedName(const EnumVal &ev) const {
return EscapeKeyword(ev.name);
}
// Converts the name of a definition into upper Camel format.
std::string MakeUpperCamel(const Definition &definition) const {
return MakeCamel(NormalizedName(definition), true);
}
// Converts the name of a definition into lower Camel format.
std::string MakeLowerCamel(const Definition &definition) const {
auto name = MakeCamel(NormalizedName(definition), false);
name[0] = CharToLower(name[0]);
return name;
}
// Starts a new line and then indents.
std::string GenIndents(int num) {
return "\n" + std::string(num * Indent.length(), ' ');
}
// A single enum member.
void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
std::string *code_ptr) {
auto &code = *code_ptr;
code += Indent;
code += NormalizedName(ev);
code += " = ";
code += enum_def.ToString(ev) + "\n";
}
// End enum code.
void EndEnum(std::string *code_ptr) {
auto &code = *code_ptr;
code += "\n";
}
// Initialize a new struct or table from existing data.
void NewRootTypeFromBuffer(const StructDef &struct_def,
std::string *code_ptr) {
auto &code = *code_ptr;
code += Indent + "@classmethod\n";
code += Indent + "def GetRootAs";
code += "(cls, buf, offset=0):";
code += "\n";
code += Indent + Indent;
code += "n = flatbuffers.encode.Get";
code += "(flatbuffers.packer.uoffset, buf, offset)\n";
code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
code += Indent + Indent + "x.Init(buf, n + offset)\n";
code += Indent + Indent + "return x\n";
code += "\n";
// Add an alias with the old name
code += Indent + "@classmethod\n";
code += Indent + "def GetRootAs";
code += NormalizedName(struct_def);
code += "(cls, buf, offset=0):\n";
code +=
Indent + Indent +
"\"\"\"This method is deprecated. Please switch to GetRootAs.\"\"\"\n";
code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n";
}
// Initialize an existing object with other data, to avoid an allocation.
void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += "Init(self, buf, pos):\n";
code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
code += "\n";
}
// Get the length of a vector.
void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "Length(self";
code += "):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
code += Indent + Indent + "return 0\n\n";
}
// Determines whether a vector is none or not.
void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "IsNone(self";
code += "):";
code += GenIndents(2) +
"o = flatbuffers.number_types.UOffsetTFlags.py_type" +
"(self._tab.Offset(" + NumToString(field.value.offset) + "))";
code += GenIndents(2) + "return o == 0";
code += "\n\n";
}
// Get the value of a struct's scalar.
void GetScalarFieldOfStruct(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self): return " + getter;
code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
code += NumToString(field.value.offset) + "))\n";
}
// Get the value of a table's scalar.
void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self):";
code += OffsetPrefix(field);
getter += "o + self._tab.Pos)";
auto is_bool = IsBool(field.value.type.base_type);
if (is_bool) {
getter = "bool(" + getter + ")";
}
code += Indent + Indent + Indent + "return " + getter + "\n";
std::string default_value;
if (is_bool) {
default_value = field.value.constant == "0" ? "False" : "True";
} else {
default_value = IsFloat(field.value.type.base_type)
? float_const_gen_.GenFloatConstant(field)
: field.value.constant;
}
code += Indent + Indent + "return " + default_value + "\n\n";
}
// Get a struct by initializing an existing struct.
// Specific to Struct.
void GetStructFieldOfStruct(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self, obj):\n";
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
code += NumToString(field.value.offset) + ")";
code += "\n" + Indent + Indent + "return obj\n\n";
}
// Get the value of a fixed size array.
void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
const auto vec_type = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
if (IsStruct(vec_type)) {
code += "(self, obj, i):\n";
code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
code += NumToString(field.value.offset) + " + i * ";
code += NumToString(InlineSize(vec_type));
code += ")\n" + Indent + Indent + "return obj\n\n";
} else {
auto getter = GenGetter(vec_type);
code += "(self): return [" + getter;
code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
code += NumToString(field.value.offset) + " + i * ";
code += NumToString(InlineSize(vec_type));
code += ")) for i in range(";
code += NumToString(field.value.type.fixed_length) + ")]\n";
}
}
// Get a struct by initializing an existing struct.
// Specific to Table.
void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self):";
code += OffsetPrefix(field);
if (field.value.type.struct_def->fixed) {
code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
} else {
code += Indent + Indent + Indent;
code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
}
if (parser_.opts.include_dependence_headers) {
code += Indent + Indent + Indent;
code += "from " + GenPackageReference(field.value.type) + " import " +
TypeName(field) + "\n";
}
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a string.
void GetStringField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
code += "o + self._tab.Pos)\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a union from an object.
void GetUnionField(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "(self):";
code += OffsetPrefix(field);
// TODO(rw): this works and is not the good way to it:
bool is_native_table = TypeName(field) == "*flatbuffers.Table";
if (is_native_table) {
code +=
Indent + Indent + Indent + "from flatbuffers.table import Table\n";
} else if (parser_.opts.include_dependence_headers) {
code += Indent + Indent + Indent;
code += "from " + GenPackageReference(field.value.type) + " import " +
TypeName(field) + "\n";
}
code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
code += Indent + Indent + Indent + GenGetter(field.value.type);
code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Generate the package reference when importing a struct or enum from its
// module.
std::string GenPackageReference(const Type &type) {
Namespace *namespaces;
if (type.struct_def) {
namespaces = type.struct_def->defined_namespace;
} else if (type.enum_def) {
namespaces = type.enum_def->defined_namespace;
} else {
return "." + GenTypeGet(type);
}
return namespaces->GetFullyQualifiedName(GenTypeGet(type));
}
// Get the value of a vector's struct member.
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self, j):" + OffsetPrefix(field);
code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
code += Indent + Indent + Indent;
code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
code += NumToString(InlineSize(vectortype)) + "\n";
if (!(vectortype.struct_def->fixed)) {
code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
}
if (parser_.opts.include_dependence_headers) {
code += Indent + Indent + Indent;
code += "from " + GenPackageReference(field.value.type) + " import " +
TypeName(field) + "\n";
}
code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
code += Indent + Indent + Indent + "return obj\n";
code += Indent + Indent + "return None\n\n";
}
// Get the value of a vector's non-struct member. Uses a named return
// argument to conveniently set the zero value for the result.
void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field));
code += "(self, j):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
code += Indent + Indent + Indent;
code += "return " + GenGetter(field.value.type);
code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
code += NumToString(InlineSize(vectortype)) + "))\n";
if (IsString(vectortype)) {
code += Indent + Indent + "return \"\"\n";
} else {
code += Indent + Indent + "return 0\n";
}
code += "\n";
}
// Returns a non-struct vector as a numpy array. Much faster
// than iterating over the vector element by element.
void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
// Currently, we only support accessing as numpy array if
// the vector type is a scalar.
if (!(IsScalar(vectortype.base_type))) {
return;
}
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent;
code += "return ";
code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
code += MakeCamel(GenTypeGet(field.value.type));
code += "Flags, o)\n";
if (IsString(vectortype)) {
code += Indent + Indent + "return \"\"\n";
} else {
code += Indent + Indent + "return 0\n";
}
code += "\n";
}
// Returns a nested flatbuffer as itself.
void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (!nested) {
return;
} // There is no nested flatbuffer.
std::string unqualified_name = nested->constant;
std::string qualified_name = nested->constant;
auto nested_root = parser_.LookupStruct(nested->constant);
if (nested_root == nullptr) {
qualified_name =
parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
nested_root = parser_.LookupStruct(qualified_name);
}
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
(void)nested_root;
auto &code = *code_ptr;
GenReceiver(struct_def, code_ptr);
code += MakeCamel(NormalizedName(field)) + "NestedRoot(self):";
code += OffsetPrefix(field);
code += Indent + Indent + Indent;
code += "from " + qualified_name + " import " + unqualified_name + "\n";
code += Indent + Indent + Indent + "return " + unqualified_name;
code += ".GetRootAs" + unqualified_name;
code += "(self._tab.Bytes, self._tab.Vector(o))\n";
code += Indent + Indent + "return 0\n";
code += "\n";
}
// Begin the creator function signature.
void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
code += "\n";
code += "def Create" + NormalizedName(struct_def);
code += "(builder";
}
// Recursively generate arguments for a constructor, to deal with nested
// structs.
void StructBuilderArgs(const StructDef &struct_def,
const std::string nameprefix,
const std::string namesuffix, bool has_field_name,
const std::string fieldname_suffix,
std::string *code_ptr) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
const auto &field_type = field.value.type;
const auto &type =
IsArray(field_type) ? field_type.VectorType() : field_type;
if (IsStruct(type)) {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
auto subprefix = nameprefix;
if (has_field_name) {
subprefix += MakeLowerCamel(field) + fieldname_suffix;
}
StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
has_field_name, fieldname_suffix, code_ptr);
} else {
auto &code = *code_ptr;
code += std::string(", ") + nameprefix;
if (has_field_name) {
code += MakeCamel(NormalizedName(field), false);
}
code += namesuffix;
}
}
}
// End the creator function signature.
void EndBuilderArgs(std::string *code_ptr) {
auto &code = *code_ptr;
code += "):\n";
}
// Recursively generate struct construction statements and instert manual
// padding.
void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
std::string *code_ptr, size_t index = 0,
bool in_array = false) {
auto &code = *code_ptr;
std::string indent(index * 4, ' ');
code +=
indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
code += NumToString(struct_def.bytesize) + ")\n";
for (auto it = struct_def.fields.vec.rbegin();
it != struct_def.fields.vec.rend(); ++it) {
auto &field = **it;
const auto &field_type = field.value.type;
const auto &type =
IsArray(field_type) ? field_type.VectorType() : field_type;
if (field.padding)
code +=
indent + " builder.Pad(" + NumToString(field.padding) + ")\n";
if (IsStruct(field_type)) {
StructBuilderBody(*field_type.struct_def,
(nameprefix + (MakeLowerCamel(field) + "_")).c_str(),
code_ptr, index, in_array);
} else {
const auto index_var = "_idx" + NumToString(index);
if (IsArray(field_type)) {
code += indent + " for " + index_var + " in range(";
code += NumToString(field_type.fixed_length);
code += " , 0, -1):\n";
in_array = true;
}
if (IsStruct(type)) {
StructBuilderBody(
*field_type.struct_def,
(nameprefix + (MakeLowerCamel(field) + "_")).c_str(), code_ptr,
index + 1, in_array);
} else {
code += IsArray(field_type) ? " " : "";
code += indent + " builder.Prepend" + GenMethod(field) + "(";
code += nameprefix + MakeCamel(NormalizedName(field), false);
size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
for (size_t i = 0; in_array && i < array_cnt; i++) {
code += "[_idx" + NumToString(i) + "-1]";
}
code += ")\n";
}
}
}
}
void EndBuilderBody(std::string *code_ptr) {
auto &code = *code_ptr;
code += " return builder.Offset()\n";
}
// Get the value of a table's starting offset.
void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
// Generate method with struct name.
code += "def " + NormalizedName(struct_def) + "Start(builder): ";
code += "builder.StartObject(";
code += NumToString(struct_def.fields.vec.size());
code += ")\n";
// Generate method without struct name.
code += "def Start(builder):\n";
code +=
Indent + "return " + NormalizedName(struct_def) + "Start(builder)\n";
}
// Set the value of a table's field.
void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
const size_t offset, std::string *code_ptr) {
auto &code = *code_ptr;
// Generate method with struct name.
code += "def " + NormalizedName(struct_def) + "Add" +
MakeCamel(NormalizedName(field));
code += "(builder, ";
code += MakeCamel(NormalizedName(field), false);
code += "): ";
code += "builder.Prepend";
code += GenMethod(field) + "Slot(";
code += NumToString(offset) + ", ";
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
code += "flatbuffers.number_types.UOffsetTFlags.py_type";
code += "(";
code += MakeCamel(NormalizedName(field), false) + ")";
} else {
code += MakeCamel(NormalizedName(field), false);
}
code += ", ";
code += IsFloat(field.value.type.base_type)
? float_const_gen_.GenFloatConstant(field)
: field.value.constant;
code += ")\n";
// Generate method without struct name.
code += "def Add" + MakeCamel(NormalizedName(field));
code += "(builder, ";
code += MakeCamel(NormalizedName(field), false);
code += "):\n";
code += Indent + "return " + NormalizedName(struct_def) + "Add" +
MakeCamel(NormalizedName(field));
code += "(builder, ";
code += MakeCamel(NormalizedName(field), false);
code += ")\n";
}
// Set the value of one of the members of a table's vector.
void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
// Generate method with struct name.
code += "def " + NormalizedName(struct_def) + "Start";
code += MakeCamel(NormalizedName(field));
code += "Vector(builder, numElems): return builder.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
code += NumToString(elem_size);
code += ", numElems, " + NumToString(alignment);
code += ")\n";
// Generate method without struct name.
code += "def Start";
code += MakeCamel(NormalizedName(field));
code += "Vector(builder, numElems):\n";
code += Indent + "return " + NormalizedName(struct_def) + "Start";
code += MakeCamel(NormalizedName(field));
code += "Vector(builder, numElems)\n";
}
// Set the value of one of the members of a table's vector and fills in the
// elements from a bytearray. This is for simplifying the use of nested
// flatbuffers.
void BuildVectorOfTableFromBytes(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
auto nested = field.attributes.Lookup("nested_flatbuffer");
if (!nested) {
return;
} // There is no nested flatbuffer.
std::string unqualified_name = nested->constant;
std::string qualified_name = nested->constant;
auto nested_root = parser_.LookupStruct(nested->constant);
if (nested_root == nullptr) {
qualified_name =
parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
nested_root = parser_.LookupStruct(qualified_name);
}
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
(void)nested_root;
auto &code = *code_ptr;
// Generate method with struct and field name.
code += "def " + NormalizedName(struct_def) + "Make";
code += MakeCamel(NormalizedName(field));
code += "VectorFromBytes(builder, bytes):\n";
code += Indent + "builder.StartVector(";
auto vector_type = field.value.type.VectorType();
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
code += NumToString(elem_size);
code += ", len(bytes), " + NumToString(alignment);
code += ")\n";
code += Indent + "builder.head = builder.head - len(bytes)\n";
code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
code += " = bytes\n";
code += Indent + "return builder.EndVector()\n";
// Generate method without struct and field name.
code += "def Make" + MakeCamel(NormalizedName(field)) +
"VectorFromBytes(builder, bytes):\n";
code += Indent + "return " + NormalizedName(struct_def) + "Make" +
MakeCamel(NormalizedName(field)) +
"VectorFromBytes(builder, bytes)\n";
}
// Get the offset of the end of a table.
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
// Generate method with struct name.
code += "def " + NormalizedName(struct_def) + "End";
code += "(builder): ";
code += "return builder.EndObject()\n";
// Generate method without struct name.
code += "def End(builder):\n";
code += Indent + "return " + NormalizedName(struct_def) + "End(builder)";
}
// Generate the receiver for function signatures.
void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
code += Indent + "# " + NormalizedName(struct_def) + "\n";
code += Indent + "def ";
}
// 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, &def_comment, Indent.c_str());
if (IsScalar(field.value.type.base_type)) {
if (struct_def.fixed) {
GetScalarFieldOfStruct(struct_def, field, code_ptr);
} else {
GetScalarFieldOfTable(struct_def, field, code_ptr);
}
} else if (IsArray(field.value.type)) {
GetArrayOfStruct(struct_def, field, code_ptr);
} else {
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT:
if (struct_def.fixed) {
GetStructFieldOfStruct(struct_def, field, code_ptr);
} else {
GetStructFieldOfTable(struct_def, field, code_ptr);
}
break;
case BASE_TYPE_STRING:
GetStringField(struct_def, field, code_ptr);
break;
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
} else {
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
}
break;
}
case BASE_TYPE_UNION:
GetUnionField(struct_def, field, code_ptr);
break;
default:
FLATBUFFERS_ASSERT(0);
}
}
if (IsVector(field.value.type) || IsArray(field.value.type)) {
GetVectorLen(struct_def, field, code_ptr);
GetVectorIsNone(struct_def, field, code_ptr);
}
}
// Generate struct sizeof.
void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
code += Indent + "@classmethod\n";
code += Indent + "def SizeOf(cls):\n";
code +=
Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
code += "\n";
}
// Generate table constructors, conditioned on its members' types.
void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto offset = it - struct_def.fields.vec.begin();
BuildFieldOfTable(struct_def, field, offset, code_ptr);
if (IsVector(field.value.type)) {
BuildVectorOfTable(struct_def, field, code_ptr);
BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
}
}
GetEndOffsetOnTable(struct_def, code_ptr);
}
// Generate function to check for proper file identifier
void GenHasFileIdentifier(const StructDef &struct_def,
std::string *code_ptr) {
auto &code = *code_ptr;
std::string escapedID;
// In the event any of file_identifier characters are special(NULL, \, etc),
// problems occur. To prevent this, convert all chars to their hex-escaped
// equivalent.
for (auto it = parser_.file_identifier_.begin();
it != parser_.file_identifier_.end(); ++it) {
escapedID += "\\x" + IntToStringHex(*it, 2);
}
code += Indent + "@classmethod\n";
code += Indent + "def " + NormalizedName(struct_def);
code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
code += "\n";
code += Indent + Indent;
code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
code += escapedID;
code += "\", size_prefixed=size_prefixed)\n";
code += "\n";
}
// Generates struct or table methods.
void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
if (struct_def.generated) return;
GenComment(struct_def.doc_comment, code_ptr, &def_comment);
BeginClass(struct_def, code_ptr);
if (!struct_def.fixed) {
// Generate a special accessor for the table that has been declared as
// the root type.
NewRootTypeFromBuffer(struct_def, code_ptr);
if (parser_.file_identifier_.length()) {
// Generate a special function to test file_identifier
GenHasFileIdentifier(struct_def, code_ptr);
}
} else {
// Generates the SizeOf method for all structs.
GenStructSizeOf(struct_def, code_ptr);
}
// Generates the Init method that sets the field in a pre-existing
// accessor object. This is to allow object reuse.
InitializeExisting(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
GenStructAccessor(struct_def, field, code_ptr);
}
if (struct_def.fixed) {
// creates a struct constructor function
GenStructBuilder(struct_def, code_ptr);
} else {
// Creates a set of functions that allow table construction.
GenTableBuilders(struct_def, code_ptr);
}
}
void GenReceiverForObjectAPI(const StructDef &struct_def,
std::string *code_ptr) {
auto &code = *code_ptr;
code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
code += GenIndents(1) + "def ";
}
void BeginClassForObjectAPI(const StructDef &struct_def,
std::string *code_ptr) {
auto &code = *code_ptr;
code += "\n";
code += "class " + NormalizedName(struct_def) + "T(object):";
code += "\n";
}
// Gets the accoresponding python builtin type of a BaseType for scalars and
// string.
std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
if (IsBool(base_type)) {
return "bool";
} else if (IsFloat(base_type)) {
return "float";
} else if (IsInteger(base_type)) {
return "int";
} else if (base_type == BASE_TYPE_STRING) {
return "str";
} else {
FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
return "";
}
}
std::string GetDefaultValue(const FieldDef &field) {
BaseType base_type = field.value.type.base_type;
if (IsBool(base_type)) {
return field.value.constant == "0" ? "False" : "True";
} else if (IsFloat(base_type)) {
return float_const_gen_.GenFloatConstant(field);
} else if (IsInteger(base_type)) {
return field.value.constant;
} else {
// For string, struct, and table.
return "None";
}
}
void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
std::set<std::string> *import_list,
std::set<std::string> *import_typing_list) {
// Gets all possible types in the union.
import_typing_list->insert("Union");
auto &field_types = *field_types_ptr;
field_types = "Union[";
std::string separator_string = ", ";
auto enum_def = field.value.type.enum_def;
for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
++it) {
auto &ev = **it;
// Union only supports string and table.
std::string field_type;
switch (ev.union_type.base_type) {
case BASE_TYPE_STRUCT:
field_type = GenTypeGet(ev.union_type) + "T";
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(ev.union_type);
field_type = package_reference + "." + field_type;
import_list->insert("import " + package_reference);
}
break;
case BASE_TYPE_STRING:
field_type += "str";
break;
case BASE_TYPE_NONE:
field_type += "None";
break;
default:
break;
}
field_types += field_type + separator_string;
}
// Removes the last separator_string.
field_types.erase(field_types.length() - separator_string.size());
field_types += "]";
// Gets the import lists for the union.
if (parser_.opts.include_dependence_headers) {
// The package reference is generated based on enum_def, instead
// of struct_def in field.type. That's why GenPackageReference() is
// not used.
Namespace *namespaces = field.value.type.enum_def->defined_namespace;
auto package_reference = namespaces->GetFullyQualifiedName(
MakeUpperCamel(*(field.value.type.enum_def)));
auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
import_list->insert("import " + package_reference);
}
}
void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
std::set<std::string> *import_list,
std::set<std::string> *import_typing_list) {
import_typing_list->insert("Optional");
auto &field_type = *field_type_ptr;
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(field.value.type);
field_type = package_reference + "." + TypeName(field) + "T]";
import_list->insert("import " + package_reference);
} else {
field_type = TypeName(field) + "T]";
}
field_type = "Optional[" + field_type;
}
void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
std::set<std::string> *import_list,
std::set<std::string> *import_typing_list) {
import_typing_list->insert("List");
auto &field_type = *field_type_ptr;
auto base_type = field.value.type.VectorType().base_type;
if (base_type == BASE_TYPE_STRUCT) {
field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
if (parser_.opts.include_dependence_headers) {
auto package_reference =
GenPackageReference(field.value.type.VectorType());
field_type = package_reference + "." +
GenTypeGet(field.value.type.VectorType()) + "T]";
import_list->insert("import " + package_reference);
}
field_type = "List[" + field_type;
} else {
field_type =
"List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
}
}
void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
std::set<std::string> *import_list) {
std::string code;
std::set<std::string> import_typing_list;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
// Determines field type, default value, and typing imports.
auto base_type = field.value.type.base_type;
std::string field_type;
switch (base_type) {
case BASE_TYPE_UNION: {
GenUnionInit(field, &field_type, import_list, &import_typing_list);
break;
}
case BASE_TYPE_STRUCT: {
GenStructInit(field, &field_type, import_list, &import_typing_list);
break;
}
case BASE_TYPE_VECTOR:
case BASE_TYPE_ARRAY: {
GenVectorInit(field, &field_type, import_list, &import_typing_list);
break;
}
default:
// Scalar or sting fields.
field_type = GetBasePythonTypeForScalarAndString(base_type);
break;
}
auto default_value = GetDefaultValue(field);
// Wrties the init statement.
auto field_instance_name = MakeLowerCamel(field);
code += GenIndents(2) + "self." + field_instance_name + " = " +
default_value + " # type: " + field_type;
}
// Writes __init__ method.
auto &code_base = *code_ptr;
GenReceiverForObjectAPI(struct_def, code_ptr);
code_base += "__init__(self):";
if (code.empty()) {
code_base += GenIndents(2) + "pass";
} else {
code_base += code;
}
code_base += "\n";
// Merges the typing imports into import_list.
if (!import_typing_list.empty()) {
// Adds the try statement.
std::string typing_imports = "try:";
typing_imports += GenIndents(1) + "from typing import ";
std::string separator_string = ", ";
for (auto it = import_typing_list.begin(); it != import_typing_list.end();
++it) {
const std::string &im = *it;
typing_imports += im + separator_string;
}
// Removes the last separator_string.
typing_imports.erase(typing_imports.length() - separator_string.size());
// Adds the except statement.
typing_imports += "\n";
typing_imports += "except:";
typing_imports += GenIndents(1) + "pass";
import_list->insert(typing_imports);
}
// Removes the import of the struct itself, if applied.
auto package_reference =
struct_def.defined_namespace->GetFullyQualifiedName(
MakeUpperCamel(struct_def));
auto struct_import = "import " + package_reference;
import_list->erase(struct_import);
}
void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
auto instance_name = MakeLowerCamel(struct_def);
auto struct_name = NormalizedName(struct_def);
code += GenIndents(1) + "@classmethod";
code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
code += GenIndents(2) + instance_name + " = " + struct_name + "()";
code += GenIndents(2) + instance_name + ".Init(buf, pos)";
code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
code += "\n";
}
void InitializeFromObjForObject(const StructDef &struct_def,
std::string *code_ptr) {
auto &code = *code_ptr;
auto instance_name = MakeLowerCamel(struct_def);
auto struct_name = NormalizedName(struct_def);
code += GenIndents(1) + "@classmethod";
code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
code += GenIndents(2) + "x = " + struct_name + "T()";
code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
code += GenIndents(2) + "return x";
code += "\n";
}
void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
auto struct_instance_name = MakeLowerCamel(struct_def);
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto field_type = TypeName(field);
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(field.value.type);
field_type = package_reference + "." + TypeName(field);
}
code += GenIndents(2) + "if " + struct_instance_name + "." +
field_accessor_name + "(";
// if field is a struct, we need to create an instance for it first.
if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
code += field_type + "()";
}
code += ") is not None:";
code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
"T.InitFromObj(" + struct_instance_name + "." +
field_accessor_name + "(";
// A struct's accessor requires a struct buf instance.
if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
code += field_type + "()";
}
code += "))";
}
void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_instance_name = MakeLowerCamel(struct_def);
auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
if (parser_.opts.include_dependence_headers) {
Namespace *namespaces = field.value.type.enum_def->defined_namespace;
auto package_reference = namespaces->GetFullyQualifiedName(
MakeUpperCamel(*(field.value.type.enum_def)));
union_name = package_reference + "." + union_name;
}
code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
"Creator(" + "self." + field_instance_name + "Type, " +
struct_instance_name + "." + field_accessor_name + "())";
}
void GenUnPackForStructVector(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_instance_name = MakeLowerCamel(struct_def);
code += GenIndents(2) + "if not " + struct_instance_name + "." +
field_accessor_name + "IsNone():";
code += GenIndents(3) + "self." + field_instance_name + " = []";
code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
field_accessor_name + "Length()):";
auto field_type_name = TypeName(field);
auto one_instance = field_type_name + "_";
one_instance[0] = CharToLower(one_instance[0]);
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(field.value.type);
field_type_name = package_reference + "." + TypeName(field);
}
code += GenIndents(4) + "if " + struct_instance_name + "." +
field_accessor_name + "(i) is None:";
code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
code += GenIndents(4) + "else:";
code += GenIndents(5) + one_instance + " = " + field_type_name +
"T.InitFromObj(" + struct_instance_name + "." +
field_accessor_name + "(i))";
code += GenIndents(5) + "self." + field_instance_name + ".append(" +
one_instance + ")";
}
void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr, int indents) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_instance_name = MakeLowerCamel(struct_def);
code += GenIndents(indents) + "self." + field_instance_name + " = []";
code += GenIndents(indents) + "for i in range(" + struct_instance_name +
"." + field_accessor_name + "Length()):";
code += GenIndents(indents + 1) + "self." + field_instance_name +
".append(" + struct_instance_name + "." + field_accessor_name +
"(i))";
}
void GenUnPackForScalarVector(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_instance_name = MakeLowerCamel(struct_def);
code += GenIndents(2) + "if not " + struct_instance_name + "." +
field_accessor_name + "IsNone():";
// String does not have the AsNumpy method.
if (!(IsScalar(field.value.type.VectorType().base_type))) {
GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
return;
}
code += GenIndents(3) + "if np is None:";
GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
// If numpy exists, use the AsNumpy method to optimize the unpack speed.
code += GenIndents(3) + "else:";
code += GenIndents(4) + "self." + field_instance_name + " = " +
struct_instance_name + "." + field_accessor_name + "AsNumpy()";
}
void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_instance_name = MakeLowerCamel(struct_def);
code += GenIndents(2) + "self." + field_instance_name + " = " +
struct_instance_name + "." + field_accessor_name + "()";
}
// Generates the UnPack method for the object class.
void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
std::string code;
// Items that needs to be imported. No duplicate modules will be imported.
std::set<std::string> import_list;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto field_type = TypeName(field);
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
GenUnPackForStruct(struct_def, field, &code);
break;
}
case BASE_TYPE_UNION: {
GenUnPackForUnion(struct_def, field, &code);
break;
}
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
GenUnPackForStructVector(struct_def, field, &code);
} else {
GenUnPackForScalarVector(struct_def, field, &code);
}
break;
}
case BASE_TYPE_ARRAY: {
GenUnPackForScalarVector(struct_def, field, &code);
break;
}
default:
GenUnPackForScalar(struct_def, field, &code);
}
}
// Writes import statements and code into the generated file.
auto &code_base = *code_ptr;
auto struct_instance_name = MakeLowerCamel(struct_def);
auto struct_name = MakeUpperCamel(struct_def);
GenReceiverForObjectAPI(struct_def, code_ptr);
code_base += "_UnPack(self, " + struct_instance_name + "):";
code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
code_base += GenIndents(3) + "return";
// Write the import statements.
for (std::set<std::string>::iterator it = import_list.begin();
it != import_list.end(); ++it) {
code_base += GenIndents(2) + *it;
}
// Write the code.
code_base += code;
code_base += "\n";
}
void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
auto &code = *code_ptr;
auto struct_name = MakeUpperCamel(struct_def);
GenReceiverForObjectAPI(struct_def, code_ptr);
code += "Pack(self, builder):";
code += GenIndents(2) + "return Create" + struct_name + "(builder";
StructBuilderArgs(struct_def,
/* nameprefix = */ "self.",
/* namesuffix = */ "",
/* has_field_name = */ true,
/* fieldname_suffix = */ ".", code_ptr);
code += ")\n";
}
void GenPackForStructVectorField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_prefix_ptr,
std::string *code_ptr) {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto struct_name = NormalizedName(struct_def);
auto field_accessor_name = MakeUpperCamel(field);
// Creates the field.
code_prefix +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
if (field.value.type.struct_def->fixed) {
code_prefix += GenIndents(3) + struct_name + "Start" +
field_accessor_name + "Vector(builder, len(self." +
field_instance_name + "))";
code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
field_instance_name + "))):";
code_prefix +=
GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
code_prefix +=
GenIndents(3) + field_instance_name + " = builder.EndVector()";
} else {
// If the vector is a struct vector, we need to first build accessor for
// each struct element.
code_prefix += GenIndents(3) + field_instance_name + "list = []";
code_prefix += GenIndents(3);
code_prefix += "for i in range(len(self." + field_instance_name + ")):";
code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
field_instance_name + "[i].Pack(builder))";
code_prefix += GenIndents(3) + struct_name + "Start" +
field_accessor_name + "Vector(builder, len(self." +
field_instance_name + "))";
code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
field_instance_name + "))):";
code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
field_instance_name + "list[i])";
code_prefix +=
GenIndents(3) + field_instance_name + " = builder.EndVector()";
}
// Adds the field into the struct.
code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
"(builder, " + field_instance_name + ")";
}
void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr, int indents) {
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_name = NormalizedName(struct_def);
auto vectortype = field.value.type.VectorType();
code += GenIndents(indents) + struct_name + "Start" + field_accessor_name +
"Vector(builder, len(self." + field_instance_name + "))";
code += GenIndents(indents) + "for i in reversed(range(len(self." +
field_instance_name + "))):";
code += GenIndents(indents + 1) + "builder.Prepend";
std::string type_name;
switch (vectortype.base_type) {
case BASE_TYPE_BOOL:
type_name = "Bool";
break;
case BASE_TYPE_CHAR:
type_name = "Byte";
break;
case BASE_TYPE_UCHAR:
type_name = "Uint8";
break;
case BASE_TYPE_SHORT:
type_name = "Int16";
break;
case BASE_TYPE_USHORT:
type_name = "Uint16";
break;
case BASE_TYPE_INT:
type_name = "Int32";
break;
case BASE_TYPE_UINT:
type_name = "Uint32";
break;
case BASE_TYPE_LONG:
type_name = "Int64";
break;
case BASE_TYPE_ULONG:
type_name = "Uint64";
break;
case BASE_TYPE_FLOAT:
type_name = "Float32";
break;
case BASE_TYPE_DOUBLE:
type_name = "Float64";
break;
case BASE_TYPE_STRING:
type_name = "UOffsetTRelative";
break;
default:
type_name = "VOffsetT";
break;
}
code += type_name;
}
void GenPackForScalarVectorField(const StructDef &struct_def,
const FieldDef &field,
std::string *code_prefix_ptr,
std::string *code_ptr) {
auto &code = *code_ptr;
auto &code_prefix = *code_prefix_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_name = NormalizedName(struct_def);
// Adds the field into the struct.
code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
"(builder, " + field_instance_name + ")";
// Creates the field.
code_prefix +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
// If the vector is a string vector, we need to first build accessor for
// each string element. And this generated code, needs to be
// placed ahead of code_prefix.
auto vectortype = field.value.type.VectorType();
if (IsString(vectortype)) {
code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
code_prefix += GenIndents(3) + "for i in range(len(self." +
field_instance_name + ")):";
code_prefix += GenIndents(4) + MakeLowerCamel(field) +
"list.append(builder.CreateString(self." +
field_instance_name + "[i]))";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
code_prefix +=
GenIndents(3) + field_instance_name + " = builder.EndVector()";
return;
}
code_prefix += GenIndents(3) + "if np is not None and type(self." +
field_instance_name + ") is np.ndarray:";
code_prefix += GenIndents(4) + field_instance_name +
" = builder.CreateNumpyVector(self." + field_instance_name +
")";
code_prefix += GenIndents(3) + "else:";
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
code_prefix += "(self." + field_instance_name + "[i])";
code_prefix +=
GenIndents(4) + field_instance_name + " = builder.EndVector()";
}
void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
std::string *code_prefix_ptr,
std::string *code_ptr) {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_name = NormalizedName(struct_def);
if (field.value.type.struct_def->fixed) {
// Pure struct fields need to be created along with their parent
// structs.
code +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
code += GenIndents(3) + field_instance_name + " = self." +
field_instance_name + ".Pack(builder)";
} else {
// Tables need to be created before their parent structs are created.
code_prefix +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
code_prefix += GenIndents(3) + field_instance_name + " = self." +
field_instance_name + ".Pack(builder)";
code +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
}
code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
"(builder, " + field_instance_name + ")";
}
void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
std::string *code_prefix_ptr,
std::string *code_ptr) {
auto &code_prefix = *code_prefix_ptr;
auto &code = *code_ptr;
auto field_instance_name = MakeLowerCamel(field);
auto field_accessor_name = MakeUpperCamel(field);
auto struct_name = NormalizedName(struct_def);
// TODO(luwa): TypeT should be moved under the None check as well.
code_prefix +=
GenIndents(2) + "if self." + field_instance_name + " is not None:";
code_prefix += GenIndents(3) + field_instance_name + " = self." +
field_instance_name + ".Pack(builder)";
code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
"(builder, " + field_instance_name + ")";
}
void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
auto &code_base = *code_ptr;
std::string code, code_prefix;
auto struct_instance_name = MakeLowerCamel(struct_def);
auto struct_name = NormalizedName(struct_def);
GenReceiverForObjectAPI(struct_def, code_ptr);
code_base += "Pack(self, builder):";
code += GenIndents(2) + struct_name + "Start(builder)";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (field.deprecated) continue;
auto field_accessor_name = MakeUpperCamel(field);
auto field_instance_name = MakeLowerCamel(field);
switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: {
GenPackForStructField(struct_def, field, &code_prefix, &code);
break;
}
case BASE_TYPE_UNION: {
GenPackForUnionField(struct_def, field, &code_prefix, &code);
break;
}
case BASE_TYPE_VECTOR: {
auto vectortype = field.value.type.VectorType();
if (vectortype.base_type == BASE_TYPE_STRUCT) {
GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
} else {
GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
}
break;
}
case BASE_TYPE_ARRAY: {
GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
break;
}
case BASE_TYPE_STRING: {
code_prefix += GenIndents(2) + "if self." + field_instance_name +
" is not None:";
code_prefix += GenIndents(3) + field_instance_name +
" = builder.CreateString(self." + field_instance_name +
")";
code += GenIndents(2) + "if self." + field_instance_name +
" is not None:";
code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
"(builder, " + field_instance_name + ")";
break;
}
default:
// Generates code for scalar values. If the value equals to the
// default value, builder will automatically ignore it. So we don't
// need to check the value ahead.
code += GenIndents(2) + struct_name + "Add" + field_accessor_name +
"(builder, self." + field_instance_name + ")";
break;
}
}
code += GenIndents(2) + struct_instance_name + " = " + struct_name +
"End(builder)";
code += GenIndents(2) + "return " + struct_instance_name;
code_base += code_prefix + code;
code_base += "\n";
}
void GenStructForObjectAPI(const StructDef &struct_def,
std::string *code_ptr) {
if (struct_def.generated) return;
std::set<std::string> import_list;
std::string code;
// Creates an object class for a struct or a table
BeginClassForObjectAPI(struct_def, &code);
GenInitialize(struct_def, &code, &import_list);
InitializeFromBuf(struct_def, &code);
InitializeFromObjForObject(struct_def, &code);
GenUnPack(struct_def, &code);
if (struct_def.fixed) {
GenPackForStruct(struct_def, &code);
} else {
GenPackForTable(struct_def, &code);
}
// Adds the imports at top.
auto &code_base = *code_ptr;
code_base += "\n";
for (auto it = import_list.begin(); it != import_list.end(); it++) {
auto im = *it;
code_base += im + "\n";
}
code_base += code;
}
void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
std::string *code_ptr) {
auto &code = *code_ptr;
auto union_name = NormalizedName(enum_def);
auto field_name = NormalizedName(ev);
auto field_type = GenTypeGet(ev.union_type) + "T";
code += GenIndents(1) + "if unionType == " + union_name + "()." +
field_name + ":";
if (parser_.opts.include_dependence_headers) {
auto package_reference = GenPackageReference(ev.union_type);
code += GenIndents(2) + "import " + package_reference;
field_type = package_reference + "." + field_type;
}
code += GenIndents(2) + "return " + field_type +
".InitFromBuf(table.Bytes, table.Pos)";
}
void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
std::string *code_ptr) {
auto &code = *code_ptr;
auto union_name = NormalizedName(enum_def);
auto field_name = NormalizedName(ev);
code += GenIndents(1) + "if unionType == " + union_name + "()." +
field_name + ":";
code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
code += GenIndents(2) + "union = tab.String(table.Pos)";
code += GenIndents(2) + "return union";
}
// Creates an union object based on union type.
void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
auto &code = *code_ptr;
auto union_name = MakeUpperCamel(enum_def);
code += "\n";
code += "def " + union_name + "Creator(unionType, table):";
code += GenIndents(1) + "from flatbuffers.table import Table";
code += GenIndents(1) + "if not isinstance(table, Table):";
code += GenIndents(2) + "return None";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
// Union only supports string and table.
switch (ev.union_type.base_type) {
case BASE_TYPE_STRUCT:
GenUnionCreatorForStruct(enum_def, ev, &code);
break;
case BASE_TYPE_STRING:
GenUnionCreatorForString(enum_def, ev, &code);
break;
default:
break;
}
}
code += GenIndents(1) + "return None";
code += "\n";
}
// Generate enum declarations.
void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
if (enum_def.generated) return;
GenComment(enum_def.doc_comment, code_ptr, &def_comment);
BeginEnum(NormalizedName(enum_def), code_ptr);
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
auto &ev = **it;
GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
EnumMember(enum_def, ev, code_ptr);
}
EndEnum(code_ptr);
}
// Returns the function name that is able to read a value of the given type.
std::string GenGetter(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "self._tab.String(";
case BASE_TYPE_UNION:
return "self._tab.Union(";
case BASE_TYPE_VECTOR:
return GenGetter(type.VectorType());
default:
return "self._tab.Get(flatbuffers.number_types." +
MakeCamel(GenTypeGet(type)) + "Flags, ";
}
}
// Returns the method name for use with add/put calls.
std::string GenMethod(const FieldDef &field) {
return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
? MakeCamel(GenTypeBasic(field.value.type))
: (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
}
std::string GenTypeBasic(const Type &type) {
// clang-format off
static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
#PTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD
};
// clang-format on
return ctypename[IsArray(type) ? type.VectorType().base_type
: type.base_type];
}
std::string GenTypePointer(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "string";
case BASE_TYPE_VECTOR:
return GenTypeGet(type.VectorType());
case BASE_TYPE_STRUCT:
return type.struct_def->name;
case BASE_TYPE_UNION:
// fall through
default:
return "*flatbuffers.Table";
}
}
std::string GenTypeGet(const Type &type) {
return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
}
std::string TypeName(const FieldDef &field) {
return GenTypeGet(field.value.type);
}
// Create a struct with a builder and the struct's arguments.
void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
BeginBuilderArgs(struct_def, code_ptr);
StructBuilderArgs(struct_def,
/* nameprefix = */ "",
/* namesuffix = */ "",
/* has_field_name = */ true,
/* fieldname_suffix = */ "_", code_ptr);
EndBuilderArgs(code_ptr);
StructBuilderBody(struct_def, "", code_ptr);
EndBuilderBody(code_ptr);
}
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 (parser_.opts.generate_object_based_api & enum_def.is_union) {
GenUnionCreator(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 (parser_.opts.generate_object_based_api) {
GenStructForObjectAPI(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) {
auto &code = *code_ptr;
code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
code += "# namespace: " + name_space_name + "\n\n";
if (needs_imports) {
code += "import flatbuffers\n";
code += "from flatbuffers.compat import import_numpy\n";
code += "np = import_numpy()\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 = def.defined_namespace->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) + NormalizedName(def) + ".py";
return SaveFile(filename.c_str(), code, false);
}
private:
std::unordered_set<std::string> keywords_;
const SimpleFloatConstantGenerator float_const_gen_;
};
} // namespace python
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