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