xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_lobster.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2018 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker  *
4*890232f2SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker  *
8*890232f2SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker  *
10*890232f2SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker  * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker  */
16*890232f2SAndroid Build Coastguard Worker 
17*890232f2SAndroid Build Coastguard Worker #include <string>
18*890232f2SAndroid Build Coastguard Worker #include <unordered_set>
19*890232f2SAndroid Build Coastguard Worker 
20*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/code_generators.h"
21*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
22*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
23*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/util.h"
24*890232f2SAndroid Build Coastguard Worker 
25*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
26*890232f2SAndroid Build Coastguard Worker namespace lobster {
27*890232f2SAndroid Build Coastguard Worker 
28*890232f2SAndroid Build Coastguard Worker class LobsterGenerator : public BaseGenerator {
29*890232f2SAndroid Build Coastguard Worker  public:
LobsterGenerator(const Parser & parser,const std::string & path,const std::string & file_name)30*890232f2SAndroid Build Coastguard Worker   LobsterGenerator(const Parser &parser, const std::string &path,
31*890232f2SAndroid Build Coastguard Worker                    const std::string &file_name)
32*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, file_name, "" /* not used */, "_",
33*890232f2SAndroid Build Coastguard Worker                       "lobster") {
34*890232f2SAndroid Build Coastguard Worker     static const char *const keywords[] = {
35*890232f2SAndroid Build Coastguard Worker       "nil",    "true",    "false",     "return",  "struct",    "class",
36*890232f2SAndroid Build Coastguard Worker       "import", "int",     "float",     "string",  "any",       "def",
37*890232f2SAndroid Build Coastguard Worker       "is",     "from",    "program",   "private", "coroutine", "resource",
38*890232f2SAndroid Build Coastguard Worker       "enum",   "typeof",  "var",       "let",     "pakfile",   "switch",
39*890232f2SAndroid Build Coastguard Worker       "case",   "default", "namespace", "not",     "and",       "or",
40*890232f2SAndroid Build Coastguard Worker       "bool",
41*890232f2SAndroid Build Coastguard Worker     };
42*890232f2SAndroid Build Coastguard Worker     keywords_.insert(std::begin(keywords), std::end(keywords));
43*890232f2SAndroid Build Coastguard Worker   }
44*890232f2SAndroid Build Coastguard Worker 
EscapeKeyword(const std::string & name) const45*890232f2SAndroid Build Coastguard Worker   std::string EscapeKeyword(const std::string &name) const {
46*890232f2SAndroid Build Coastguard Worker     return keywords_.find(name) == keywords_.end() ? name : name + "_";
47*890232f2SAndroid Build Coastguard Worker   }
48*890232f2SAndroid Build Coastguard Worker 
NormalizedName(const Definition & definition) const49*890232f2SAndroid Build Coastguard Worker   std::string NormalizedName(const Definition &definition) const {
50*890232f2SAndroid Build Coastguard Worker     return EscapeKeyword(definition.name);
51*890232f2SAndroid Build Coastguard Worker   }
52*890232f2SAndroid Build Coastguard Worker 
NormalizedName(const EnumVal & ev) const53*890232f2SAndroid Build Coastguard Worker   std::string NormalizedName(const EnumVal &ev) const {
54*890232f2SAndroid Build Coastguard Worker     return EscapeKeyword(ev.name);
55*890232f2SAndroid Build Coastguard Worker   }
56*890232f2SAndroid Build Coastguard Worker 
NamespacedName(const Definition & def)57*890232f2SAndroid Build Coastguard Worker   std::string NamespacedName(const Definition &def) {
58*890232f2SAndroid Build Coastguard Worker     return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
59*890232f2SAndroid Build Coastguard Worker   }
60*890232f2SAndroid Build Coastguard Worker 
GenTypeName(const Type & type)61*890232f2SAndroid Build Coastguard Worker   std::string GenTypeName(const Type &type) {
62*890232f2SAndroid Build Coastguard Worker     auto bits = NumToString(SizeOf(type.base_type) * 8);
63*890232f2SAndroid Build Coastguard Worker     if (IsInteger(type.base_type)) {
64*890232f2SAndroid Build Coastguard Worker       if (IsUnsigned(type.base_type)) return "uint" + bits;
65*890232f2SAndroid Build Coastguard Worker       else return "int" + bits;
66*890232f2SAndroid Build Coastguard Worker     }
67*890232f2SAndroid Build Coastguard Worker     if (IsFloat(type.base_type)) return "float" + bits;
68*890232f2SAndroid Build Coastguard Worker     if (IsString(type)) return "string";
69*890232f2SAndroid Build Coastguard Worker     if (type.base_type == BASE_TYPE_STRUCT) return "table";
70*890232f2SAndroid Build Coastguard Worker     return "none";
71*890232f2SAndroid Build Coastguard Worker   }
72*890232f2SAndroid Build Coastguard Worker 
LobsterType(const Type & type)73*890232f2SAndroid Build Coastguard Worker   std::string LobsterType(const Type &type) {
74*890232f2SAndroid Build Coastguard Worker     if (IsFloat(type.base_type)) return "float";
75*890232f2SAndroid Build Coastguard Worker     if (IsBool(type.base_type)) return "bool";
76*890232f2SAndroid Build Coastguard Worker     if (IsScalar(type.base_type) && type.enum_def)
77*890232f2SAndroid Build Coastguard Worker       return NormalizedName(*type.enum_def);
78*890232f2SAndroid Build Coastguard Worker     if (!IsScalar(type.base_type)) return "flatbuffers_offset";
79*890232f2SAndroid Build Coastguard Worker     if (IsString(type)) return "string";
80*890232f2SAndroid Build Coastguard Worker     return "int";
81*890232f2SAndroid Build Coastguard Worker   }
82*890232f2SAndroid Build Coastguard Worker 
83*890232f2SAndroid Build Coastguard Worker   // Returns the method name for use with add/put calls.
GenMethod(const Type & type)84*890232f2SAndroid Build Coastguard Worker   std::string GenMethod(const Type &type) {
85*890232f2SAndroid Build Coastguard Worker     return IsScalar(type.base_type)
86*890232f2SAndroid Build Coastguard Worker                ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
87*890232f2SAndroid Build Coastguard Worker                : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
88*890232f2SAndroid Build Coastguard Worker   }
89*890232f2SAndroid Build Coastguard Worker 
90*890232f2SAndroid Build Coastguard Worker   // This uses Python names for now..
GenTypeBasic(const Type & type)91*890232f2SAndroid Build Coastguard Worker   std::string GenTypeBasic(const Type &type) {
92*890232f2SAndroid Build Coastguard Worker     // clang-format off
93*890232f2SAndroid Build Coastguard Worker     static const char *ctypename[] = {
94*890232f2SAndroid Build Coastguard Worker       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
95*890232f2SAndroid Build Coastguard Worker               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
96*890232f2SAndroid Build Coastguard Worker         #PTYPE,
97*890232f2SAndroid Build Coastguard Worker         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
98*890232f2SAndroid Build Coastguard Worker       #undef FLATBUFFERS_TD
99*890232f2SAndroid Build Coastguard Worker     };
100*890232f2SAndroid Build Coastguard Worker     // clang-format on
101*890232f2SAndroid Build Coastguard Worker     return ctypename[type.base_type];
102*890232f2SAndroid Build Coastguard Worker   }
103*890232f2SAndroid Build Coastguard Worker 
104*890232f2SAndroid Build Coastguard Worker   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)105*890232f2SAndroid Build Coastguard Worker   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
106*890232f2SAndroid Build Coastguard Worker                          std::string *code_ptr) {
107*890232f2SAndroid Build Coastguard Worker     GenComment(field.doc_comment, code_ptr, nullptr, "    ");
108*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
109*890232f2SAndroid Build Coastguard Worker     auto offsets = NumToString(field.value.offset);
110*890232f2SAndroid Build Coastguard Worker     auto def = "    def " + NormalizedName(field);
111*890232f2SAndroid Build Coastguard Worker     if (IsScalar(field.value.type.base_type)) {
112*890232f2SAndroid Build Coastguard Worker       std::string acc;
113*890232f2SAndroid Build Coastguard Worker       if (struct_def.fixed) {
114*890232f2SAndroid Build Coastguard Worker         acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
115*890232f2SAndroid Build Coastguard Worker               offsets + ")";
116*890232f2SAndroid Build Coastguard Worker 
117*890232f2SAndroid Build Coastguard Worker       } else {
118*890232f2SAndroid Build Coastguard Worker         auto defval = field.IsOptional() ? "0" : field.value.constant;
119*890232f2SAndroid Build Coastguard Worker         acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
120*890232f2SAndroid Build Coastguard Worker               "(pos_, " + offsets + ", " + defval + ")";
121*890232f2SAndroid Build Coastguard Worker         if (IsBool(field.value.type.base_type))
122*890232f2SAndroid Build Coastguard Worker           acc = "bool(" + acc + ")";
123*890232f2SAndroid Build Coastguard Worker       }
124*890232f2SAndroid Build Coastguard Worker       if (field.value.type.enum_def)
125*890232f2SAndroid Build Coastguard Worker         acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
126*890232f2SAndroid Build Coastguard Worker       if (field.IsOptional()) {
127*890232f2SAndroid Build Coastguard Worker         acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
128*890232f2SAndroid Build Coastguard Worker         code += def + "() -> " + LobsterType(field.value.type) + ", bool:\n        return " + acc + "\n";
129*890232f2SAndroid Build Coastguard Worker       } else {
130*890232f2SAndroid Build Coastguard Worker         code += def + "() -> " + LobsterType(field.value.type) + ":\n        return " + acc + "\n";
131*890232f2SAndroid Build Coastguard Worker       }
132*890232f2SAndroid Build Coastguard Worker       return;
133*890232f2SAndroid Build Coastguard Worker     }
134*890232f2SAndroid Build Coastguard Worker     switch (field.value.type.base_type) {
135*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: {
136*890232f2SAndroid Build Coastguard Worker         auto name = NamespacedName(*field.value.type.struct_def);
137*890232f2SAndroid Build Coastguard Worker         if (struct_def.fixed) {
138*890232f2SAndroid Build Coastguard Worker           code += def + "() -> " + name + ":\n        ";
139*890232f2SAndroid Build Coastguard Worker           code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
140*890232f2SAndroid Build Coastguard Worker         } else {
141*890232f2SAndroid Build Coastguard Worker           code += def + "() -> " + name + "?:\n        ";
142*890232f2SAndroid Build Coastguard Worker           code += std::string("let o = buf_.flatbuffers_field_") +
143*890232f2SAndroid Build Coastguard Worker                   (field.value.type.struct_def->fixed ? "struct" : "table") +
144*890232f2SAndroid Build Coastguard Worker                   "(pos_, " + offsets + ")\n        return if o: " + name +
145*890232f2SAndroid Build Coastguard Worker                   " { buf_, o } else: nil\n";
146*890232f2SAndroid Build Coastguard Worker         }
147*890232f2SAndroid Build Coastguard Worker         break;
148*890232f2SAndroid Build Coastguard Worker       }
149*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING:
150*890232f2SAndroid Build Coastguard Worker         code += def +
151*890232f2SAndroid Build Coastguard Worker                 "() -> string:\n        return buf_.flatbuffers_field_string(pos_, " +
152*890232f2SAndroid Build Coastguard Worker                 offsets + ")\n";
153*890232f2SAndroid Build Coastguard Worker         break;
154*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: {
155*890232f2SAndroid Build Coastguard Worker         auto vectortype = field.value.type.VectorType();
156*890232f2SAndroid Build Coastguard Worker         if (vectortype.base_type == BASE_TYPE_STRUCT) {
157*890232f2SAndroid Build Coastguard Worker           auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
158*890232f2SAndroid Build Coastguard Worker                        ") + i * " + NumToString(InlineSize(vectortype));
159*890232f2SAndroid Build Coastguard Worker           if (!(vectortype.struct_def->fixed)) {
160*890232f2SAndroid Build Coastguard Worker             start = "buf_.flatbuffers_indirect(" + start + ")";
161*890232f2SAndroid Build Coastguard Worker           }
162*890232f2SAndroid Build Coastguard Worker           code += def + "(i:int) -> " + NamespacedName(*field.value.type.struct_def) + ":\n        return ";
163*890232f2SAndroid Build Coastguard Worker           code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
164*890232f2SAndroid Build Coastguard Worker                   start + " }\n";
165*890232f2SAndroid Build Coastguard Worker         } else {
166*890232f2SAndroid Build Coastguard Worker           if (IsString(vectortype)) {
167*890232f2SAndroid Build Coastguard Worker             code += def + "(i:int) -> string:\n        return ";
168*890232f2SAndroid Build Coastguard Worker             code += "buf_.flatbuffers_string";
169*890232f2SAndroid Build Coastguard Worker           } else {
170*890232f2SAndroid Build Coastguard Worker             code += def + "(i:int) -> " + LobsterType(vectortype) + ":\n        return ";
171*890232f2SAndroid Build Coastguard Worker             code += "buf_.read_" + GenTypeName(vectortype) + "_le";
172*890232f2SAndroid Build Coastguard Worker           }
173*890232f2SAndroid Build Coastguard Worker           code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
174*890232f2SAndroid Build Coastguard Worker                   ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
175*890232f2SAndroid Build Coastguard Worker         }
176*890232f2SAndroid Build Coastguard Worker         break;
177*890232f2SAndroid Build Coastguard Worker       }
178*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION: {
179*890232f2SAndroid Build Coastguard Worker         for (auto it = field.value.type.enum_def->Vals().begin();
180*890232f2SAndroid Build Coastguard Worker              it != field.value.type.enum_def->Vals().end(); ++it) {
181*890232f2SAndroid Build Coastguard Worker           auto &ev = **it;
182*890232f2SAndroid Build Coastguard Worker           if (ev.IsNonZero()) {
183*890232f2SAndroid Build Coastguard Worker             code += def + "_as_" + ev.name + "():\n        return " +
184*890232f2SAndroid Build Coastguard Worker                     NamespacedName(*ev.union_type.struct_def) +
185*890232f2SAndroid Build Coastguard Worker                     " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
186*890232f2SAndroid Build Coastguard Worker                     ") }\n";
187*890232f2SAndroid Build Coastguard Worker           }
188*890232f2SAndroid Build Coastguard Worker         }
189*890232f2SAndroid Build Coastguard Worker         break;
190*890232f2SAndroid Build Coastguard Worker       }
191*890232f2SAndroid Build Coastguard Worker       default: FLATBUFFERS_ASSERT(0);
192*890232f2SAndroid Build Coastguard Worker     }
193*890232f2SAndroid Build Coastguard Worker     if (IsVector(field.value.type)) {
194*890232f2SAndroid Build Coastguard Worker       code += def +
195*890232f2SAndroid Build Coastguard Worker               "_length() -> int:\n        return "
196*890232f2SAndroid Build Coastguard Worker               "buf_.flatbuffers_field_vector_len(pos_, " +
197*890232f2SAndroid Build Coastguard Worker               offsets + ")\n";
198*890232f2SAndroid Build Coastguard Worker     }
199*890232f2SAndroid Build Coastguard Worker   }
200*890232f2SAndroid Build Coastguard Worker 
201*890232f2SAndroid Build Coastguard Worker   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)202*890232f2SAndroid Build Coastguard Worker   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
203*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
204*890232f2SAndroid Build Coastguard Worker     code += "struct " + NormalizedName(struct_def) +
205*890232f2SAndroid Build Coastguard Worker             "Builder:\n    b_:flatbuffers_builder\n";
206*890232f2SAndroid Build Coastguard Worker     code += "    def start():\n        b_.StartObject(" +
207*890232f2SAndroid Build Coastguard Worker             NumToString(struct_def.fields.vec.size()) +
208*890232f2SAndroid Build Coastguard Worker             ")\n        return this\n";
209*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
210*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
211*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
212*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
213*890232f2SAndroid Build Coastguard Worker       auto offset = it - struct_def.fields.vec.begin();
214*890232f2SAndroid Build Coastguard Worker       code += "    def add_" + NormalizedName(field) + "(" +
215*890232f2SAndroid Build Coastguard Worker               NormalizedName(field) + ":" + LobsterType(field.value.type) +
216*890232f2SAndroid Build Coastguard Worker               "):\n        b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
217*890232f2SAndroid Build Coastguard Worker               NumToString(offset) + ", " + NormalizedName(field);
218*890232f2SAndroid Build Coastguard Worker       if (IsScalar(field.value.type.base_type) && !field.IsOptional())
219*890232f2SAndroid Build Coastguard Worker         code += ", " + field.value.constant;
220*890232f2SAndroid Build Coastguard Worker       code += ")\n        return this\n";
221*890232f2SAndroid Build Coastguard Worker     }
222*890232f2SAndroid Build Coastguard Worker     code += "    def end():\n        return b_.EndObject()\n\n";
223*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
224*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
225*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
226*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
227*890232f2SAndroid Build Coastguard Worker       if (IsVector(field.value.type)) {
228*890232f2SAndroid Build Coastguard Worker         code += "def " + NormalizedName(struct_def) + "Start" +
229*890232f2SAndroid Build Coastguard Worker                 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
230*890232f2SAndroid Build Coastguard Worker                 "Vector(b_:flatbuffers_builder, n_:int):\n    b_.StartVector(";
231*890232f2SAndroid Build Coastguard Worker         auto vector_type = field.value.type.VectorType();
232*890232f2SAndroid Build Coastguard Worker         auto alignment = InlineAlignment(vector_type);
233*890232f2SAndroid Build Coastguard Worker         auto elem_size = InlineSize(vector_type);
234*890232f2SAndroid Build Coastguard Worker         code +=
235*890232f2SAndroid Build Coastguard Worker             NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
236*890232f2SAndroid Build Coastguard Worker         if (vector_type.base_type != BASE_TYPE_STRUCT ||
237*890232f2SAndroid Build Coastguard Worker             !vector_type.struct_def->fixed) {
238*890232f2SAndroid Build Coastguard Worker           code += "def " + NormalizedName(struct_def) + "Create" +
239*890232f2SAndroid Build Coastguard Worker                   ConvertCase(NormalizedName(field), Case::kUpperCamel) +
240*890232f2SAndroid Build Coastguard Worker                   "Vector(b_:flatbuffers_builder, v_:[" +
241*890232f2SAndroid Build Coastguard Worker                   LobsterType(vector_type) + "]):\n    b_.StartVector(" +
242*890232f2SAndroid Build Coastguard Worker                   NumToString(elem_size) + ", v_.length, " +
243*890232f2SAndroid Build Coastguard Worker                   NumToString(alignment) + ")\n    reverse(v_) e_: b_.Prepend" +
244*890232f2SAndroid Build Coastguard Worker                   GenMethod(vector_type) +
245*890232f2SAndroid Build Coastguard Worker                   "(e_)\n    return b_.EndVector(v_.length)\n";
246*890232f2SAndroid Build Coastguard Worker         }
247*890232f2SAndroid Build Coastguard Worker         code += "\n";
248*890232f2SAndroid Build Coastguard Worker       }
249*890232f2SAndroid Build Coastguard Worker     }
250*890232f2SAndroid Build Coastguard Worker   }
251*890232f2SAndroid Build Coastguard Worker 
GenStructPreDecl(const StructDef & struct_def,std::string * code_ptr)252*890232f2SAndroid Build Coastguard Worker   void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
253*890232f2SAndroid Build Coastguard Worker     if (struct_def.generated) return;
254*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
255*890232f2SAndroid Build Coastguard Worker     CheckNameSpace(struct_def, &code);
256*890232f2SAndroid Build Coastguard Worker     code += "class " + NormalizedName(struct_def) + "\n\n";
257*890232f2SAndroid Build Coastguard Worker   }
258*890232f2SAndroid Build Coastguard Worker 
259*890232f2SAndroid Build Coastguard Worker   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)260*890232f2SAndroid Build Coastguard Worker   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
261*890232f2SAndroid Build Coastguard Worker     if (struct_def.generated) return;
262*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
263*890232f2SAndroid Build Coastguard Worker     CheckNameSpace(struct_def, &code);
264*890232f2SAndroid Build Coastguard Worker     GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
265*890232f2SAndroid Build Coastguard Worker     code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
266*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
267*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
268*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
269*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
270*890232f2SAndroid Build Coastguard Worker       GenStructAccessor(struct_def, field, code_ptr);
271*890232f2SAndroid Build Coastguard Worker     }
272*890232f2SAndroid Build Coastguard Worker     code += "\n";
273*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed) {
274*890232f2SAndroid Build Coastguard Worker       // Generate a special accessor for the table that has been declared as
275*890232f2SAndroid Build Coastguard Worker       // the root type.
276*890232f2SAndroid Build Coastguard Worker       code += "def GetRootAs" + NormalizedName(struct_def) +
277*890232f2SAndroid Build Coastguard Worker               "(buf:string): return " + NormalizedName(struct_def) +
278*890232f2SAndroid Build Coastguard Worker               " { buf, buf.flatbuffers_indirect(0) }\n\n";
279*890232f2SAndroid Build Coastguard Worker     }
280*890232f2SAndroid Build Coastguard Worker     if (struct_def.fixed) {
281*890232f2SAndroid Build Coastguard Worker       // create a struct constructor function
282*890232f2SAndroid Build Coastguard Worker       GenStructBuilder(struct_def, code_ptr);
283*890232f2SAndroid Build Coastguard Worker     } else {
284*890232f2SAndroid Build Coastguard Worker       // Create a set of functions that allow table construction.
285*890232f2SAndroid Build Coastguard Worker       GenTableBuilders(struct_def, code_ptr);
286*890232f2SAndroid Build Coastguard Worker     }
287*890232f2SAndroid Build Coastguard Worker   }
288*890232f2SAndroid Build Coastguard Worker 
289*890232f2SAndroid Build Coastguard Worker   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)290*890232f2SAndroid Build Coastguard Worker   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
291*890232f2SAndroid Build Coastguard Worker     if (enum_def.generated) return;
292*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
293*890232f2SAndroid Build Coastguard Worker     CheckNameSpace(enum_def, &code);
294*890232f2SAndroid Build Coastguard Worker     GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
295*890232f2SAndroid Build Coastguard Worker     code += "enum " + NormalizedName(enum_def) + ":\n";
296*890232f2SAndroid Build Coastguard Worker     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
297*890232f2SAndroid Build Coastguard Worker       auto &ev = **it;
298*890232f2SAndroid Build Coastguard Worker       GenComment(ev.doc_comment, code_ptr, nullptr, "    ");
299*890232f2SAndroid Build Coastguard Worker       code += "    " + enum_def.name + "_" + NormalizedName(ev) + " = " +
300*890232f2SAndroid Build Coastguard Worker               enum_def.ToString(ev) + "\n";
301*890232f2SAndroid Build Coastguard Worker     }
302*890232f2SAndroid Build Coastguard Worker     code += "\n";
303*890232f2SAndroid Build Coastguard Worker   }
304*890232f2SAndroid Build Coastguard Worker 
305*890232f2SAndroid Build Coastguard Worker   // Recursively generate arguments for a constructor, to deal with nested
306*890232f2SAndroid Build Coastguard Worker   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)307*890232f2SAndroid Build Coastguard Worker   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
308*890232f2SAndroid Build Coastguard Worker                          std::string *code_ptr) {
309*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
310*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
311*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
312*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
313*890232f2SAndroid Build Coastguard Worker         // Generate arguments for a struct inside a struct. To ensure names
314*890232f2SAndroid Build Coastguard Worker         // don't clash, and to make it obvious these arguments are constructing
315*890232f2SAndroid Build Coastguard Worker         // a nested struct, prefix the name with the field name.
316*890232f2SAndroid Build Coastguard Worker         StructBuilderArgs(*field.value.type.struct_def,
317*890232f2SAndroid Build Coastguard Worker                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
318*890232f2SAndroid Build Coastguard Worker                           code_ptr);
319*890232f2SAndroid Build Coastguard Worker       } else {
320*890232f2SAndroid Build Coastguard Worker         std::string &code = *code_ptr;
321*890232f2SAndroid Build Coastguard Worker         code += ", " + (nameprefix + NormalizedName(field)) + ":" +
322*890232f2SAndroid Build Coastguard Worker                 LobsterType(field.value.type);
323*890232f2SAndroid Build Coastguard Worker       }
324*890232f2SAndroid Build Coastguard Worker     }
325*890232f2SAndroid Build Coastguard Worker   }
326*890232f2SAndroid Build Coastguard Worker 
327*890232f2SAndroid Build Coastguard Worker   // Recursively generate struct construction statements and instert manual
328*890232f2SAndroid Build Coastguard Worker   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)329*890232f2SAndroid Build Coastguard Worker   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
330*890232f2SAndroid Build Coastguard Worker                          std::string *code_ptr) {
331*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
332*890232f2SAndroid Build Coastguard Worker     code += "    b_.Prep(" + NumToString(struct_def.minalign) + ", " +
333*890232f2SAndroid Build Coastguard Worker             NumToString(struct_def.bytesize) + ")\n";
334*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.rbegin();
335*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.rend(); ++it) {
336*890232f2SAndroid Build Coastguard Worker       auto &field = **it;
337*890232f2SAndroid Build Coastguard Worker       if (field.padding)
338*890232f2SAndroid Build Coastguard Worker         code += "    b_.Pad(" + NumToString(field.padding) + ")\n";
339*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
340*890232f2SAndroid Build Coastguard Worker         StructBuilderBody(*field.value.type.struct_def,
341*890232f2SAndroid Build Coastguard Worker                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
342*890232f2SAndroid Build Coastguard Worker                           code_ptr);
343*890232f2SAndroid Build Coastguard Worker       } else {
344*890232f2SAndroid Build Coastguard Worker         code += "    b_.Prepend" + GenMethod(field.value.type) + "(" +
345*890232f2SAndroid Build Coastguard Worker                 nameprefix + NormalizedName(field) + ")\n";
346*890232f2SAndroid Build Coastguard Worker       }
347*890232f2SAndroid Build Coastguard Worker     }
348*890232f2SAndroid Build Coastguard Worker   }
349*890232f2SAndroid Build Coastguard Worker 
350*890232f2SAndroid Build Coastguard Worker   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)351*890232f2SAndroid Build Coastguard Worker   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
352*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
353*890232f2SAndroid Build Coastguard Worker     code +=
354*890232f2SAndroid Build Coastguard Worker         "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
355*890232f2SAndroid Build Coastguard Worker     StructBuilderArgs(struct_def, "", code_ptr);
356*890232f2SAndroid Build Coastguard Worker     code += "):\n";
357*890232f2SAndroid Build Coastguard Worker     StructBuilderBody(struct_def, "", code_ptr);
358*890232f2SAndroid Build Coastguard Worker     code += "    return b_.Offset()\n\n";
359*890232f2SAndroid Build Coastguard Worker   }
360*890232f2SAndroid Build Coastguard Worker 
CheckNameSpace(const Definition & def,std::string * code_ptr)361*890232f2SAndroid Build Coastguard Worker   void CheckNameSpace(const Definition &def, std::string *code_ptr) {
362*890232f2SAndroid Build Coastguard Worker     auto ns = GetNameSpace(def);
363*890232f2SAndroid Build Coastguard Worker     if (ns == current_namespace_) return;
364*890232f2SAndroid Build Coastguard Worker     current_namespace_ = ns;
365*890232f2SAndroid Build Coastguard Worker     std::string &code = *code_ptr;
366*890232f2SAndroid Build Coastguard Worker     code += "namespace " + ns + "\n\n";
367*890232f2SAndroid Build Coastguard Worker   }
368*890232f2SAndroid Build Coastguard Worker 
generate()369*890232f2SAndroid Build Coastguard Worker   bool generate() {
370*890232f2SAndroid Build Coastguard Worker     std::string code;
371*890232f2SAndroid Build Coastguard Worker     code += std::string("// ") + FlatBuffersGeneratedWarning() +
372*890232f2SAndroid Build Coastguard Worker             "\nimport flatbuffers\n\n";
373*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
374*890232f2SAndroid Build Coastguard Worker          ++it) {
375*890232f2SAndroid Build Coastguard Worker       auto &enum_def = **it;
376*890232f2SAndroid Build Coastguard Worker       GenEnum(enum_def, &code);
377*890232f2SAndroid Build Coastguard Worker     }
378*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.structs_.vec.begin();
379*890232f2SAndroid Build Coastguard Worker          it != parser_.structs_.vec.end(); ++it) {
380*890232f2SAndroid Build Coastguard Worker       auto &struct_def = **it;
381*890232f2SAndroid Build Coastguard Worker       GenStructPreDecl(struct_def, &code);
382*890232f2SAndroid Build Coastguard Worker     }
383*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.structs_.vec.begin();
384*890232f2SAndroid Build Coastguard Worker          it != parser_.structs_.vec.end(); ++it) {
385*890232f2SAndroid Build Coastguard Worker       auto &struct_def = **it;
386*890232f2SAndroid Build Coastguard Worker       GenStruct(struct_def, &code);
387*890232f2SAndroid Build Coastguard Worker     }
388*890232f2SAndroid Build Coastguard Worker     return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
389*890232f2SAndroid Build Coastguard Worker                     code, false);
390*890232f2SAndroid Build Coastguard Worker   }
391*890232f2SAndroid Build Coastguard Worker 
392*890232f2SAndroid Build Coastguard Worker  private:
393*890232f2SAndroid Build Coastguard Worker   std::unordered_set<std::string> keywords_;
394*890232f2SAndroid Build Coastguard Worker   std::string current_namespace_;
395*890232f2SAndroid Build Coastguard Worker };
396*890232f2SAndroid Build Coastguard Worker 
397*890232f2SAndroid Build Coastguard Worker }  // namespace lobster
398*890232f2SAndroid Build Coastguard Worker 
GenerateLobster(const Parser & parser,const std::string & path,const std::string & file_name)399*890232f2SAndroid Build Coastguard Worker bool GenerateLobster(const Parser &parser, const std::string &path,
400*890232f2SAndroid Build Coastguard Worker                      const std::string &file_name) {
401*890232f2SAndroid Build Coastguard Worker   lobster::LobsterGenerator generator(parser, path, file_name);
402*890232f2SAndroid Build Coastguard Worker   return generator.generate();
403*890232f2SAndroid Build Coastguard Worker }
404*890232f2SAndroid Build Coastguard Worker 
405*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
406