xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_dart.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker  * Copyright 2018 Dan Field
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 // independent from idl_parser, since this code is not needed for most clients
18*890232f2SAndroid Build Coastguard Worker #include <cassert>
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 #include "idl_namer.h"
25*890232f2SAndroid Build Coastguard Worker 
26*890232f2SAndroid Build Coastguard Worker namespace flatbuffers {
27*890232f2SAndroid Build Coastguard Worker 
28*890232f2SAndroid Build Coastguard Worker namespace dart {
29*890232f2SAndroid Build Coastguard Worker 
30*890232f2SAndroid Build Coastguard Worker namespace {
31*890232f2SAndroid Build Coastguard Worker 
DartDefaultConfig()32*890232f2SAndroid Build Coastguard Worker static Namer::Config DartDefaultConfig() {
33*890232f2SAndroid Build Coastguard Worker   return { /*types=*/Case::kUpperCamel,
34*890232f2SAndroid Build Coastguard Worker            /*constants=*/Case::kScreamingSnake,
35*890232f2SAndroid Build Coastguard Worker            /*methods=*/Case::kLowerCamel,
36*890232f2SAndroid Build Coastguard Worker            /*functions=*/Case::kUnknown,  // unused.
37*890232f2SAndroid Build Coastguard Worker            /*fields=*/Case::kLowerCamel,
38*890232f2SAndroid Build Coastguard Worker            /*variables=*/Case::kLowerCamel,
39*890232f2SAndroid Build Coastguard Worker            /*variants=*/Case::kKeep,
40*890232f2SAndroid Build Coastguard Worker            /*enum_variant_seperator=*/".",
41*890232f2SAndroid Build Coastguard Worker            /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
42*890232f2SAndroid Build Coastguard Worker            /*namespaces=*/Case::kSnake2,
43*890232f2SAndroid Build Coastguard Worker            /*namespace_seperator=*/".",
44*890232f2SAndroid Build Coastguard Worker            /*object_prefix=*/"",
45*890232f2SAndroid Build Coastguard Worker            /*object_suffix=*/"T",
46*890232f2SAndroid Build Coastguard Worker            /*keyword_prefix=*/"$",
47*890232f2SAndroid Build Coastguard Worker            /*keyword_suffix=*/"",
48*890232f2SAndroid Build Coastguard Worker            /*filenames=*/Case::kKeep,
49*890232f2SAndroid Build Coastguard Worker            /*directories=*/Case::kKeep,
50*890232f2SAndroid Build Coastguard Worker            /*output_path=*/"",
51*890232f2SAndroid Build Coastguard Worker            /*filename_suffix=*/"_generated",
52*890232f2SAndroid Build Coastguard Worker            /*filename_extension=*/".dart" };
53*890232f2SAndroid Build Coastguard Worker }
54*890232f2SAndroid Build Coastguard Worker 
DartKeywords()55*890232f2SAndroid Build Coastguard Worker static std::set<std::string> DartKeywords() {
56*890232f2SAndroid Build Coastguard Worker   // see https://www.dartlang.org/guides/language/language-tour#keywords
57*890232f2SAndroid Build Coastguard Worker   // yield*, async*, and sync* shouldn't be proble
58*890232f2SAndroid Build Coastguard Worker   return {
59*890232f2SAndroid Build Coastguard Worker     "abstract", "else",       "import",    "show",     "as",        "enum",
60*890232f2SAndroid Build Coastguard Worker     "in",       "static",     "assert",    "export",   "interface", "super",
61*890232f2SAndroid Build Coastguard Worker     "async",    "extends",    "is",        "switch",   "await",     "extension",
62*890232f2SAndroid Build Coastguard Worker     "late",     "sync",       "break",     "external", "library",   "this",
63*890232f2SAndroid Build Coastguard Worker     "case",     "factory",    "mixin",     "throw",    "catch",     "false",
64*890232f2SAndroid Build Coastguard Worker     "new",      "true",       "class",     "final",    "null",      "try",
65*890232f2SAndroid Build Coastguard Worker     "const",    "finally",    "on",        "typedef",  "continue",  "for",
66*890232f2SAndroid Build Coastguard Worker     "operator", "var",        "covariant", "Function", "part",      "void",
67*890232f2SAndroid Build Coastguard Worker     "default",  "get",        "required",  "while",    "deferred",  "hide",
68*890232f2SAndroid Build Coastguard Worker     "rethrow",  "with",       "do",        "if",       "return",    "yield",
69*890232f2SAndroid Build Coastguard Worker     "dynamic",  "implements", "set",
70*890232f2SAndroid Build Coastguard Worker   };
71*890232f2SAndroid Build Coastguard Worker }
72*890232f2SAndroid Build Coastguard Worker } // namespace
73*890232f2SAndroid Build Coastguard Worker 
74*890232f2SAndroid Build Coastguard Worker const std::string _kFb = "fb";
75*890232f2SAndroid Build Coastguard Worker 
76*890232f2SAndroid Build Coastguard Worker // Iterate through all definitions we haven't generate code for (enums, structs,
77*890232f2SAndroid Build Coastguard Worker // and tables) and output them to a single file.
78*890232f2SAndroid Build Coastguard Worker class DartGenerator : public BaseGenerator {
79*890232f2SAndroid Build Coastguard Worker  public:
80*890232f2SAndroid Build Coastguard Worker   typedef std::map<std::string, std::string> namespace_code_map;
81*890232f2SAndroid Build Coastguard Worker 
DartGenerator(const Parser & parser,const std::string & path,const std::string & file_name)82*890232f2SAndroid Build Coastguard Worker   DartGenerator(const Parser &parser, const std::string &path,
83*890232f2SAndroid Build Coastguard Worker                 const std::string &file_name)
84*890232f2SAndroid Build Coastguard Worker       : BaseGenerator(parser, path, file_name, "", ".", "dart"),
85*890232f2SAndroid Build Coastguard Worker         namer_(WithFlagOptions(DartDefaultConfig(), parser.opts, path),
86*890232f2SAndroid Build Coastguard Worker                DartKeywords()) {}
87*890232f2SAndroid Build Coastguard Worker   // Iterate through all definitions we haven't generate code for (enums,
88*890232f2SAndroid Build Coastguard Worker   // structs, and tables) and output them to a single file.
generate()89*890232f2SAndroid Build Coastguard Worker   bool generate() {
90*890232f2SAndroid Build Coastguard Worker     std::string code;
91*890232f2SAndroid Build Coastguard Worker     namespace_code_map namespace_code;
92*890232f2SAndroid Build Coastguard Worker     GenerateEnums(namespace_code);
93*890232f2SAndroid Build Coastguard Worker     GenerateStructs(namespace_code);
94*890232f2SAndroid Build Coastguard Worker 
95*890232f2SAndroid Build Coastguard Worker     for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
96*890232f2SAndroid Build Coastguard Worker       code.clear();
97*890232f2SAndroid Build Coastguard Worker       code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
98*890232f2SAndroid Build Coastguard Worker       code = code +
99*890232f2SAndroid Build Coastguard Worker              "// ignore_for_file: unused_import, unused_field, unused_element, "
100*890232f2SAndroid Build Coastguard Worker              "unused_local_variable\n\n";
101*890232f2SAndroid Build Coastguard Worker 
102*890232f2SAndroid Build Coastguard Worker       if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
103*890232f2SAndroid Build Coastguard Worker 
104*890232f2SAndroid Build Coastguard Worker       code += "import 'dart:typed_data' show Uint8List;\n";
105*890232f2SAndroid Build Coastguard Worker       code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
106*890232f2SAndroid Build Coastguard Worker               ";\n\n";
107*890232f2SAndroid Build Coastguard Worker 
108*890232f2SAndroid Build Coastguard Worker       for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
109*890232f2SAndroid Build Coastguard Worker            ++kv2) {
110*890232f2SAndroid Build Coastguard Worker         if (kv2->first != kv->first) {
111*890232f2SAndroid Build Coastguard Worker           code += "import './" + Filename(kv2->first, /*path=*/false) +
112*890232f2SAndroid Build Coastguard Worker                   "' as " + ImportAliasName(kv2->first) + ";\n";
113*890232f2SAndroid Build Coastguard Worker         }
114*890232f2SAndroid Build Coastguard Worker       }
115*890232f2SAndroid Build Coastguard Worker       code += "\n";
116*890232f2SAndroid Build Coastguard Worker       code += kv->second;
117*890232f2SAndroid Build Coastguard Worker 
118*890232f2SAndroid Build Coastguard Worker       if (!SaveFile(Filename(kv->first).c_str(), code, false)) { return false; }
119*890232f2SAndroid Build Coastguard Worker     }
120*890232f2SAndroid Build Coastguard Worker     return true;
121*890232f2SAndroid Build Coastguard Worker   }
122*890232f2SAndroid Build Coastguard Worker 
Filename(const std::string & suffix,bool path=true) const123*890232f2SAndroid Build Coastguard Worker   std::string Filename(const std::string &suffix, bool path = true) const {
124*890232f2SAndroid Build Coastguard Worker     return (path ? path_ : "") +
125*890232f2SAndroid Build Coastguard Worker            namer_.File(file_name_ + (suffix.empty() ? "" : "_" + suffix));
126*890232f2SAndroid Build Coastguard Worker   }
127*890232f2SAndroid Build Coastguard Worker 
128*890232f2SAndroid Build Coastguard Worker  private:
ImportAliasName(const std::string & ns)129*890232f2SAndroid Build Coastguard Worker   static std::string ImportAliasName(const std::string &ns) {
130*890232f2SAndroid Build Coastguard Worker     std::string ret;
131*890232f2SAndroid Build Coastguard Worker     ret.assign(ns);
132*890232f2SAndroid Build Coastguard Worker     size_t pos = ret.find('.');
133*890232f2SAndroid Build Coastguard Worker     while (pos != std::string::npos) {
134*890232f2SAndroid Build Coastguard Worker       ret.replace(pos, 1, "_");
135*890232f2SAndroid Build Coastguard Worker       pos = ret.find('.', pos + 1);
136*890232f2SAndroid Build Coastguard Worker     }
137*890232f2SAndroid Build Coastguard Worker 
138*890232f2SAndroid Build Coastguard Worker     return ret;
139*890232f2SAndroid Build Coastguard Worker   }
140*890232f2SAndroid Build Coastguard Worker 
GenerateEnums(namespace_code_map & namespace_code)141*890232f2SAndroid Build Coastguard Worker   void GenerateEnums(namespace_code_map &namespace_code) {
142*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
143*890232f2SAndroid Build Coastguard Worker          ++it) {
144*890232f2SAndroid Build Coastguard Worker       auto &enum_def = **it;
145*890232f2SAndroid Build Coastguard Worker       GenEnum(enum_def, namespace_code);
146*890232f2SAndroid Build Coastguard Worker     }
147*890232f2SAndroid Build Coastguard Worker   }
148*890232f2SAndroid Build Coastguard Worker 
GenerateStructs(namespace_code_map & namespace_code)149*890232f2SAndroid Build Coastguard Worker   void GenerateStructs(namespace_code_map &namespace_code) {
150*890232f2SAndroid Build Coastguard Worker     for (auto it = parser_.structs_.vec.begin();
151*890232f2SAndroid Build Coastguard Worker          it != parser_.structs_.vec.end(); ++it) {
152*890232f2SAndroid Build Coastguard Worker       auto &struct_def = **it;
153*890232f2SAndroid Build Coastguard Worker       GenStruct(struct_def, namespace_code);
154*890232f2SAndroid Build Coastguard Worker     }
155*890232f2SAndroid Build Coastguard Worker   }
156*890232f2SAndroid Build Coastguard Worker 
157*890232f2SAndroid Build Coastguard Worker   // Generate a documentation comment, if available.
GenDocComment(const std::vector<std::string> & dc,const char * indent,std::string & code)158*890232f2SAndroid Build Coastguard Worker   static void GenDocComment(const std::vector<std::string> &dc,
159*890232f2SAndroid Build Coastguard Worker                             const char *indent, std::string &code) {
160*890232f2SAndroid Build Coastguard Worker     for (auto it = dc.begin(); it != dc.end(); ++it) {
161*890232f2SAndroid Build Coastguard Worker       if (indent) code += indent;
162*890232f2SAndroid Build Coastguard Worker       code += "/// " + *it + "\n";
163*890232f2SAndroid Build Coastguard Worker     }
164*890232f2SAndroid Build Coastguard Worker   }
165*890232f2SAndroid Build Coastguard Worker 
166*890232f2SAndroid Build Coastguard Worker   // Generate an enum declaration and an enum string lookup table.
GenEnum(EnumDef & enum_def,namespace_code_map & namespace_code)167*890232f2SAndroid Build Coastguard Worker   void GenEnum(EnumDef &enum_def, namespace_code_map &namespace_code) {
168*890232f2SAndroid Build Coastguard Worker     if (enum_def.generated) return;
169*890232f2SAndroid Build Coastguard Worker     std::string &code =
170*890232f2SAndroid Build Coastguard Worker         namespace_code[namer_.Namespace(*enum_def.defined_namespace)];
171*890232f2SAndroid Build Coastguard Worker     GenDocComment(enum_def.doc_comment, "", code);
172*890232f2SAndroid Build Coastguard Worker 
173*890232f2SAndroid Build Coastguard Worker     const std::string enum_type =
174*890232f2SAndroid Build Coastguard Worker         namer_.Type(enum_def) + (enum_def.is_union ? "TypeId" : "");
175*890232f2SAndroid Build Coastguard Worker     const bool is_bit_flags =
176*890232f2SAndroid Build Coastguard Worker         enum_def.attributes.Lookup("bit_flags") != nullptr;
177*890232f2SAndroid Build Coastguard Worker     // The flatbuffer schema language allows bit flag enums to potentially have
178*890232f2SAndroid Build Coastguard Worker     // a default value of zero, even if it's not a valid enum value...
179*890232f2SAndroid Build Coastguard Worker     const bool permit_zero = is_bit_flags;
180*890232f2SAndroid Build Coastguard Worker 
181*890232f2SAndroid Build Coastguard Worker     code += "class " + enum_type + " {\n";
182*890232f2SAndroid Build Coastguard Worker     code += "  final int value;\n";
183*890232f2SAndroid Build Coastguard Worker     code += "  const " + enum_type + "._(this.value);\n\n";
184*890232f2SAndroid Build Coastguard Worker     code += "  factory " + enum_type + ".fromValue(int value) {\n";
185*890232f2SAndroid Build Coastguard Worker     code += "    final result = values[value];\n";
186*890232f2SAndroid Build Coastguard Worker     code += "    if (result == null) {\n";
187*890232f2SAndroid Build Coastguard Worker     if (permit_zero) {
188*890232f2SAndroid Build Coastguard Worker       code += "      if (value == 0) {\n";
189*890232f2SAndroid Build Coastguard Worker       code += "        return " + enum_type + "._(0);\n";
190*890232f2SAndroid Build Coastguard Worker       code += "      } else {\n";
191*890232f2SAndroid Build Coastguard Worker     }
192*890232f2SAndroid Build Coastguard Worker     code += "        throw StateError('Invalid value $value for bit flag enum ";
193*890232f2SAndroid Build Coastguard Worker     code += enum_type + "');\n";
194*890232f2SAndroid Build Coastguard Worker     if (permit_zero) { code += "      }\n"; }
195*890232f2SAndroid Build Coastguard Worker     code += "    }\n";
196*890232f2SAndroid Build Coastguard Worker 
197*890232f2SAndroid Build Coastguard Worker     code += "    return result;\n";
198*890232f2SAndroid Build Coastguard Worker     code += "  }\n\n";
199*890232f2SAndroid Build Coastguard Worker 
200*890232f2SAndroid Build Coastguard Worker     code += "  static " + enum_type + "? _createOrNull(int? value) => \n";
201*890232f2SAndroid Build Coastguard Worker     code +=
202*890232f2SAndroid Build Coastguard Worker         "      value == null ? null : " + enum_type + ".fromValue(value);\n\n";
203*890232f2SAndroid Build Coastguard Worker 
204*890232f2SAndroid Build Coastguard Worker     // this is meaningless for bit_flags
205*890232f2SAndroid Build Coastguard Worker     // however, note that unlike "regular" dart enums this enum can still have
206*890232f2SAndroid Build Coastguard Worker     // holes.
207*890232f2SAndroid Build Coastguard Worker     if (!is_bit_flags) {
208*890232f2SAndroid Build Coastguard Worker       code += "  static const int minValue = " +
209*890232f2SAndroid Build Coastguard Worker               enum_def.ToString(*enum_def.MinValue()) + ";\n";
210*890232f2SAndroid Build Coastguard Worker       code += "  static const int maxValue = " +
211*890232f2SAndroid Build Coastguard Worker               enum_def.ToString(*enum_def.MaxValue()) + ";\n";
212*890232f2SAndroid Build Coastguard Worker     }
213*890232f2SAndroid Build Coastguard Worker 
214*890232f2SAndroid Build Coastguard Worker     code +=
215*890232f2SAndroid Build Coastguard Worker         "  static bool containsValue(int value) =>"
216*890232f2SAndroid Build Coastguard Worker         " values.containsKey(value);\n\n";
217*890232f2SAndroid Build Coastguard Worker 
218*890232f2SAndroid Build Coastguard Worker     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
219*890232f2SAndroid Build Coastguard Worker       auto &ev = **it;
220*890232f2SAndroid Build Coastguard Worker       const auto enum_var = namer_.Variant(ev);
221*890232f2SAndroid Build Coastguard Worker 
222*890232f2SAndroid Build Coastguard Worker       if (!ev.doc_comment.empty()) {
223*890232f2SAndroid Build Coastguard Worker         if (it != enum_def.Vals().begin()) { code += '\n'; }
224*890232f2SAndroid Build Coastguard Worker         GenDocComment(ev.doc_comment, "  ", code);
225*890232f2SAndroid Build Coastguard Worker       }
226*890232f2SAndroid Build Coastguard Worker       code += "  static const " + enum_type + " " + enum_var + " = " +
227*890232f2SAndroid Build Coastguard Worker               enum_type + "._(" + enum_def.ToString(ev) + ");\n";
228*890232f2SAndroid Build Coastguard Worker     }
229*890232f2SAndroid Build Coastguard Worker 
230*890232f2SAndroid Build Coastguard Worker     code += "  static const Map<int, " + enum_type + "> values = {\n";
231*890232f2SAndroid Build Coastguard Worker     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
232*890232f2SAndroid Build Coastguard Worker       auto &ev = **it;
233*890232f2SAndroid Build Coastguard Worker       const auto enum_var = namer_.Variant(ev);
234*890232f2SAndroid Build Coastguard Worker       if (it != enum_def.Vals().begin()) code += ",\n";
235*890232f2SAndroid Build Coastguard Worker       code += "    " + enum_def.ToString(ev) + ": " + enum_var;
236*890232f2SAndroid Build Coastguard Worker     }
237*890232f2SAndroid Build Coastguard Worker     code += "};\n\n";
238*890232f2SAndroid Build Coastguard Worker 
239*890232f2SAndroid Build Coastguard Worker     code += "  static const " + _kFb + ".Reader<" + enum_type + "> reader = _" +
240*890232f2SAndroid Build Coastguard Worker             enum_type + "Reader();\n\n";
241*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
242*890232f2SAndroid Build Coastguard Worker     code += "  String toString() {\n";
243*890232f2SAndroid Build Coastguard Worker     code += "    return '" + enum_type + "{value: $value}';\n";
244*890232f2SAndroid Build Coastguard Worker     code += "  }\n";
245*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
246*890232f2SAndroid Build Coastguard Worker 
247*890232f2SAndroid Build Coastguard Worker     GenEnumReader(enum_def, enum_type, code);
248*890232f2SAndroid Build Coastguard Worker   }
249*890232f2SAndroid Build Coastguard Worker 
GenEnumReader(EnumDef & enum_def,const std::string & enum_type,std::string & code)250*890232f2SAndroid Build Coastguard Worker   void GenEnumReader(EnumDef &enum_def, const std::string &enum_type,
251*890232f2SAndroid Build Coastguard Worker                      std::string &code) {
252*890232f2SAndroid Build Coastguard Worker     code += "class _" + enum_type + "Reader extends " + _kFb + ".Reader<" +
253*890232f2SAndroid Build Coastguard Worker             enum_type + "> {\n";
254*890232f2SAndroid Build Coastguard Worker     code += "  const _" + enum_type + "Reader();\n\n";
255*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
256*890232f2SAndroid Build Coastguard Worker     code += "  int get size => " + EnumSize(enum_def.underlying_type) + ";\n\n";
257*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
258*890232f2SAndroid Build Coastguard Worker     code += "  " + enum_type + " read(" + _kFb +
259*890232f2SAndroid Build Coastguard Worker             ".BufferContext bc, int offset) =>\n";
260*890232f2SAndroid Build Coastguard Worker     code += "      " + enum_type + ".fromValue(const " + _kFb + "." +
261*890232f2SAndroid Build Coastguard Worker             GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
262*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
263*890232f2SAndroid Build Coastguard Worker   }
264*890232f2SAndroid Build Coastguard Worker 
GenType(const Type & type)265*890232f2SAndroid Build Coastguard Worker   std::string GenType(const Type &type) {
266*890232f2SAndroid Build Coastguard Worker     switch (type.base_type) {
267*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_BOOL: return "Bool";
268*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_CHAR: return "Int8";
269*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UTYPE:
270*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UCHAR: return "Uint8";
271*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_SHORT: return "Int16";
272*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_USHORT: return "Uint16";
273*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_INT: return "Int32";
274*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UINT: return "Uint32";
275*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_LONG: return "Int64";
276*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ULONG: return "Uint64";
277*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_FLOAT: return "Float32";
278*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_DOUBLE: return "Float64";
279*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: return "String";
280*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR: return GenType(type.VectorType());
281*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT: return namer_.Type(*type.struct_def);
282*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UNION: return namer_.Type(*type.enum_def) + "TypeId";
283*890232f2SAndroid Build Coastguard Worker       default: return "Table";
284*890232f2SAndroid Build Coastguard Worker     }
285*890232f2SAndroid Build Coastguard Worker   }
286*890232f2SAndroid Build Coastguard Worker 
EnumSize(const Type & type)287*890232f2SAndroid Build Coastguard Worker   static std::string EnumSize(const Type &type) {
288*890232f2SAndroid Build Coastguard Worker     switch (type.base_type) {
289*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_BOOL:
290*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_CHAR:
291*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UTYPE:
292*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UCHAR: return "1";
293*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_SHORT:
294*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_USHORT: return "2";
295*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_INT:
296*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UINT:
297*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_FLOAT: return "4";
298*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_LONG:
299*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ULONG:
300*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_DOUBLE: return "8";
301*890232f2SAndroid Build Coastguard Worker       default: return "1";
302*890232f2SAndroid Build Coastguard Worker     }
303*890232f2SAndroid Build Coastguard Worker   }
304*890232f2SAndroid Build Coastguard Worker 
GenReaderTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,bool parent_is_vector=false,bool lazy=true,bool constConstruct=true)305*890232f2SAndroid Build Coastguard Worker   std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
306*890232f2SAndroid Build Coastguard Worker                                 const FieldDef &def,
307*890232f2SAndroid Build Coastguard Worker                                 bool parent_is_vector = false, bool lazy = true,
308*890232f2SAndroid Build Coastguard Worker                                 bool constConstruct = true) {
309*890232f2SAndroid Build Coastguard Worker     std::string prefix = (constConstruct ? "const " : "") + _kFb;
310*890232f2SAndroid Build Coastguard Worker     if (type.base_type == BASE_TYPE_BOOL) {
311*890232f2SAndroid Build Coastguard Worker       return prefix + ".BoolReader()";
312*890232f2SAndroid Build Coastguard Worker     } else if (IsVector(type)) {
313*890232f2SAndroid Build Coastguard Worker       if (!type.VectorType().enum_def) {
314*890232f2SAndroid Build Coastguard Worker         if (type.VectorType().base_type == BASE_TYPE_CHAR) {
315*890232f2SAndroid Build Coastguard Worker           return prefix + ".Int8ListReader(" + (lazy ? ")" : "lazy: false)");
316*890232f2SAndroid Build Coastguard Worker         }
317*890232f2SAndroid Build Coastguard Worker         if (type.VectorType().base_type == BASE_TYPE_UCHAR) {
318*890232f2SAndroid Build Coastguard Worker           return prefix + ".Uint8ListReader(" + (lazy ? ")" : "lazy: false)");
319*890232f2SAndroid Build Coastguard Worker         }
320*890232f2SAndroid Build Coastguard Worker       }
321*890232f2SAndroid Build Coastguard Worker       return prefix + ".ListReader<" +
322*890232f2SAndroid Build Coastguard Worker              GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
323*890232f2SAndroid Build Coastguard Worker              GenReaderTypeName(type.VectorType(), current_namespace, def, true,
324*890232f2SAndroid Build Coastguard Worker                                true, false) +
325*890232f2SAndroid Build Coastguard Worker              (lazy ? ")" : ", lazy: false)");
326*890232f2SAndroid Build Coastguard Worker     } else if (IsString(type)) {
327*890232f2SAndroid Build Coastguard Worker       return prefix + ".StringReader()";
328*890232f2SAndroid Build Coastguard Worker     }
329*890232f2SAndroid Build Coastguard Worker     if (IsScalar(type.base_type)) {
330*890232f2SAndroid Build Coastguard Worker       if (type.enum_def && parent_is_vector) {
331*890232f2SAndroid Build Coastguard Worker         return GenDartTypeName(type, current_namespace, def) + ".reader";
332*890232f2SAndroid Build Coastguard Worker       }
333*890232f2SAndroid Build Coastguard Worker       return prefix + "." + GenType(type) + "Reader()";
334*890232f2SAndroid Build Coastguard Worker     } else {
335*890232f2SAndroid Build Coastguard Worker       return GenDartTypeName(type, current_namespace, def) + ".reader";
336*890232f2SAndroid Build Coastguard Worker     }
337*890232f2SAndroid Build Coastguard Worker   }
338*890232f2SAndroid Build Coastguard Worker 
GenDartTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,std::string struct_type_suffix="")339*890232f2SAndroid Build Coastguard Worker   std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
340*890232f2SAndroid Build Coastguard Worker                               const FieldDef &def,
341*890232f2SAndroid Build Coastguard Worker                               std::string struct_type_suffix = "") {
342*890232f2SAndroid Build Coastguard Worker     if (type.enum_def) {
343*890232f2SAndroid Build Coastguard Worker       if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
344*890232f2SAndroid Build Coastguard Worker         return namer_.Type(*type.enum_def) + "TypeId";
345*890232f2SAndroid Build Coastguard Worker       } else if (type.enum_def->is_union) {
346*890232f2SAndroid Build Coastguard Worker         return "dynamic";
347*890232f2SAndroid Build Coastguard Worker       } else if (type.base_type != BASE_TYPE_VECTOR) {
348*890232f2SAndroid Build Coastguard Worker         return namer_.Type(*type.enum_def);
349*890232f2SAndroid Build Coastguard Worker       }
350*890232f2SAndroid Build Coastguard Worker     }
351*890232f2SAndroid Build Coastguard Worker 
352*890232f2SAndroid Build Coastguard Worker     switch (type.base_type) {
353*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_BOOL: return "bool";
354*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_LONG:
355*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_ULONG:
356*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_INT:
357*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UINT:
358*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_SHORT:
359*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_USHORT:
360*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_CHAR:
361*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_UCHAR: return "int";
362*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_FLOAT:
363*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_DOUBLE: return "double";
364*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRING: return "String";
365*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_STRUCT:
366*890232f2SAndroid Build Coastguard Worker         return MaybeWrapNamespace(
367*890232f2SAndroid Build Coastguard Worker             namer_.Type(*type.struct_def) + struct_type_suffix,
368*890232f2SAndroid Build Coastguard Worker             current_namespace, def);
369*890232f2SAndroid Build Coastguard Worker       case BASE_TYPE_VECTOR:
370*890232f2SAndroid Build Coastguard Worker         return "List<" +
371*890232f2SAndroid Build Coastguard Worker                GenDartTypeName(type.VectorType(), current_namespace, def,
372*890232f2SAndroid Build Coastguard Worker                                struct_type_suffix) +
373*890232f2SAndroid Build Coastguard Worker                ">";
374*890232f2SAndroid Build Coastguard Worker       default: assert(0); return "dynamic";
375*890232f2SAndroid Build Coastguard Worker     }
376*890232f2SAndroid Build Coastguard Worker   }
377*890232f2SAndroid Build Coastguard Worker 
GenDartTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,bool nullable,std::string struct_type_suffix)378*890232f2SAndroid Build Coastguard Worker   std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
379*890232f2SAndroid Build Coastguard Worker                               const FieldDef &def, bool nullable,
380*890232f2SAndroid Build Coastguard Worker                               std::string struct_type_suffix) {
381*890232f2SAndroid Build Coastguard Worker     std::string typeName =
382*890232f2SAndroid Build Coastguard Worker         GenDartTypeName(type, current_namespace, def, struct_type_suffix);
383*890232f2SAndroid Build Coastguard Worker     if (nullable && typeName != "dynamic") typeName += "?";
384*890232f2SAndroid Build Coastguard Worker     return typeName;
385*890232f2SAndroid Build Coastguard Worker   }
386*890232f2SAndroid Build Coastguard Worker 
MaybeWrapNamespace(const std::string & type_name,Namespace * current_ns,const FieldDef & field) const387*890232f2SAndroid Build Coastguard Worker   std::string MaybeWrapNamespace(const std::string &type_name,
388*890232f2SAndroid Build Coastguard Worker                                  Namespace *current_ns,
389*890232f2SAndroid Build Coastguard Worker                                  const FieldDef &field) const {
390*890232f2SAndroid Build Coastguard Worker     const std::string current_namespace = namer_.Namespace(*current_ns);
391*890232f2SAndroid Build Coastguard Worker     const std::string field_namespace =
392*890232f2SAndroid Build Coastguard Worker         field.value.type.struct_def
393*890232f2SAndroid Build Coastguard Worker             ? namer_.Namespace(*field.value.type.struct_def->defined_namespace)
394*890232f2SAndroid Build Coastguard Worker         : field.value.type.enum_def
395*890232f2SAndroid Build Coastguard Worker             ? namer_.Namespace(*field.value.type.enum_def->defined_namespace)
396*890232f2SAndroid Build Coastguard Worker             : "";
397*890232f2SAndroid Build Coastguard Worker 
398*890232f2SAndroid Build Coastguard Worker     if (field_namespace != "" && field_namespace != current_namespace) {
399*890232f2SAndroid Build Coastguard Worker       return ImportAliasName(field_namespace) + "." + type_name;
400*890232f2SAndroid Build Coastguard Worker     } else {
401*890232f2SAndroid Build Coastguard Worker       return type_name;
402*890232f2SAndroid Build Coastguard Worker     }
403*890232f2SAndroid Build Coastguard Worker   }
404*890232f2SAndroid Build Coastguard Worker 
405*890232f2SAndroid Build Coastguard Worker   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def,namespace_code_map & namespace_code)406*890232f2SAndroid Build Coastguard Worker   void GenStruct(const StructDef &struct_def,
407*890232f2SAndroid Build Coastguard Worker                  namespace_code_map &namespace_code) {
408*890232f2SAndroid Build Coastguard Worker     if (struct_def.generated) return;
409*890232f2SAndroid Build Coastguard Worker 
410*890232f2SAndroid Build Coastguard Worker     std::string &code =
411*890232f2SAndroid Build Coastguard Worker         namespace_code[namer_.Namespace(*struct_def.defined_namespace)];
412*890232f2SAndroid Build Coastguard Worker 
413*890232f2SAndroid Build Coastguard Worker     const auto &struct_type = namer_.Type(struct_def);
414*890232f2SAndroid Build Coastguard Worker 
415*890232f2SAndroid Build Coastguard Worker     // Emit constructor
416*890232f2SAndroid Build Coastguard Worker 
417*890232f2SAndroid Build Coastguard Worker     GenDocComment(struct_def.doc_comment, "", code);
418*890232f2SAndroid Build Coastguard Worker 
419*890232f2SAndroid Build Coastguard Worker     auto reader_name = "_" + struct_type + "Reader";
420*890232f2SAndroid Build Coastguard Worker     auto builder_name = struct_type + "Builder";
421*890232f2SAndroid Build Coastguard Worker     auto object_builder_name = struct_type + "ObjectBuilder";
422*890232f2SAndroid Build Coastguard Worker 
423*890232f2SAndroid Build Coastguard Worker     std::string reader_code, builder_code;
424*890232f2SAndroid Build Coastguard Worker 
425*890232f2SAndroid Build Coastguard Worker     code += "class " + struct_type + " {\n";
426*890232f2SAndroid Build Coastguard Worker 
427*890232f2SAndroid Build Coastguard Worker     code += "  " + struct_type + "._(this._bc, this._bcOffset);\n";
428*890232f2SAndroid Build Coastguard Worker     if (!struct_def.fixed) {
429*890232f2SAndroid Build Coastguard Worker       code += "  factory " + struct_type + "(List<int> bytes) {\n";
430*890232f2SAndroid Build Coastguard Worker       code +=
431*890232f2SAndroid Build Coastguard Worker           "    final rootRef = " + _kFb + ".BufferContext.fromBytes(bytes);\n";
432*890232f2SAndroid Build Coastguard Worker       code += "    return reader.read(rootRef, 0);\n";
433*890232f2SAndroid Build Coastguard Worker       code += "  }\n";
434*890232f2SAndroid Build Coastguard Worker     }
435*890232f2SAndroid Build Coastguard Worker 
436*890232f2SAndroid Build Coastguard Worker     code += "\n";
437*890232f2SAndroid Build Coastguard Worker     code += "  static const " + _kFb + ".Reader<" + struct_type +
438*890232f2SAndroid Build Coastguard Worker             "> reader = " + reader_name + "();\n\n";
439*890232f2SAndroid Build Coastguard Worker 
440*890232f2SAndroid Build Coastguard Worker     code += "  final " + _kFb + ".BufferContext _bc;\n";
441*890232f2SAndroid Build Coastguard Worker     code += "  final int _bcOffset;\n\n";
442*890232f2SAndroid Build Coastguard Worker 
443*890232f2SAndroid Build Coastguard Worker     std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
444*890232f2SAndroid Build Coastguard Worker     for (auto it = struct_def.fields.vec.begin();
445*890232f2SAndroid Build Coastguard Worker          it != struct_def.fields.vec.end(); ++it) {
446*890232f2SAndroid Build Coastguard Worker       FieldDef &field = **it;
447*890232f2SAndroid Build Coastguard Worker       if (field.deprecated) continue;
448*890232f2SAndroid Build Coastguard Worker       auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
449*890232f2SAndroid Build Coastguard Worker       non_deprecated_fields.push_back(std::make_pair(offset, &field));
450*890232f2SAndroid Build Coastguard Worker     }
451*890232f2SAndroid Build Coastguard Worker 
452*890232f2SAndroid Build Coastguard Worker     GenImplementationGetters(struct_def, non_deprecated_fields, code);
453*890232f2SAndroid Build Coastguard Worker 
454*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api) {
455*890232f2SAndroid Build Coastguard Worker       code +=
456*890232f2SAndroid Build Coastguard Worker           "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields);
457*890232f2SAndroid Build Coastguard Worker 
458*890232f2SAndroid Build Coastguard Worker       code += "\n  static int pack(fb.Builder fbBuilder, " +
459*890232f2SAndroid Build Coastguard Worker               namer_.ObjectType(struct_def) + "? object) {\n";
460*890232f2SAndroid Build Coastguard Worker       code += "    if (object == null) return 0;\n";
461*890232f2SAndroid Build Coastguard Worker       code += "    return object.pack(fbBuilder);\n";
462*890232f2SAndroid Build Coastguard Worker       code += "  }\n";
463*890232f2SAndroid Build Coastguard Worker     }
464*890232f2SAndroid Build Coastguard Worker 
465*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
466*890232f2SAndroid Build Coastguard Worker 
467*890232f2SAndroid Build Coastguard Worker     if (parser_.opts.generate_object_based_api) {
468*890232f2SAndroid Build Coastguard Worker       code += GenStructObjectAPI(struct_def, non_deprecated_fields);
469*890232f2SAndroid Build Coastguard Worker     }
470*890232f2SAndroid Build Coastguard Worker 
471*890232f2SAndroid Build Coastguard Worker     GenReader(struct_def, reader_name, reader_code);
472*890232f2SAndroid Build Coastguard Worker     GenBuilder(struct_def, non_deprecated_fields, builder_name, builder_code);
473*890232f2SAndroid Build Coastguard Worker     GenObjectBuilder(struct_def, non_deprecated_fields, object_builder_name,
474*890232f2SAndroid Build Coastguard Worker                      builder_code);
475*890232f2SAndroid Build Coastguard Worker 
476*890232f2SAndroid Build Coastguard Worker     code += reader_code;
477*890232f2SAndroid Build Coastguard Worker     code += builder_code;
478*890232f2SAndroid Build Coastguard Worker   }
479*890232f2SAndroid Build Coastguard Worker 
480*890232f2SAndroid Build Coastguard Worker   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStructObjectAPI(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)481*890232f2SAndroid Build Coastguard Worker   std::string GenStructObjectAPI(
482*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
483*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
484*890232f2SAndroid Build Coastguard Worker     std::string code;
485*890232f2SAndroid Build Coastguard Worker     GenDocComment(struct_def.doc_comment, "", code);
486*890232f2SAndroid Build Coastguard Worker 
487*890232f2SAndroid Build Coastguard Worker     std::string object_type = namer_.ObjectType(struct_def);
488*890232f2SAndroid Build Coastguard Worker     code += "class " + object_type + " implements " + _kFb + ".Packable {\n";
489*890232f2SAndroid Build Coastguard Worker 
490*890232f2SAndroid Build Coastguard Worker     std::string constructor_args;
491*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
492*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
493*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
494*890232f2SAndroid Build Coastguard Worker 
495*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
496*890232f2SAndroid Build Coastguard Worker       const std::string defaultValue = getDefaultValue(field.value);
497*890232f2SAndroid Build Coastguard Worker       const std::string type_name =
498*890232f2SAndroid Build Coastguard Worker           GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
499*890232f2SAndroid Build Coastguard Worker                           defaultValue.empty() && !struct_def.fixed, "T");
500*890232f2SAndroid Build Coastguard Worker 
501*890232f2SAndroid Build Coastguard Worker       GenDocComment(field.doc_comment, "  ", code);
502*890232f2SAndroid Build Coastguard Worker       code += "  " + type_name + " " + field_name + ";\n";
503*890232f2SAndroid Build Coastguard Worker 
504*890232f2SAndroid Build Coastguard Worker       if (!constructor_args.empty()) constructor_args += ",\n";
505*890232f2SAndroid Build Coastguard Worker       constructor_args += "      ";
506*890232f2SAndroid Build Coastguard Worker       constructor_args += (struct_def.fixed ? "required " : "");
507*890232f2SAndroid Build Coastguard Worker       constructor_args += "this." + field_name;
508*890232f2SAndroid Build Coastguard Worker       if (!struct_def.fixed && !defaultValue.empty()) {
509*890232f2SAndroid Build Coastguard Worker         if (IsEnum(field.value.type)) {
510*890232f2SAndroid Build Coastguard Worker           auto &enum_def = *field.value.type.enum_def;
511*890232f2SAndroid Build Coastguard Worker           if (auto val = enum_def.FindByValue(defaultValue)) {
512*890232f2SAndroid Build Coastguard Worker             constructor_args += " = " + namer_.EnumVariant(enum_def, *val);
513*890232f2SAndroid Build Coastguard Worker           } else {
514*890232f2SAndroid Build Coastguard Worker             constructor_args += " = const " + namer_.Type(enum_def) + "._(" +
515*890232f2SAndroid Build Coastguard Worker                                 defaultValue + ")";
516*890232f2SAndroid Build Coastguard Worker           }
517*890232f2SAndroid Build Coastguard Worker         } else {
518*890232f2SAndroid Build Coastguard Worker           constructor_args += " = " + defaultValue;
519*890232f2SAndroid Build Coastguard Worker         }
520*890232f2SAndroid Build Coastguard Worker       }
521*890232f2SAndroid Build Coastguard Worker     }
522*890232f2SAndroid Build Coastguard Worker 
523*890232f2SAndroid Build Coastguard Worker     if (!constructor_args.empty()) {
524*890232f2SAndroid Build Coastguard Worker       code += "\n  " + object_type + "({\n" + constructor_args + "});\n\n";
525*890232f2SAndroid Build Coastguard Worker     }
526*890232f2SAndroid Build Coastguard Worker 
527*890232f2SAndroid Build Coastguard Worker     code += GenStructObjectAPIPack(struct_def, non_deprecated_fields);
528*890232f2SAndroid Build Coastguard Worker     code += "\n";
529*890232f2SAndroid Build Coastguard Worker     code += GenToString(object_type, non_deprecated_fields);
530*890232f2SAndroid Build Coastguard Worker 
531*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
532*890232f2SAndroid Build Coastguard Worker     return code;
533*890232f2SAndroid Build Coastguard Worker   }
534*890232f2SAndroid Build Coastguard Worker 
535*890232f2SAndroid Build Coastguard Worker   // Generate function `StructNameT unpack()`
GenStructObjectAPIUnpack(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)536*890232f2SAndroid Build Coastguard Worker   std::string GenStructObjectAPIUnpack(
537*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
538*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
539*890232f2SAndroid Build Coastguard Worker     std::string constructor_args;
540*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
541*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
542*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
543*890232f2SAndroid Build Coastguard Worker 
544*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
545*890232f2SAndroid Build Coastguard Worker       if (!constructor_args.empty()) constructor_args += ",\n";
546*890232f2SAndroid Build Coastguard Worker       constructor_args += "      " + field_name + ": ";
547*890232f2SAndroid Build Coastguard Worker 
548*890232f2SAndroid Build Coastguard Worker       const Type &type = field.value.type;
549*890232f2SAndroid Build Coastguard Worker       std::string defaultValue = getDefaultValue(field.value);
550*890232f2SAndroid Build Coastguard Worker       bool isNullable = defaultValue.empty() && !struct_def.fixed;
551*890232f2SAndroid Build Coastguard Worker       std::string nullableValueAccessOperator = isNullable ? "?" : "";
552*890232f2SAndroid Build Coastguard Worker       if (type.base_type == BASE_TYPE_STRUCT) {
553*890232f2SAndroid Build Coastguard Worker         constructor_args +=
554*890232f2SAndroid Build Coastguard Worker             field_name + nullableValueAccessOperator + ".unpack()";
555*890232f2SAndroid Build Coastguard Worker       } else if (type.base_type == BASE_TYPE_VECTOR) {
556*890232f2SAndroid Build Coastguard Worker         if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
557*890232f2SAndroid Build Coastguard Worker           constructor_args += field_name + nullableValueAccessOperator +
558*890232f2SAndroid Build Coastguard Worker                               ".map((e) => e.unpack()).toList()";
559*890232f2SAndroid Build Coastguard Worker         } else {
560*890232f2SAndroid Build Coastguard Worker           constructor_args +=
561*890232f2SAndroid Build Coastguard Worker               GenReaderTypeName(field.value.type, struct_def.defined_namespace,
562*890232f2SAndroid Build Coastguard Worker                                 field, false, false);
563*890232f2SAndroid Build Coastguard Worker           constructor_args += ".vTableGet";
564*890232f2SAndroid Build Coastguard Worker           std::string offset = NumToString(field.value.offset);
565*890232f2SAndroid Build Coastguard Worker           constructor_args +=
566*890232f2SAndroid Build Coastguard Worker               isNullable
567*890232f2SAndroid Build Coastguard Worker                   ? "Nullable(_bc, _bcOffset, " + offset + ")"
568*890232f2SAndroid Build Coastguard Worker                   : "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
569*890232f2SAndroid Build Coastguard Worker         }
570*890232f2SAndroid Build Coastguard Worker       } else {
571*890232f2SAndroid Build Coastguard Worker         constructor_args += field_name;
572*890232f2SAndroid Build Coastguard Worker       }
573*890232f2SAndroid Build Coastguard Worker     }
574*890232f2SAndroid Build Coastguard Worker 
575*890232f2SAndroid Build Coastguard Worker     const std::string object_type = namer_.ObjectType(struct_def);
576*890232f2SAndroid Build Coastguard Worker     std::string code = "  " + object_type + " unpack() => " + object_type + "(";
577*890232f2SAndroid Build Coastguard Worker     if (!constructor_args.empty()) code += "\n" + constructor_args;
578*890232f2SAndroid Build Coastguard Worker     code += ");\n";
579*890232f2SAndroid Build Coastguard Worker     return code;
580*890232f2SAndroid Build Coastguard Worker   }
581*890232f2SAndroid Build Coastguard Worker 
582*890232f2SAndroid Build Coastguard Worker   // Generate function `StructNameT pack()`
GenStructObjectAPIPack(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)583*890232f2SAndroid Build Coastguard Worker   std::string GenStructObjectAPIPack(
584*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
585*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
586*890232f2SAndroid Build Coastguard Worker     std::string code;
587*890232f2SAndroid Build Coastguard Worker 
588*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
589*890232f2SAndroid Build Coastguard Worker     code += "  int pack(fb.Builder fbBuilder) {\n";
590*890232f2SAndroid Build Coastguard Worker     code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields,
591*890232f2SAndroid Build Coastguard Worker                                            false, true);
592*890232f2SAndroid Build Coastguard Worker     code += "  }\n";
593*890232f2SAndroid Build Coastguard Worker     return code;
594*890232f2SAndroid Build Coastguard Worker   }
595*890232f2SAndroid Build Coastguard Worker 
NamespaceAliasFromUnionType(Namespace * root_namespace,const Type & type)596*890232f2SAndroid Build Coastguard Worker   std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
597*890232f2SAndroid Build Coastguard Worker                                           const Type &type) {
598*890232f2SAndroid Build Coastguard Worker     const std::vector<std::string> qualified_name_parts =
599*890232f2SAndroid Build Coastguard Worker         type.struct_def->defined_namespace->components;
600*890232f2SAndroid Build Coastguard Worker     if (std::equal(root_namespace->components.begin(),
601*890232f2SAndroid Build Coastguard Worker                    root_namespace->components.end(),
602*890232f2SAndroid Build Coastguard Worker                    qualified_name_parts.begin())) {
603*890232f2SAndroid Build Coastguard Worker       return namer_.Type(*type.struct_def);
604*890232f2SAndroid Build Coastguard Worker     }
605*890232f2SAndroid Build Coastguard Worker 
606*890232f2SAndroid Build Coastguard Worker     std::string ns;
607*890232f2SAndroid Build Coastguard Worker 
608*890232f2SAndroid Build Coastguard Worker     for (auto it = qualified_name_parts.begin();
609*890232f2SAndroid Build Coastguard Worker          it != qualified_name_parts.end(); ++it) {
610*890232f2SAndroid Build Coastguard Worker       auto &part = *it;
611*890232f2SAndroid Build Coastguard Worker 
612*890232f2SAndroid Build Coastguard Worker       for (size_t i = 0; i < part.length(); i++) {
613*890232f2SAndroid Build Coastguard Worker         if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
614*890232f2SAndroid Build Coastguard Worker           ns += "_";
615*890232f2SAndroid Build Coastguard Worker           ns += CharToLower(part[i]);
616*890232f2SAndroid Build Coastguard Worker         } else {
617*890232f2SAndroid Build Coastguard Worker           ns += CharToLower(part[i]);
618*890232f2SAndroid Build Coastguard Worker         }
619*890232f2SAndroid Build Coastguard Worker       }
620*890232f2SAndroid Build Coastguard Worker       if (it != qualified_name_parts.end() - 1) { ns += "_"; }
621*890232f2SAndroid Build Coastguard Worker     }
622*890232f2SAndroid Build Coastguard Worker 
623*890232f2SAndroid Build Coastguard Worker     return ns + "." + namer_.Type(*type.struct_def);
624*890232f2SAndroid Build Coastguard Worker   }
625*890232f2SAndroid Build Coastguard Worker 
GenImplementationGetters(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)626*890232f2SAndroid Build Coastguard Worker   void GenImplementationGetters(
627*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
628*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
629*890232f2SAndroid Build Coastguard Worker       std::string &code) {
630*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
631*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
632*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
633*890232f2SAndroid Build Coastguard Worker 
634*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
635*890232f2SAndroid Build Coastguard Worker       const std::string defaultValue = getDefaultValue(field.value);
636*890232f2SAndroid Build Coastguard Worker       const bool isNullable = defaultValue.empty() && !struct_def.fixed;
637*890232f2SAndroid Build Coastguard Worker       const std::string type_name =
638*890232f2SAndroid Build Coastguard Worker           GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
639*890232f2SAndroid Build Coastguard Worker                           isNullable, "");
640*890232f2SAndroid Build Coastguard Worker 
641*890232f2SAndroid Build Coastguard Worker       GenDocComment(field.doc_comment, "  ", code);
642*890232f2SAndroid Build Coastguard Worker 
643*890232f2SAndroid Build Coastguard Worker       code += "  " + type_name + " get " + field_name;
644*890232f2SAndroid Build Coastguard Worker       if (field.value.type.base_type == BASE_TYPE_UNION) {
645*890232f2SAndroid Build Coastguard Worker         code += " {\n";
646*890232f2SAndroid Build Coastguard Worker         code += "    switch (" + field_name + "Type?.value) {\n";
647*890232f2SAndroid Build Coastguard Worker         const auto &enum_def = *field.value.type.enum_def;
648*890232f2SAndroid Build Coastguard Worker         for (auto en_it = enum_def.Vals().begin() + 1;
649*890232f2SAndroid Build Coastguard Worker              en_it != enum_def.Vals().end(); ++en_it) {
650*890232f2SAndroid Build Coastguard Worker           const auto &ev = **en_it;
651*890232f2SAndroid Build Coastguard Worker           const auto enum_name = NamespaceAliasFromUnionType(
652*890232f2SAndroid Build Coastguard Worker               enum_def.defined_namespace, ev.union_type);
653*890232f2SAndroid Build Coastguard Worker           code += "      case " + enum_def.ToString(ev) + ": return " +
654*890232f2SAndroid Build Coastguard Worker                   enum_name + ".reader.vTableGetNullable(_bc, _bcOffset, " +
655*890232f2SAndroid Build Coastguard Worker                   NumToString(field.value.offset) + ");\n";
656*890232f2SAndroid Build Coastguard Worker         }
657*890232f2SAndroid Build Coastguard Worker         code += "      default: return null;\n";
658*890232f2SAndroid Build Coastguard Worker         code += "    }\n";
659*890232f2SAndroid Build Coastguard Worker         code += "  }\n";
660*890232f2SAndroid Build Coastguard Worker       } else {
661*890232f2SAndroid Build Coastguard Worker         code += " => ";
662*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def &&
663*890232f2SAndroid Build Coastguard Worker             field.value.type.base_type != BASE_TYPE_VECTOR) {
664*890232f2SAndroid Build Coastguard Worker           code += GenDartTypeName(field.value.type,
665*890232f2SAndroid Build Coastguard Worker                                   struct_def.defined_namespace, field) +
666*890232f2SAndroid Build Coastguard Worker                   (isNullable ? "._createOrNull(" : ".fromValue(");
667*890232f2SAndroid Build Coastguard Worker         }
668*890232f2SAndroid Build Coastguard Worker 
669*890232f2SAndroid Build Coastguard Worker         code += GenReaderTypeName(field.value.type,
670*890232f2SAndroid Build Coastguard Worker                                   struct_def.defined_namespace, field);
671*890232f2SAndroid Build Coastguard Worker         if (struct_def.fixed) {
672*890232f2SAndroid Build Coastguard Worker           code +=
673*890232f2SAndroid Build Coastguard Worker               ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
674*890232f2SAndroid Build Coastguard Worker         } else {
675*890232f2SAndroid Build Coastguard Worker           code += ".vTableGet";
676*890232f2SAndroid Build Coastguard Worker           std::string offset = NumToString(field.value.offset);
677*890232f2SAndroid Build Coastguard Worker           if (isNullable) {
678*890232f2SAndroid Build Coastguard Worker             code += "Nullable(_bc, _bcOffset, " + offset + ")";
679*890232f2SAndroid Build Coastguard Worker           } else {
680*890232f2SAndroid Build Coastguard Worker             code += "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
681*890232f2SAndroid Build Coastguard Worker           }
682*890232f2SAndroid Build Coastguard Worker         }
683*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def &&
684*890232f2SAndroid Build Coastguard Worker             field.value.type.base_type != BASE_TYPE_VECTOR) {
685*890232f2SAndroid Build Coastguard Worker           code += ")";
686*890232f2SAndroid Build Coastguard Worker         }
687*890232f2SAndroid Build Coastguard Worker         code += ";\n";
688*890232f2SAndroid Build Coastguard Worker       }
689*890232f2SAndroid Build Coastguard Worker     }
690*890232f2SAndroid Build Coastguard Worker 
691*890232f2SAndroid Build Coastguard Worker     code += "\n";
692*890232f2SAndroid Build Coastguard Worker     code += GenToString(namer_.Type(struct_def), non_deprecated_fields);
693*890232f2SAndroid Build Coastguard Worker   }
694*890232f2SAndroid Build Coastguard Worker 
GenToString(const std::string & object_name,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)695*890232f2SAndroid Build Coastguard Worker   std::string GenToString(
696*890232f2SAndroid Build Coastguard Worker       const std::string &object_name,
697*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
698*890232f2SAndroid Build Coastguard Worker     std::string code;
699*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
700*890232f2SAndroid Build Coastguard Worker     code += "  String toString() {\n";
701*890232f2SAndroid Build Coastguard Worker     code += "    return '" + object_name + "{";
702*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
703*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
704*890232f2SAndroid Build Coastguard Worker       const std::string field = namer_.Field(*it->second);
705*890232f2SAndroid Build Coastguard Worker       // We need to escape the fact that some fields have $ in the name which is
706*890232f2SAndroid Build Coastguard Worker       // also used in symbol/string substitution.
707*890232f2SAndroid Build Coastguard Worker       std::string escaped_field;
708*890232f2SAndroid Build Coastguard Worker       for (size_t i = 0; i < field.size(); i++) {
709*890232f2SAndroid Build Coastguard Worker         if (field[i] == '$') escaped_field.push_back('\\');
710*890232f2SAndroid Build Coastguard Worker         escaped_field.push_back(field[i]);
711*890232f2SAndroid Build Coastguard Worker       }
712*890232f2SAndroid Build Coastguard Worker       code += escaped_field + ": ${" + field + "}";
713*890232f2SAndroid Build Coastguard Worker       if (it != non_deprecated_fields.end() - 1) { code += ", "; }
714*890232f2SAndroid Build Coastguard Worker     }
715*890232f2SAndroid Build Coastguard Worker     code += "}';\n";
716*890232f2SAndroid Build Coastguard Worker     code += "  }\n";
717*890232f2SAndroid Build Coastguard Worker     return code;
718*890232f2SAndroid Build Coastguard Worker   }
719*890232f2SAndroid Build Coastguard Worker 
getDefaultValue(const Value & value) const720*890232f2SAndroid Build Coastguard Worker   std::string getDefaultValue(const Value &value) const {
721*890232f2SAndroid Build Coastguard Worker     if (!value.constant.empty() && value.constant != "0") {
722*890232f2SAndroid Build Coastguard Worker       if (IsBool(value.type.base_type)) {
723*890232f2SAndroid Build Coastguard Worker         return "true";
724*890232f2SAndroid Build Coastguard Worker       } else if (value.constant == "nan" || value.constant == "+nan" ||
725*890232f2SAndroid Build Coastguard Worker                  value.constant == "-nan") {
726*890232f2SAndroid Build Coastguard Worker         return "double.nan";
727*890232f2SAndroid Build Coastguard Worker       } else if (value.constant == "inf" || value.constant == "+inf") {
728*890232f2SAndroid Build Coastguard Worker         return "double.infinity";
729*890232f2SAndroid Build Coastguard Worker       } else if (value.constant == "-inf") {
730*890232f2SAndroid Build Coastguard Worker         return "double.negativeInfinity";
731*890232f2SAndroid Build Coastguard Worker       } else {
732*890232f2SAndroid Build Coastguard Worker         return value.constant;
733*890232f2SAndroid Build Coastguard Worker       }
734*890232f2SAndroid Build Coastguard Worker     } else if (IsBool(value.type.base_type)) {
735*890232f2SAndroid Build Coastguard Worker       return "false";
736*890232f2SAndroid Build Coastguard Worker     } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
737*890232f2SAndroid Build Coastguard Worker       return "0";
738*890232f2SAndroid Build Coastguard Worker     } else {
739*890232f2SAndroid Build Coastguard Worker       return "";
740*890232f2SAndroid Build Coastguard Worker     }
741*890232f2SAndroid Build Coastguard Worker   }
742*890232f2SAndroid Build Coastguard Worker 
GenReader(const StructDef & struct_def,const std::string & reader_name,std::string & code)743*890232f2SAndroid Build Coastguard Worker   void GenReader(const StructDef &struct_def, const std::string &reader_name,
744*890232f2SAndroid Build Coastguard Worker                  std::string &code) {
745*890232f2SAndroid Build Coastguard Worker     const auto struct_type = namer_.Type(struct_def);
746*890232f2SAndroid Build Coastguard Worker 
747*890232f2SAndroid Build Coastguard Worker     code += "class " + reader_name + " extends " + _kFb;
748*890232f2SAndroid Build Coastguard Worker     if (struct_def.fixed) {
749*890232f2SAndroid Build Coastguard Worker       code += ".StructReader<";
750*890232f2SAndroid Build Coastguard Worker     } else {
751*890232f2SAndroid Build Coastguard Worker       code += ".TableReader<";
752*890232f2SAndroid Build Coastguard Worker     }
753*890232f2SAndroid Build Coastguard Worker     code += struct_type + "> {\n";
754*890232f2SAndroid Build Coastguard Worker     code += "  const " + reader_name + "();\n\n";
755*890232f2SAndroid Build Coastguard Worker 
756*890232f2SAndroid Build Coastguard Worker     if (struct_def.fixed) {
757*890232f2SAndroid Build Coastguard Worker       code += "  @override\n";
758*890232f2SAndroid Build Coastguard Worker       code += "  int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
759*890232f2SAndroid Build Coastguard Worker     }
760*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
761*890232f2SAndroid Build Coastguard Worker     code += "  " + struct_type +
762*890232f2SAndroid Build Coastguard Worker             " createObject(fb.BufferContext bc, int offset) => \n    " +
763*890232f2SAndroid Build Coastguard Worker             struct_type + "._(bc, offset);\n";
764*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
765*890232f2SAndroid Build Coastguard Worker   }
766*890232f2SAndroid Build Coastguard Worker 
GenBuilder(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,const std::string & builder_name,std::string & code)767*890232f2SAndroid Build Coastguard Worker   void GenBuilder(
768*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
769*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
770*890232f2SAndroid Build Coastguard Worker       const std::string &builder_name, std::string &code) {
771*890232f2SAndroid Build Coastguard Worker     if (non_deprecated_fields.size() == 0) { return; }
772*890232f2SAndroid Build Coastguard Worker 
773*890232f2SAndroid Build Coastguard Worker     code += "class " + builder_name + " {\n";
774*890232f2SAndroid Build Coastguard Worker     code += "  " + builder_name + "(this.fbBuilder);\n\n";
775*890232f2SAndroid Build Coastguard Worker     code += "  final " + _kFb + ".Builder fbBuilder;\n\n";
776*890232f2SAndroid Build Coastguard Worker 
777*890232f2SAndroid Build Coastguard Worker     if (struct_def.fixed) {
778*890232f2SAndroid Build Coastguard Worker       StructBuilderBody(struct_def, non_deprecated_fields, code);
779*890232f2SAndroid Build Coastguard Worker     } else {
780*890232f2SAndroid Build Coastguard Worker       TableBuilderBody(struct_def, non_deprecated_fields, code);
781*890232f2SAndroid Build Coastguard Worker     }
782*890232f2SAndroid Build Coastguard Worker 
783*890232f2SAndroid Build Coastguard Worker     code += "}\n\n";
784*890232f2SAndroid Build Coastguard Worker   }
785*890232f2SAndroid Build Coastguard Worker 
StructBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)786*890232f2SAndroid Build Coastguard Worker   void StructBuilderBody(
787*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
788*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
789*890232f2SAndroid Build Coastguard Worker       std::string &code) {
790*890232f2SAndroid Build Coastguard Worker     code += "  int finish(";
791*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
792*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
793*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
794*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
795*890232f2SAndroid Build Coastguard Worker 
796*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
797*890232f2SAndroid Build Coastguard Worker         code += "fb.StructBuilder";
798*890232f2SAndroid Build Coastguard Worker       } else {
799*890232f2SAndroid Build Coastguard Worker         code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
800*890232f2SAndroid Build Coastguard Worker                                 field);
801*890232f2SAndroid Build Coastguard Worker       }
802*890232f2SAndroid Build Coastguard Worker       code += " " + field_name;
803*890232f2SAndroid Build Coastguard Worker       if (it != non_deprecated_fields.end() - 1) { code += ", "; }
804*890232f2SAndroid Build Coastguard Worker     }
805*890232f2SAndroid Build Coastguard Worker     code += ") {\n";
806*890232f2SAndroid Build Coastguard Worker 
807*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.rbegin();
808*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.rend(); ++it) {
809*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
810*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
811*890232f2SAndroid Build Coastguard Worker 
812*890232f2SAndroid Build Coastguard Worker       if (field.padding) {
813*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
814*890232f2SAndroid Build Coastguard Worker       }
815*890232f2SAndroid Build Coastguard Worker 
816*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
817*890232f2SAndroid Build Coastguard Worker         code += "    " + field_name + "();\n";
818*890232f2SAndroid Build Coastguard Worker       } else {
819*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.put" + GenType(field.value.type) + "(";
820*890232f2SAndroid Build Coastguard Worker         code += field_name;
821*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def) { code += ".value"; }
822*890232f2SAndroid Build Coastguard Worker         code += ");\n";
823*890232f2SAndroid Build Coastguard Worker       }
824*890232f2SAndroid Build Coastguard Worker     }
825*890232f2SAndroid Build Coastguard Worker     code += "    return fbBuilder.offset;\n";
826*890232f2SAndroid Build Coastguard Worker     code += "  }\n\n";
827*890232f2SAndroid Build Coastguard Worker   }
828*890232f2SAndroid Build Coastguard Worker 
TableBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)829*890232f2SAndroid Build Coastguard Worker   void TableBuilderBody(
830*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
831*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
832*890232f2SAndroid Build Coastguard Worker       std::string &code) {
833*890232f2SAndroid Build Coastguard Worker     code += "  void begin() {\n";
834*890232f2SAndroid Build Coastguard Worker     code += "    fbBuilder.startTable(" +
835*890232f2SAndroid Build Coastguard Worker             NumToString(struct_def.fields.vec.size()) + ");\n";
836*890232f2SAndroid Build Coastguard Worker     code += "  }\n\n";
837*890232f2SAndroid Build Coastguard Worker 
838*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
839*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
840*890232f2SAndroid Build Coastguard Worker       const auto &field = *it->second;
841*890232f2SAndroid Build Coastguard Worker       const auto offset = it->first;
842*890232f2SAndroid Build Coastguard Worker       const std::string add_field = namer_.Method("add", field);
843*890232f2SAndroid Build Coastguard Worker       const std::string field_var = namer_.Variable(field);
844*890232f2SAndroid Build Coastguard Worker 
845*890232f2SAndroid Build Coastguard Worker       if (IsScalar(field.value.type.base_type)) {
846*890232f2SAndroid Build Coastguard Worker         code += "  int " + add_field + "(";
847*890232f2SAndroid Build Coastguard Worker         code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
848*890232f2SAndroid Build Coastguard Worker                                 field);
849*890232f2SAndroid Build Coastguard Worker         code += "? " + field_var + ") {\n";
850*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
851*890232f2SAndroid Build Coastguard Worker                 NumToString(offset) + ", ";
852*890232f2SAndroid Build Coastguard Worker         code += field_var;
853*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def) { code += "?.value"; }
854*890232f2SAndroid Build Coastguard Worker         code += ");\n";
855*890232f2SAndroid Build Coastguard Worker       } else if (IsStruct(field.value.type)) {
856*890232f2SAndroid Build Coastguard Worker         code += "  int " + add_field + "(int offset) {\n";
857*890232f2SAndroid Build Coastguard Worker         code +=
858*890232f2SAndroid Build Coastguard Worker             "    fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
859*890232f2SAndroid Build Coastguard Worker       } else {
860*890232f2SAndroid Build Coastguard Worker         code += "  int " + add_field + "Offset(int? offset) {\n";
861*890232f2SAndroid Build Coastguard Worker         code +=
862*890232f2SAndroid Build Coastguard Worker             "    fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
863*890232f2SAndroid Build Coastguard Worker       }
864*890232f2SAndroid Build Coastguard Worker       code += "    return fbBuilder.offset;\n";
865*890232f2SAndroid Build Coastguard Worker       code += "  }\n";
866*890232f2SAndroid Build Coastguard Worker     }
867*890232f2SAndroid Build Coastguard Worker 
868*890232f2SAndroid Build Coastguard Worker     code += "\n";
869*890232f2SAndroid Build Coastguard Worker     code += "  int finish() {\n";
870*890232f2SAndroid Build Coastguard Worker     code += "    return fbBuilder.endTable();\n";
871*890232f2SAndroid Build Coastguard Worker     code += "  }\n";
872*890232f2SAndroid Build Coastguard Worker   }
873*890232f2SAndroid Build Coastguard Worker 
GenObjectBuilder(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,const std::string & builder_name,std::string & code)874*890232f2SAndroid Build Coastguard Worker   void GenObjectBuilder(
875*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
876*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
877*890232f2SAndroid Build Coastguard Worker       const std::string &builder_name, std::string &code) {
878*890232f2SAndroid Build Coastguard Worker     code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
879*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
880*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
881*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
882*890232f2SAndroid Build Coastguard Worker 
883*890232f2SAndroid Build Coastguard Worker       code += "  final " +
884*890232f2SAndroid Build Coastguard Worker               GenDartTypeName(field.value.type, struct_def.defined_namespace,
885*890232f2SAndroid Build Coastguard Worker                               field, !struct_def.fixed, "ObjectBuilder") +
886*890232f2SAndroid Build Coastguard Worker               " _" + namer_.Variable(field) + ";\n";
887*890232f2SAndroid Build Coastguard Worker     }
888*890232f2SAndroid Build Coastguard Worker     code += "\n";
889*890232f2SAndroid Build Coastguard Worker     code += "  " + builder_name + "(";
890*890232f2SAndroid Build Coastguard Worker 
891*890232f2SAndroid Build Coastguard Worker     if (non_deprecated_fields.size() != 0) {
892*890232f2SAndroid Build Coastguard Worker       code += "{\n";
893*890232f2SAndroid Build Coastguard Worker       for (auto it = non_deprecated_fields.begin();
894*890232f2SAndroid Build Coastguard Worker            it != non_deprecated_fields.end(); ++it) {
895*890232f2SAndroid Build Coastguard Worker         const FieldDef &field = *it->second;
896*890232f2SAndroid Build Coastguard Worker 
897*890232f2SAndroid Build Coastguard Worker         code += "    ";
898*890232f2SAndroid Build Coastguard Worker         code += (struct_def.fixed ? "required " : "") +
899*890232f2SAndroid Build Coastguard Worker                 GenDartTypeName(field.value.type, struct_def.defined_namespace,
900*890232f2SAndroid Build Coastguard Worker                                 field, !struct_def.fixed, "ObjectBuilder") +
901*890232f2SAndroid Build Coastguard Worker                 " " + namer_.Variable(field) + ",\n";
902*890232f2SAndroid Build Coastguard Worker       }
903*890232f2SAndroid Build Coastguard Worker       code += "  })\n";
904*890232f2SAndroid Build Coastguard Worker       code += "      : ";
905*890232f2SAndroid Build Coastguard Worker       for (auto it = non_deprecated_fields.begin();
906*890232f2SAndroid Build Coastguard Worker            it != non_deprecated_fields.end(); ++it) {
907*890232f2SAndroid Build Coastguard Worker         const FieldDef &field = *it->second;
908*890232f2SAndroid Build Coastguard Worker 
909*890232f2SAndroid Build Coastguard Worker         code += "_" + namer_.Variable(field) + " = " + namer_.Variable(field);
910*890232f2SAndroid Build Coastguard Worker         if (it == non_deprecated_fields.end() - 1) {
911*890232f2SAndroid Build Coastguard Worker           code += ";\n\n";
912*890232f2SAndroid Build Coastguard Worker         } else {
913*890232f2SAndroid Build Coastguard Worker           code += ",\n        ";
914*890232f2SAndroid Build Coastguard Worker         }
915*890232f2SAndroid Build Coastguard Worker       }
916*890232f2SAndroid Build Coastguard Worker     } else {
917*890232f2SAndroid Build Coastguard Worker       code += ");\n\n";
918*890232f2SAndroid Build Coastguard Worker     }
919*890232f2SAndroid Build Coastguard Worker 
920*890232f2SAndroid Build Coastguard Worker     code += "  /// Finish building, and store into the [fbBuilder].\n";
921*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
922*890232f2SAndroid Build Coastguard Worker     code += "  int finish(" + _kFb + ".Builder fbBuilder) {\n";
923*890232f2SAndroid Build Coastguard Worker     code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields);
924*890232f2SAndroid Build Coastguard Worker     code += "  }\n\n";
925*890232f2SAndroid Build Coastguard Worker 
926*890232f2SAndroid Build Coastguard Worker     code += "  /// Convenience method to serialize to byte list.\n";
927*890232f2SAndroid Build Coastguard Worker     code += "  @override\n";
928*890232f2SAndroid Build Coastguard Worker     code += "  Uint8List toBytes([String? fileIdentifier]) {\n";
929*890232f2SAndroid Build Coastguard Worker     code += "    final fbBuilder = " + _kFb +
930*890232f2SAndroid Build Coastguard Worker             ".Builder(deduplicateTables: false);\n";
931*890232f2SAndroid Build Coastguard Worker     code += "    fbBuilder.finish(finish(fbBuilder), fileIdentifier);\n";
932*890232f2SAndroid Build Coastguard Worker     code += "    return fbBuilder.buffer;\n";
933*890232f2SAndroid Build Coastguard Worker     code += "  }\n";
934*890232f2SAndroid Build Coastguard Worker     code += "}\n";
935*890232f2SAndroid Build Coastguard Worker   }
936*890232f2SAndroid Build Coastguard Worker 
GenObjectBuilderImplementation(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)937*890232f2SAndroid Build Coastguard Worker   std::string GenObjectBuilderImplementation(
938*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
939*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
940*890232f2SAndroid Build Coastguard Worker       bool prependUnderscore = true, bool pack = false) {
941*890232f2SAndroid Build Coastguard Worker     std::string code;
942*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
943*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
944*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
945*890232f2SAndroid Build Coastguard Worker 
946*890232f2SAndroid Build Coastguard Worker       if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
947*890232f2SAndroid Build Coastguard Worker         continue;
948*890232f2SAndroid Build Coastguard Worker 
949*890232f2SAndroid Build Coastguard Worker       std::string offset_name = namer_.Variable(field) + "Offset";
950*890232f2SAndroid Build Coastguard Worker       std::string field_name =
951*890232f2SAndroid Build Coastguard Worker           (prependUnderscore ? "_" : "") + namer_.Variable(field);
952*890232f2SAndroid Build Coastguard Worker       // custom handling for fixed-sized struct in pack()
953*890232f2SAndroid Build Coastguard Worker       if (pack && IsVector(field.value.type) &&
954*890232f2SAndroid Build Coastguard Worker           field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
955*890232f2SAndroid Build Coastguard Worker           field.value.type.struct_def->fixed) {
956*890232f2SAndroid Build Coastguard Worker         code += "    int? " + offset_name + ";\n";
957*890232f2SAndroid Build Coastguard Worker         code += "    if (" + field_name + " != null) {\n";
958*890232f2SAndroid Build Coastguard Worker         code +=
959*890232f2SAndroid Build Coastguard Worker             "      for (var e in " + field_name + "!) { e.pack(fbBuilder); }\n";
960*890232f2SAndroid Build Coastguard Worker         code += "      " + namer_.Variable(field) +
961*890232f2SAndroid Build Coastguard Worker                 "Offset = fbBuilder.endStructVector(" + field_name +
962*890232f2SAndroid Build Coastguard Worker                 "!.length);\n";
963*890232f2SAndroid Build Coastguard Worker         code += "    }\n";
964*890232f2SAndroid Build Coastguard Worker         continue;
965*890232f2SAndroid Build Coastguard Worker       }
966*890232f2SAndroid Build Coastguard Worker 
967*890232f2SAndroid Build Coastguard Worker       code += "    final int? " + offset_name;
968*890232f2SAndroid Build Coastguard Worker       if (IsVector(field.value.type)) {
969*890232f2SAndroid Build Coastguard Worker         code += " = " + field_name + " == null ? null\n";
970*890232f2SAndroid Build Coastguard Worker         code += "        : fbBuilder.writeList";
971*890232f2SAndroid Build Coastguard Worker         switch (field.value.type.VectorType().base_type) {
972*890232f2SAndroid Build Coastguard Worker           case BASE_TYPE_STRING:
973*890232f2SAndroid Build Coastguard Worker             code +=
974*890232f2SAndroid Build Coastguard Worker                 "(" + field_name + "!.map(fbBuilder.writeString).toList());\n";
975*890232f2SAndroid Build Coastguard Worker             break;
976*890232f2SAndroid Build Coastguard Worker           case BASE_TYPE_STRUCT:
977*890232f2SAndroid Build Coastguard Worker             if (field.value.type.struct_def->fixed) {
978*890232f2SAndroid Build Coastguard Worker               code += "OfStructs(" + field_name + "!);\n";
979*890232f2SAndroid Build Coastguard Worker             } else {
980*890232f2SAndroid Build Coastguard Worker               code += "(" + field_name + "!.map((b) => b." +
981*890232f2SAndroid Build Coastguard Worker                       (pack ? "pack" : "getOrCreateOffset") +
982*890232f2SAndroid Build Coastguard Worker                       "(fbBuilder)).toList());\n";
983*890232f2SAndroid Build Coastguard Worker             }
984*890232f2SAndroid Build Coastguard Worker             break;
985*890232f2SAndroid Build Coastguard Worker           default:
986*890232f2SAndroid Build Coastguard Worker             code +=
987*890232f2SAndroid Build Coastguard Worker                 GenType(field.value.type.VectorType()) + "(" + field_name + "!";
988*890232f2SAndroid Build Coastguard Worker             if (field.value.type.enum_def) {
989*890232f2SAndroid Build Coastguard Worker               code += ".map((f) => f.value).toList()";
990*890232f2SAndroid Build Coastguard Worker             }
991*890232f2SAndroid Build Coastguard Worker             code += ");\n";
992*890232f2SAndroid Build Coastguard Worker         }
993*890232f2SAndroid Build Coastguard Worker       } else if (IsString(field.value.type)) {
994*890232f2SAndroid Build Coastguard Worker         code += " = " + field_name + " == null ? null\n";
995*890232f2SAndroid Build Coastguard Worker         code += "        : fbBuilder.writeString(" + field_name + "!);\n";
996*890232f2SAndroid Build Coastguard Worker       } else {
997*890232f2SAndroid Build Coastguard Worker         code += " = " + field_name + "?." +
998*890232f2SAndroid Build Coastguard Worker                 (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n";
999*890232f2SAndroid Build Coastguard Worker       }
1000*890232f2SAndroid Build Coastguard Worker     }
1001*890232f2SAndroid Build Coastguard Worker 
1002*890232f2SAndroid Build Coastguard Worker     if (struct_def.fixed) {
1003*890232f2SAndroid Build Coastguard Worker       code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore,
1004*890232f2SAndroid Build Coastguard Worker                                       pack);
1005*890232f2SAndroid Build Coastguard Worker     } else {
1006*890232f2SAndroid Build Coastguard Worker       code += TableObjectBuilderBody(struct_def, non_deprecated_fields,
1007*890232f2SAndroid Build Coastguard Worker                                      prependUnderscore, pack);
1008*890232f2SAndroid Build Coastguard Worker     }
1009*890232f2SAndroid Build Coastguard Worker     return code;
1010*890232f2SAndroid Build Coastguard Worker   }
1011*890232f2SAndroid Build Coastguard Worker 
StructObjectBuilderBody(const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)1012*890232f2SAndroid Build Coastguard Worker   std::string StructObjectBuilderBody(
1013*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1014*890232f2SAndroid Build Coastguard Worker       bool prependUnderscore = true, bool pack = false) {
1015*890232f2SAndroid Build Coastguard Worker     std::string code;
1016*890232f2SAndroid Build Coastguard Worker 
1017*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.rbegin();
1018*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.rend(); ++it) {
1019*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
1020*890232f2SAndroid Build Coastguard Worker       const std::string field_name = namer_.Field(field);
1021*890232f2SAndroid Build Coastguard Worker 
1022*890232f2SAndroid Build Coastguard Worker       if (field.padding) {
1023*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
1024*890232f2SAndroid Build Coastguard Worker       }
1025*890232f2SAndroid Build Coastguard Worker 
1026*890232f2SAndroid Build Coastguard Worker       if (IsStruct(field.value.type)) {
1027*890232f2SAndroid Build Coastguard Worker         code += "    ";
1028*890232f2SAndroid Build Coastguard Worker         if (prependUnderscore) { code += "_"; }
1029*890232f2SAndroid Build Coastguard Worker         code += field_name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n";
1030*890232f2SAndroid Build Coastguard Worker       } else {
1031*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.put" + GenType(field.value.type) + "(";
1032*890232f2SAndroid Build Coastguard Worker         if (prependUnderscore) { code += "_"; }
1033*890232f2SAndroid Build Coastguard Worker         code += field_name;
1034*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def) { code += ".value"; }
1035*890232f2SAndroid Build Coastguard Worker         code += ");\n";
1036*890232f2SAndroid Build Coastguard Worker       }
1037*890232f2SAndroid Build Coastguard Worker     }
1038*890232f2SAndroid Build Coastguard Worker 
1039*890232f2SAndroid Build Coastguard Worker     code += "    return fbBuilder.offset;\n";
1040*890232f2SAndroid Build Coastguard Worker     return code;
1041*890232f2SAndroid Build Coastguard Worker   }
1042*890232f2SAndroid Build Coastguard Worker 
TableObjectBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)1043*890232f2SAndroid Build Coastguard Worker   std::string TableObjectBuilderBody(
1044*890232f2SAndroid Build Coastguard Worker       const StructDef &struct_def,
1045*890232f2SAndroid Build Coastguard Worker       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1046*890232f2SAndroid Build Coastguard Worker       bool prependUnderscore = true, bool pack = false) {
1047*890232f2SAndroid Build Coastguard Worker     std::string code;
1048*890232f2SAndroid Build Coastguard Worker     code += "    fbBuilder.startTable(" +
1049*890232f2SAndroid Build Coastguard Worker             NumToString(struct_def.fields.vec.size()) + ");\n";
1050*890232f2SAndroid Build Coastguard Worker 
1051*890232f2SAndroid Build Coastguard Worker     for (auto it = non_deprecated_fields.begin();
1052*890232f2SAndroid Build Coastguard Worker          it != non_deprecated_fields.end(); ++it) {
1053*890232f2SAndroid Build Coastguard Worker       const FieldDef &field = *it->second;
1054*890232f2SAndroid Build Coastguard Worker       auto offset = it->first;
1055*890232f2SAndroid Build Coastguard Worker 
1056*890232f2SAndroid Build Coastguard Worker       std::string field_var =
1057*890232f2SAndroid Build Coastguard Worker           (prependUnderscore ? "_" : "") + namer_.Variable(field);
1058*890232f2SAndroid Build Coastguard Worker 
1059*890232f2SAndroid Build Coastguard Worker       if (IsScalar(field.value.type.base_type)) {
1060*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
1061*890232f2SAndroid Build Coastguard Worker                 NumToString(offset) + ", " + field_var;
1062*890232f2SAndroid Build Coastguard Worker         if (field.value.type.enum_def) {
1063*890232f2SAndroid Build Coastguard Worker           bool isNullable = getDefaultValue(field.value).empty();
1064*890232f2SAndroid Build Coastguard Worker           code += (isNullable || !pack) ? "?.value" : ".value";
1065*890232f2SAndroid Build Coastguard Worker         }
1066*890232f2SAndroid Build Coastguard Worker         code += ");\n";
1067*890232f2SAndroid Build Coastguard Worker       } else if (IsStruct(field.value.type)) {
1068*890232f2SAndroid Build Coastguard Worker         code += "    if (" + field_var + " != null) {\n";
1069*890232f2SAndroid Build Coastguard Worker         code += "      fbBuilder.addStruct(" + NumToString(offset) + ", " +
1070*890232f2SAndroid Build Coastguard Worker                 field_var + (pack ? "!.pack" : "!.finish") + "(fbBuilder));\n";
1071*890232f2SAndroid Build Coastguard Worker         code += "    }\n";
1072*890232f2SAndroid Build Coastguard Worker       } else {
1073*890232f2SAndroid Build Coastguard Worker         code += "    fbBuilder.addOffset(" + NumToString(offset) + ", " +
1074*890232f2SAndroid Build Coastguard Worker                 namer_.Variable(field) + "Offset);\n";
1075*890232f2SAndroid Build Coastguard Worker       }
1076*890232f2SAndroid Build Coastguard Worker     }
1077*890232f2SAndroid Build Coastguard Worker     code += "    return fbBuilder.endTable();\n";
1078*890232f2SAndroid Build Coastguard Worker     return code;
1079*890232f2SAndroid Build Coastguard Worker   }
1080*890232f2SAndroid Build Coastguard Worker 
1081*890232f2SAndroid Build Coastguard Worker   const IdlNamer namer_;
1082*890232f2SAndroid Build Coastguard Worker };
1083*890232f2SAndroid Build Coastguard Worker }  // namespace dart
1084*890232f2SAndroid Build Coastguard Worker 
GenerateDart(const Parser & parser,const std::string & path,const std::string & file_name)1085*890232f2SAndroid Build Coastguard Worker bool GenerateDart(const Parser &parser, const std::string &path,
1086*890232f2SAndroid Build Coastguard Worker                   const std::string &file_name) {
1087*890232f2SAndroid Build Coastguard Worker   dart::DartGenerator generator(parser, path, file_name);
1088*890232f2SAndroid Build Coastguard Worker   return generator.generate();
1089*890232f2SAndroid Build Coastguard Worker }
1090*890232f2SAndroid Build Coastguard Worker 
DartMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1091*890232f2SAndroid Build Coastguard Worker std::string DartMakeRule(const Parser &parser, const std::string &path,
1092*890232f2SAndroid Build Coastguard Worker                          const std::string &file_name) {
1093*890232f2SAndroid Build Coastguard Worker   auto filebase =
1094*890232f2SAndroid Build Coastguard Worker       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1095*890232f2SAndroid Build Coastguard Worker   dart::DartGenerator generator(parser, path, file_name);
1096*890232f2SAndroid Build Coastguard Worker   auto make_rule = generator.Filename("") + ": ";
1097*890232f2SAndroid Build Coastguard Worker 
1098*890232f2SAndroid Build Coastguard Worker   auto included_files = parser.GetIncludedFilesRecursive(file_name);
1099*890232f2SAndroid Build Coastguard Worker   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1100*890232f2SAndroid Build Coastguard Worker     make_rule += " " + *it;
1101*890232f2SAndroid Build Coastguard Worker   }
1102*890232f2SAndroid Build Coastguard Worker   return make_rule;
1103*890232f2SAndroid Build Coastguard Worker }
1104*890232f2SAndroid Build Coastguard Worker 
1105*890232f2SAndroid Build Coastguard Worker }  // namespace flatbuffers
1106