[C#] Fix nested structs and arrays in Object API (#5765)

* [C#] Fix nested structs and arrays in Object API

The adds support for nested structs and fixed size arrays in the C#
Object API codegen which previously generated invalid code that wouldn't
compile.

- Nested structs would originally generate syntax errors due to adding an
  additional `.` to separate fields.
- Fixed size arrays of nested structs would originally generate code for
  the first field in the top most struct, and would lead to a compiler
  error due to referencing undefined variables.

* [C#] fix nested structs and arrays of structs.

* fix nested structs + arrays

* add table support

* Cleanup code

Co-authored-by: mugisoba <mugisoba+github@icloud.com>
This commit is contained in:
Anass Al
2020-04-06 09:27:13 -07:00
committed by GitHub
parent 408f11fbdd
commit fb96fadc20
2 changed files with 96 additions and 78 deletions

View File

@@ -38,6 +38,11 @@ static CommentConfig comment_config = {
namespace csharp { namespace csharp {
class CSharpGenerator : public BaseGenerator { class CSharpGenerator : public BaseGenerator {
struct FieldArrayLength {
std::string name;
int length;
};
public: public:
CSharpGenerator(const Parser &parser, const std::string &path, CSharpGenerator(const Parser &parser, const std::string &path,
const std::string &file_name) const std::string &file_name)
@@ -1540,6 +1545,15 @@ class CSharpGenerator : public BaseGenerator {
GenOffsetType(*field.value.type.struct_def) + GenOffsetType(*field.value.type.struct_def) +
") : " + GenTypeGet(field.value.type) + ") : " + GenTypeGet(field.value.type) +
".Pack(builder, _o." + camel_name + ");\n"; ".Pack(builder, _o." + camel_name + ");\n";
} else if (struct_def.fixed && struct_has_create) {
std::vector<FieldArrayLength> array_lengths;
FieldArrayLength tmp_array_length = {
field.name,
field.value.type.fixed_length,
};
array_lengths.push_back(tmp_array_length);
GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
array_lengths);
} }
break; break;
} }
@@ -1620,12 +1634,14 @@ class CSharpGenerator : public BaseGenerator {
} }
case BASE_TYPE_ARRAY: { case BASE_TYPE_ARRAY: {
if (field.value.type.struct_def != nullptr) { if (field.value.type.struct_def != nullptr) {
std::vector<std::string> name_vec; std::vector<FieldArrayLength> array_lengths;
name_vec.push_back(field.name); FieldArrayLength tmp_array_length = {
std::vector<int> array_length_vec; field.name,
array_length_vec.push_back(field.value.type.fixed_length); field.value.type.fixed_length,
GenArrayPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr, };
name_vec, array_length_vec); array_lengths.push_back(tmp_array_length);
GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr,
array_lengths);
} else { } else {
code += " var _" + field.name + " = _o." + camel_name + ";\n"; code += " var _" + field.name + " = _o." + camel_name + ";\n";
} }
@@ -1656,8 +1672,9 @@ class CSharpGenerator : public BaseGenerator {
switch (field.value.type.base_type) { switch (field.value.type.base_type) {
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (struct_def.fixed) { if (struct_def.fixed) {
GenStructArgs_ObjectAPI(*field.value.type.struct_def, code_ptr, GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
" _o." + camel_name + "."); code_ptr,
" _" + field.name + "_");
} else { } else {
code += ",\n"; code += ",\n";
if (field.value.type.struct_def->fixed) { if (field.value.type.struct_def->fixed) {
@@ -1674,8 +1691,9 @@ class CSharpGenerator : public BaseGenerator {
} }
case BASE_TYPE_ARRAY: { case BASE_TYPE_ARRAY: {
if (field.value.type.struct_def != nullptr) { if (field.value.type.struct_def != nullptr) {
GenArrayPackCall_ObjectAPI(*field.value.type.struct_def, code_ptr, GenStructPackCall_ObjectAPI(*field.value.type.struct_def,
" _" + field.name + "_"); code_ptr,
" _" + field.name + "_");
} else { } else {
code += ",\n"; code += ",\n";
code += " _" + field.name; code += " _" + field.name;
@@ -1745,28 +1763,9 @@ class CSharpGenerator : public BaseGenerator {
code += " }\n"; code += " }\n";
} }
void GenStructArgs_ObjectAPI(const StructDef &struct_def, void GenStructPackDecl_ObjectAPI(
std::string *code_ptr, const StructDef &struct_def, std::string *code_ptr,
std::string prefix) const { std::vector<FieldArrayLength> &array_lengths) const {
auto &code = *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;
if (IsStruct(field_type)) {
GenStructArgs_ObjectAPI(*field_type.struct_def, code_ptr,
prefix + "." + MakeCamel(field.name) + ".");
} else {
code += ",\n";
code += prefix + MakeCamel(field.name);
}
}
}
void GenArrayPackDecl_ObjectAPI(const StructDef &struct_def,
std::string *code_ptr,
std::vector<std::string> name_vec,
std::vector<int> array_length_vec) const {
auto &code = *code_ptr; auto &code = *code_ptr;
for (auto it = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) { it != struct_def.fields.vec.end(); ++it) {
@@ -1774,64 +1773,81 @@ class CSharpGenerator : public BaseGenerator {
auto is_array = IsArray(field.value.type); auto is_array = IsArray(field.value.type);
const auto &field_type = const auto &field_type =
is_array ? field.value.type.VectorType() : field.value.type; is_array ? field.value.type.VectorType() : field.value.type;
if (!IsStruct(field_type)) { FieldArrayLength tmp_array_length = {
auto tmp_name_vec = name_vec; field.name,
tmp_name_vec.push_back(field.name); field_type.fixed_length,
auto tmp_array_length_vec = array_length_vec; };
if (is_array) { array_lengths.push_back(tmp_array_length);
tmp_array_length_vec.push_back(field_type.fixed_length); if (field_type.struct_def != nullptr) {
GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr,
array_lengths);
} else {
std::vector<FieldArrayLength> array_only_lengths;
for (size_t i = 0; i < array_lengths.size(); ++i) {
if (array_lengths[i].length > 0) {
array_only_lengths.push_back(array_lengths[i]);
}
} }
std::string name; std::string name;
for (size_t tmp_name_index = 0; tmp_name_index < tmp_name_vec.size(); for (size_t i = 0; i < array_lengths.size(); ++i) {
++tmp_name_index) { name += "_" + array_lengths[i].name;
name += "_" + tmp_name_vec[tmp_name_index];
} }
code += " var " + name + " = new " + GenTypeBasic(field_type) + "["; code += " var " + name + " = ";
code += NumToString(tmp_array_length_vec[0]); if (array_only_lengths.size() > 0) {
for (size_t i = 1; i < tmp_array_length_vec.size(); ++i) { code += "new " + GenTypeBasic(field_type) + "[";
auto array_length = tmp_array_length_vec[i]; for (size_t i = 0; i < array_only_lengths.size(); ++i) {
code += "," + NumToString(array_length); if (i != 0) { code += ","; }
} code += NumToString(array_only_lengths[i].length);
code += "];\n"; }
code += " "; code += "];\n";
// initialize array code += " ";
for (size_t i = 0; i < tmp_array_length_vec.size(); ++i) { // initialize array
auto array_length = tmp_array_length_vec[i]; for (size_t i = 0; i < array_only_lengths.size(); ++i) {
auto idx = "idx" + NumToString(i); auto idx = "idx" + NumToString(i);
code += "for (var " + idx + " = 0; " + idx + " < " + code += "for (var " + idx + " = 0; " + idx + " < " +
NumToString(array_length) + "; ++" + idx + ") {"; NumToString(array_only_lengths[i].length) + "; ++" + idx +
} ") {";
code += name + "[idx0"; }
for (size_t i = 1; i < tmp_array_length_vec.size(); ++i) { for (size_t i = 0; i < array_only_lengths.size(); ++i) {
auto idx = "idx" + NumToString(i); auto idx = "idx" + NumToString(i);
code += "," + idx; if (i == 0) {
} code += name + "[" + idx;
code += "] = _o"; } else {
for (size_t i = 0; i < tmp_array_length_vec.size(); ++i) { code += "," + idx;
auto idx = "idx" + NumToString(i); }
code += "." + MakeCamel(tmp_name_vec[i]) + "[" + idx + "]"; }
} code += "] = _o";
if (!is_array) { code += "." + MakeCamel(field.name); } for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
code += ";"; code += "." + MakeCamel(array_lengths[i].name);
for (size_t i = 0; i < tmp_array_length_vec.size(); ++i) { if (array_lengths[i].length <= 0) continue;
code += "}"; code += "[idx" + NumToString(j++) + "]";
}
code += ";";
for (size_t i = 0; i < array_only_lengths.size(); ++i) { code += "}"; }
} else {
code += "_o";
for (size_t i = 0; i < array_lengths.size(); ++i) {
code += "." + MakeCamel(array_lengths[i].name);
}
code += ";";
} }
code += "\n"; code += "\n";
} }
array_lengths.pop_back();
} }
} }
void GenArrayPackCall_ObjectAPI(const StructDef &struct_def, void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
std::string *code_ptr, std::string *code_ptr,
std::string prefix) const { std::string prefix) const {
auto &code = *code_ptr; auto &code = *code_ptr;
for (auto it = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) { it != struct_def.fields.vec.end(); ++it) {
auto &field = **it; auto &field = **it;
const auto &field_type = field.value.type; const auto &field_type = field.value.type;
if (IsStruct(field_type)) { if (field_type.struct_def != nullptr) {
GenArrayPackCall_ObjectAPI(*field_type.struct_def, code_ptr, GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr,
prefix + field.name + "_"); prefix + field.name + "_");
} else { } else {
code += ",\n"; code += ",\n";
code += prefix + field.name; code += prefix + field.name;

View File

@@ -59,6 +59,8 @@ public struct Vec3 : IFlatbufferObject
} }
public static Offset<MyGame.Example.Vec3> Pack(FlatBufferBuilder builder, Vec3T _o) { public static Offset<MyGame.Example.Vec3> Pack(FlatBufferBuilder builder, Vec3T _o) {
if (_o == null) return default(Offset<MyGame.Example.Vec3>); if (_o == null) return default(Offset<MyGame.Example.Vec3>);
var _test3_a = _o.Test3.A;
var _test3_b = _o.Test3.B;
return CreateVec3( return CreateVec3(
builder, builder,
_o.X, _o.X,
@@ -66,8 +68,8 @@ public struct Vec3 : IFlatbufferObject
_o.Z, _o.Z,
_o.Test1, _o.Test1,
_o.Test2, _o.Test2,
_o.Test3.A, _test3_a,
_o.Test3.B); _test3_b);
} }
}; };