• 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\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     // The flatbuffer schema language allows bit flag enums to potentially have
219     // a default value of zero, even if it's not a valid enum value...
220     const bool permit_zero = is_bit_flags;
221 
222     code += "class " + enum_type + " {\n";
223     code += "  final int value;\n";
224     code += "  const " + enum_type + "._(this.value);\n\n";
225     code += "  factory " + enum_type + ".fromValue(int value) {\n";
226     code += "    final result = values[value];\n";
227     code += "    if (result == null) {\n";
228     if (permit_zero) {
229       code += "      if (value == 0) {\n";
230       code += "        return " + enum_type + "._(0);\n";
231       code += "      } else {\n";
232     }
233     code += "        throw StateError('Invalid value $value for bit flag enum ";
234     code += enum_type + "');\n";
235     if (permit_zero) { code += "      }\n"; }
236     code += "    }\n";
237 
238     code += "    return result;\n";
239     code += "  }\n\n";
240 
241     code += "  static " + enum_type + "? _createOrNull(int? value) => \n";
242     code +=
243         "      value == null ? null : " + enum_type + ".fromValue(value);\n\n";
244 
245     // this is meaningless for bit_flags
246     // however, note that unlike "regular" dart enums this enum can still have
247     // holes.
248     if (!is_bit_flags) {
249       code += "  static const int minValue = " +
250               enum_def.ToString(*enum_def.MinValue()) + ";\n";
251       code += "  static const int maxValue = " +
252               enum_def.ToString(*enum_def.MaxValue()) + ";\n";
253     }
254 
255     code +=
256         "  static bool containsValue(int value) =>"
257         " values.containsKey(value);\n\n";
258 
259     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
260       auto &ev = **it;
261       const auto enum_var = namer_.Variant(ev);
262 
263       if (!ev.doc_comment.empty()) {
264         if (it != enum_def.Vals().begin()) { code += '\n'; }
265         GenDocComment(ev.doc_comment, "  ", code);
266       }
267       code += "  static const " + enum_type + " " + enum_var + " = " +
268               enum_type + "._(" + enum_def.ToString(ev) + ");\n";
269     }
270 
271     code += "  static const Map<int, " + enum_type + "> values = {\n";
272     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
273       auto &ev = **it;
274       const auto enum_var = namer_.Variant(ev);
275       if (it != enum_def.Vals().begin()) code += ",\n";
276       code += "    " + enum_def.ToString(ev) + ": " + enum_var;
277     }
278     code += "};\n\n";
279 
280     code += "  static const " + _kFb + ".Reader<" + enum_type + "> reader = _" +
281             enum_type + "Reader();\n\n";
282     code += "  @override\n";
283     code += "  String toString() {\n";
284     code += "    return '" + enum_type + "{value: $value}';\n";
285     code += "  }\n";
286     code += "}\n\n";
287 
288     GenEnumReader(enum_def, enum_type, code);
289   }
290 
GenEnumReader(EnumDef & enum_def,const std::string & enum_type,std::string & code)291   void GenEnumReader(EnumDef &enum_def, const std::string &enum_type,
292                      std::string &code) {
293     code += "class _" + enum_type + "Reader extends " + _kFb + ".Reader<" +
294             enum_type + "> {\n";
295     code += "  const _" + enum_type + "Reader();\n\n";
296     code += "  @override\n";
297     code += "  int get size => " + EnumSize(enum_def.underlying_type) + ";\n\n";
298     code += "  @override\n";
299     code += "  " + enum_type + " read(" + _kFb +
300             ".BufferContext bc, int offset) =>\n";
301     code += "      " + enum_type + ".fromValue(const " + _kFb + "." +
302             GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
303     code += "}\n\n";
304   }
305 
GenType(const Type & type)306   std::string GenType(const Type &type) {
307     switch (type.base_type) {
308       case BASE_TYPE_BOOL: return "Bool";
309       case BASE_TYPE_CHAR: return "Int8";
310       case BASE_TYPE_UTYPE:
311       case BASE_TYPE_UCHAR: return "Uint8";
312       case BASE_TYPE_SHORT: return "Int16";
313       case BASE_TYPE_USHORT: return "Uint16";
314       case BASE_TYPE_INT: return "Int32";
315       case BASE_TYPE_UINT: return "Uint32";
316       case BASE_TYPE_LONG: return "Int64";
317       case BASE_TYPE_ULONG: return "Uint64";
318       case BASE_TYPE_FLOAT: return "Float32";
319       case BASE_TYPE_DOUBLE: return "Float64";
320       case BASE_TYPE_STRING: return "String";
321       case BASE_TYPE_VECTOR: return GenType(type.VectorType());
322       case BASE_TYPE_STRUCT: return namer_.Type(*type.struct_def);
323       case BASE_TYPE_UNION: return namer_.Type(*type.enum_def) + "TypeId";
324       default: return "Table";
325     }
326   }
327 
EnumSize(const Type & type)328   static std::string EnumSize(const Type &type) {
329     switch (type.base_type) {
330       case BASE_TYPE_BOOL:
331       case BASE_TYPE_CHAR:
332       case BASE_TYPE_UTYPE:
333       case BASE_TYPE_UCHAR: return "1";
334       case BASE_TYPE_SHORT:
335       case BASE_TYPE_USHORT: return "2";
336       case BASE_TYPE_INT:
337       case BASE_TYPE_UINT:
338       case BASE_TYPE_FLOAT: return "4";
339       case BASE_TYPE_LONG:
340       case BASE_TYPE_ULONG:
341       case BASE_TYPE_DOUBLE: return "8";
342       default: return "1";
343     }
344   }
345 
GenReaderTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,bool parent_is_vector=false,bool lazy=true,bool constConstruct=true)346   std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
347                                 const FieldDef &def,
348                                 bool parent_is_vector = false, bool lazy = true,
349                                 bool constConstruct = true) {
350     std::string prefix = (constConstruct ? "const " : "") + _kFb;
351     if (type.base_type == BASE_TYPE_BOOL) {
352       return prefix + ".BoolReader()";
353     } else if (IsVector(type)) {
354       if (!type.VectorType().enum_def) {
355         if (type.VectorType().base_type == BASE_TYPE_CHAR) {
356           return prefix + ".Int8ListReader(" + (lazy ? ")" : "lazy: false)");
357         }
358         if (type.VectorType().base_type == BASE_TYPE_UCHAR) {
359           return prefix + ".Uint8ListReader(" + (lazy ? ")" : "lazy: false)");
360         }
361       }
362       return prefix + ".ListReader<" +
363              GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
364              GenReaderTypeName(type.VectorType(), current_namespace, def, true,
365                                true, false) +
366              (lazy ? ")" : ", lazy: false)");
367     } else if (IsString(type)) {
368       return prefix + ".StringReader()";
369     }
370     if (IsScalar(type.base_type)) {
371       if (type.enum_def && parent_is_vector) {
372         return GenDartTypeName(type, current_namespace, def) + ".reader";
373       }
374       return prefix + "." + GenType(type) + "Reader()";
375     } else {
376       return GenDartTypeName(type, current_namespace, def) + ".reader";
377     }
378   }
379 
GenDartTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,std::string struct_type_suffix="")380   std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
381                               const FieldDef &def,
382                               std::string struct_type_suffix = "") {
383     if (type.enum_def) {
384       if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
385         return namer_.Type(*type.enum_def) + "TypeId";
386       } else if (type.enum_def->is_union) {
387         return "dynamic";
388       } else if (type.base_type != BASE_TYPE_VECTOR) {
389         return namer_.Type(*type.enum_def);
390       }
391     }
392 
393     switch (type.base_type) {
394       case BASE_TYPE_BOOL: return "bool";
395       case BASE_TYPE_LONG:
396       case BASE_TYPE_ULONG:
397       case BASE_TYPE_INT:
398       case BASE_TYPE_UINT:
399       case BASE_TYPE_SHORT:
400       case BASE_TYPE_USHORT:
401       case BASE_TYPE_CHAR:
402       case BASE_TYPE_UCHAR: return "int";
403       case BASE_TYPE_FLOAT:
404       case BASE_TYPE_DOUBLE: return "double";
405       case BASE_TYPE_STRING: return "String";
406       case BASE_TYPE_STRUCT:
407         return MaybeWrapNamespace(
408             namer_.Type(*type.struct_def) + struct_type_suffix,
409             current_namespace, def);
410       case BASE_TYPE_VECTOR:
411         return "List<" +
412                GenDartTypeName(type.VectorType(), current_namespace, def,
413                                struct_type_suffix) +
414                ">";
415       default: assert(0); return "dynamic";
416     }
417   }
418 
GenDartTypeName(const Type & type,Namespace * current_namespace,const FieldDef & def,bool nullable,std::string struct_type_suffix)419   std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
420                               const FieldDef &def, bool nullable,
421                               std::string struct_type_suffix) {
422     std::string typeName =
423         GenDartTypeName(type, current_namespace, def, struct_type_suffix);
424     if (nullable && typeName != "dynamic") typeName += "?";
425     return typeName;
426   }
427 
MaybeWrapNamespace(const std::string & type_name,Namespace * current_ns,const FieldDef & field) const428   std::string MaybeWrapNamespace(const std::string &type_name,
429                                  Namespace *current_ns,
430                                  const FieldDef &field) const {
431     const std::string current_namespace = namer_.Namespace(*current_ns);
432     const std::string field_namespace =
433         field.value.type.struct_def
434             ? namer_.Namespace(*field.value.type.struct_def->defined_namespace)
435         : field.value.type.enum_def
436             ? namer_.Namespace(*field.value.type.enum_def->defined_namespace)
437             : "";
438 
439     if (field_namespace != "" && field_namespace != current_namespace) {
440       return ImportAliasName(field_namespace) + "." + type_name;
441     } else {
442       return type_name;
443     }
444   }
445 
446   // Generate an accessor struct with constructor for a flatbuffers struct.
GenStruct(const StructDef & struct_def,namespace_code_map & namespace_code)447   void GenStruct(const StructDef &struct_def,
448                  namespace_code_map &namespace_code) {
449     if (struct_def.generated) return;
450 
451     std::string &code =
452         namespace_code[namer_.Namespace(*struct_def.defined_namespace)];
453 
454     const auto &struct_type = namer_.Type(struct_def);
455 
456     // Emit constructor
457 
458     GenDocComment(struct_def.doc_comment, "", code);
459 
460     auto reader_name = "_" + struct_type + "Reader";
461     auto builder_name = struct_type + "Builder";
462     auto object_builder_name = struct_type + "ObjectBuilder";
463 
464     std::string reader_code, builder_code;
465 
466     code += "class " + struct_type + " {\n";
467 
468     code += "  " + struct_type + "._(this._bc, this._bcOffset);\n";
469     if (!struct_def.fixed) {
470       code += "  factory " + struct_type + "(List<int> bytes) {\n";
471       code +=
472           "    final rootRef = " + _kFb + ".BufferContext.fromBytes(bytes);\n";
473       code += "    return reader.read(rootRef, 0);\n";
474       code += "  }\n";
475     }
476 
477     code += "\n";
478     code += "  static const " + _kFb + ".Reader<" + struct_type +
479             "> reader = " + reader_name + "();\n\n";
480 
481     code += "  final " + _kFb + ".BufferContext _bc;\n";
482     code += "  final int _bcOffset;\n\n";
483 
484     std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
485     for (auto it = struct_def.fields.vec.begin();
486          it != struct_def.fields.vec.end(); ++it) {
487       FieldDef &field = **it;
488       if (field.deprecated) continue;
489       auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
490       non_deprecated_fields.push_back(std::make_pair(offset, &field));
491     }
492 
493     GenImplementationGetters(struct_def, non_deprecated_fields, code);
494 
495     if (parser_.opts.generate_object_based_api) {
496       code +=
497           "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields);
498 
499       code += "\n  static int pack(fb.Builder fbBuilder, " +
500               namer_.ObjectType(struct_def) + "? object) {\n";
501       code += "    if (object == null) return 0;\n";
502       code += "    return object.pack(fbBuilder);\n";
503       code += "  }\n";
504     }
505 
506     code += "}\n\n";
507 
508     if (parser_.opts.generate_object_based_api) {
509       code += GenStructObjectAPI(struct_def, non_deprecated_fields);
510     }
511 
512     GenReader(struct_def, reader_name, reader_code);
513     GenBuilder(struct_def, non_deprecated_fields, builder_name, builder_code);
514     GenObjectBuilder(struct_def, non_deprecated_fields, object_builder_name,
515                      builder_code);
516 
517     code += reader_code;
518     code += builder_code;
519   }
520 
521   // 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)522   std::string GenStructObjectAPI(
523       const StructDef &struct_def,
524       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
525     std::string code;
526     GenDocComment(struct_def.doc_comment, "", code);
527 
528     std::string object_type = namer_.ObjectType(struct_def);
529     code += "class " + object_type + " implements " + _kFb + ".Packable {\n";
530 
531     std::string constructor_args;
532     for (auto it = non_deprecated_fields.begin();
533          it != non_deprecated_fields.end(); ++it) {
534       const FieldDef &field = *it->second;
535 
536       const std::string field_name = namer_.Field(field);
537       const std::string defaultValue = getDefaultValue(field.value);
538       const std::string type_name =
539           GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
540                           defaultValue.empty() && !struct_def.fixed, "T");
541 
542       GenDocComment(field.doc_comment, "  ", code);
543       code += "  " + type_name + " " + field_name + ";\n";
544 
545       if (!constructor_args.empty()) constructor_args += ",\n";
546       constructor_args += "      ";
547       constructor_args += (struct_def.fixed ? "required " : "");
548       constructor_args += "this." + field_name;
549       if (!struct_def.fixed && !defaultValue.empty()) {
550         if (IsEnum(field.value.type)) {
551           auto &enum_def = *field.value.type.enum_def;
552           if (auto val = enum_def.FindByValue(defaultValue)) {
553             constructor_args += " = " + namer_.EnumVariant(enum_def, *val);
554           } else {
555             constructor_args += " = const " + namer_.Type(enum_def) + "._(" +
556                                 defaultValue + ")";
557           }
558         } else {
559           constructor_args += " = " + defaultValue;
560         }
561       }
562     }
563 
564     if (!constructor_args.empty()) {
565       code += "\n  " + object_type + "({\n" + constructor_args + "});\n\n";
566     }
567 
568     code += GenStructObjectAPIPack(struct_def, non_deprecated_fields);
569     code += "\n";
570     code += GenToString(object_type, non_deprecated_fields);
571 
572     code += "}\n\n";
573     return code;
574   }
575 
576   // Generate function `StructNameT unpack()`
GenStructObjectAPIUnpack(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)577   std::string GenStructObjectAPIUnpack(
578       const StructDef &struct_def,
579       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
580     std::string constructor_args;
581     for (auto it = non_deprecated_fields.begin();
582          it != non_deprecated_fields.end(); ++it) {
583       const FieldDef &field = *it->second;
584 
585       const std::string field_name = namer_.Field(field);
586       if (!constructor_args.empty()) constructor_args += ",\n";
587       constructor_args += "      " + field_name + ": ";
588 
589       const Type &type = field.value.type;
590       std::string defaultValue = getDefaultValue(field.value);
591       bool isNullable = defaultValue.empty() && !struct_def.fixed;
592       std::string nullableValueAccessOperator = isNullable ? "?" : "";
593       if (type.base_type == BASE_TYPE_STRUCT) {
594         constructor_args +=
595             field_name + nullableValueAccessOperator + ".unpack()";
596       } else if (type.base_type == BASE_TYPE_VECTOR) {
597         if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
598           constructor_args += field_name + nullableValueAccessOperator +
599                               ".map((e) => e.unpack()).toList()";
600         } else {
601           constructor_args +=
602               GenReaderTypeName(field.value.type, struct_def.defined_namespace,
603                                 field, false, false);
604           constructor_args += ".vTableGet";
605           std::string offset = NumToString(field.value.offset);
606           constructor_args +=
607               isNullable
608                   ? "Nullable(_bc, _bcOffset, " + offset + ")"
609                   : "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
610         }
611       } else {
612         constructor_args += field_name;
613       }
614     }
615 
616     const std::string object_type = namer_.ObjectType(struct_def);
617     std::string code = "  " + object_type + " unpack() => " + object_type + "(";
618     if (!constructor_args.empty()) code += "\n" + constructor_args;
619     code += ");\n";
620     return code;
621   }
622 
623   // Generate function `StructNameT pack()`
GenStructObjectAPIPack(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)624   std::string GenStructObjectAPIPack(
625       const StructDef &struct_def,
626       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
627     std::string code;
628 
629     code += "  @override\n";
630     code += "  int pack(fb.Builder fbBuilder) {\n";
631     code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields,
632                                            false, true);
633     code += "  }\n";
634     return code;
635   }
636 
NamespaceAliasFromUnionType(Namespace * root_namespace,const Type & type)637   std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
638                                           const Type &type) {
639     const std::vector<std::string> qualified_name_parts =
640         type.struct_def->defined_namespace->components;
641     if (std::equal(root_namespace->components.begin(),
642                    root_namespace->components.end(),
643                    qualified_name_parts.begin())) {
644       return namer_.Type(*type.struct_def);
645     }
646 
647     std::string ns;
648 
649     for (auto it = qualified_name_parts.begin();
650          it != qualified_name_parts.end(); ++it) {
651       auto &part = *it;
652 
653       for (size_t i = 0; i < part.length(); i++) {
654         if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
655           ns += "_";
656           ns += CharToLower(part[i]);
657         } else {
658           ns += CharToLower(part[i]);
659         }
660       }
661       if (it != qualified_name_parts.end() - 1) { ns += "_"; }
662     }
663 
664     return ns + "." + namer_.Type(*type.struct_def);
665   }
666 
GenImplementationGetters(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)667   void GenImplementationGetters(
668       const StructDef &struct_def,
669       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
670       std::string &code) {
671     for (auto it = non_deprecated_fields.begin();
672          it != non_deprecated_fields.end(); ++it) {
673       const FieldDef &field = *it->second;
674 
675       const std::string field_name = namer_.Field(field);
676       const std::string defaultValue = getDefaultValue(field.value);
677       const bool isNullable = defaultValue.empty() && !struct_def.fixed;
678       const std::string type_name =
679           GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
680                           isNullable, "");
681 
682       GenDocComment(field.doc_comment, "  ", code);
683 
684       code += "  " + type_name + " get " + field_name;
685       if (field.value.type.base_type == BASE_TYPE_UNION) {
686         code += " {\n";
687         code += "    switch (" + field_name + "Type?.value) {\n";
688         const auto &enum_def = *field.value.type.enum_def;
689         for (auto en_it = enum_def.Vals().begin() + 1;
690              en_it != enum_def.Vals().end(); ++en_it) {
691           const auto &ev = **en_it;
692           const auto enum_name = NamespaceAliasFromUnionType(
693               enum_def.defined_namespace, ev.union_type);
694           code += "      case " + enum_def.ToString(ev) + ": return " +
695                   enum_name + ".reader.vTableGetNullable(_bc, _bcOffset, " +
696                   NumToString(field.value.offset) + ");\n";
697         }
698         code += "      default: return null;\n";
699         code += "    }\n";
700         code += "  }\n";
701       } else {
702         code += " => ";
703         if (field.value.type.enum_def &&
704             field.value.type.base_type != BASE_TYPE_VECTOR) {
705           code += GenDartTypeName(field.value.type,
706                                   struct_def.defined_namespace, field) +
707                   (isNullable ? "._createOrNull(" : ".fromValue(");
708         }
709 
710         code += GenReaderTypeName(field.value.type,
711                                   struct_def.defined_namespace, field);
712         if (struct_def.fixed) {
713           code +=
714               ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
715         } else {
716           code += ".vTableGet";
717           std::string offset = NumToString(field.value.offset);
718           if (isNullable) {
719             code += "Nullable(_bc, _bcOffset, " + offset + ")";
720           } else {
721             code += "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
722           }
723         }
724         if (field.value.type.enum_def &&
725             field.value.type.base_type != BASE_TYPE_VECTOR) {
726           code += ")";
727         }
728         code += ";\n";
729       }
730     }
731 
732     code += "\n";
733     code += GenToString(namer_.Type(struct_def), non_deprecated_fields);
734   }
735 
GenToString(const std::string & object_name,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields)736   std::string GenToString(
737       const std::string &object_name,
738       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
739     std::string code;
740     code += "  @override\n";
741     code += "  String toString() {\n";
742     code += "    return '" + object_name + "{";
743     for (auto it = non_deprecated_fields.begin();
744          it != non_deprecated_fields.end(); ++it) {
745       const std::string field = namer_.Field(*it->second);
746       // We need to escape the fact that some fields have $ in the name which is
747       // also used in symbol/string substitution.
748       std::string escaped_field;
749       for (size_t i = 0; i < field.size(); i++) {
750         if (field[i] == '$') escaped_field.push_back('\\');
751         escaped_field.push_back(field[i]);
752       }
753       code += escaped_field + ": ${" + field + "}";
754       if (it != non_deprecated_fields.end() - 1) { code += ", "; }
755     }
756     code += "}';\n";
757     code += "  }\n";
758     return code;
759   }
760 
getDefaultValue(const Value & value) const761   std::string getDefaultValue(const Value &value) const {
762     if (!value.constant.empty() && value.constant != "0") {
763       if (IsBool(value.type.base_type)) { return "true"; }
764       if (IsScalar(value.type.base_type)) {
765         if (StringIsFlatbufferNan(value.constant)) {
766           return "double.nan";
767         } else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
768           return "double.infinity";
769         } else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
770           return "double.negativeInfinity";
771         }
772       }
773       return value.constant;
774     } else if (IsBool(value.type.base_type)) {
775       return "false";
776     } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
777       return "0";
778     } else {
779       return "";
780     }
781   }
782 
GenReader(const StructDef & struct_def,const std::string & reader_name,std::string & code)783   void GenReader(const StructDef &struct_def, const std::string &reader_name,
784                  std::string &code) {
785     const auto struct_type = namer_.Type(struct_def);
786 
787     code += "class " + reader_name + " extends " + _kFb;
788     if (struct_def.fixed) {
789       code += ".StructReader<";
790     } else {
791       code += ".TableReader<";
792     }
793     code += struct_type + "> {\n";
794     code += "  const " + reader_name + "();\n\n";
795 
796     if (struct_def.fixed) {
797       code += "  @override\n";
798       code += "  int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
799     }
800     code += "  @override\n";
801     code += "  " + struct_type +
802             " createObject(fb.BufferContext bc, int offset) => \n    " +
803             struct_type + "._(bc, offset);\n";
804     code += "}\n\n";
805   }
806 
GenBuilder(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,const std::string & builder_name,std::string & code)807   void GenBuilder(
808       const StructDef &struct_def,
809       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
810       const std::string &builder_name, std::string &code) {
811     if (non_deprecated_fields.size() == 0) { return; }
812 
813     code += "class " + builder_name + " {\n";
814     code += "  " + builder_name + "(this.fbBuilder);\n\n";
815     code += "  final " + _kFb + ".Builder fbBuilder;\n\n";
816 
817     if (struct_def.fixed) {
818       StructBuilderBody(struct_def, non_deprecated_fields, code);
819     } else {
820       TableBuilderBody(struct_def, non_deprecated_fields, code);
821     }
822 
823     code += "}\n\n";
824   }
825 
StructBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)826   void StructBuilderBody(
827       const StructDef &struct_def,
828       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
829       std::string &code) {
830     code += "  int finish(";
831     for (auto it = non_deprecated_fields.begin();
832          it != non_deprecated_fields.end(); ++it) {
833       const FieldDef &field = *it->second;
834       const std::string field_name = namer_.Field(field);
835 
836       if (IsStruct(field.value.type)) {
837         code += "fb.StructBuilder";
838       } else {
839         code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
840                                 field);
841       }
842       code += " " + field_name;
843       if (it != non_deprecated_fields.end() - 1) { code += ", "; }
844     }
845     code += ") {\n";
846 
847     for (auto it = non_deprecated_fields.rbegin();
848          it != non_deprecated_fields.rend(); ++it) {
849       const FieldDef &field = *it->second;
850       const std::string field_name = namer_.Field(field);
851 
852       if (field.padding) {
853         code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
854       }
855 
856       if (IsStruct(field.value.type)) {
857         code += "    " + field_name + "();\n";
858       } else {
859         code += "    fbBuilder.put" + GenType(field.value.type) + "(";
860         code += field_name;
861         if (field.value.type.enum_def) { code += ".value"; }
862         code += ");\n";
863       }
864     }
865     code += "    return fbBuilder.offset;\n";
866     code += "  }\n\n";
867   }
868 
TableBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,std::string & code)869   void TableBuilderBody(
870       const StructDef &struct_def,
871       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
872       std::string &code) {
873     code += "  void begin() {\n";
874     code += "    fbBuilder.startTable(" +
875             NumToString(struct_def.fields.vec.size()) + ");\n";
876     code += "  }\n\n";
877 
878     for (auto it = non_deprecated_fields.begin();
879          it != non_deprecated_fields.end(); ++it) {
880       const auto &field = *it->second;
881       const auto offset = it->first;
882       const std::string add_field = namer_.Method("add", field);
883       const std::string field_var = namer_.Variable(field);
884 
885       if (IsScalar(field.value.type.base_type)) {
886         code += "  int " + add_field + "(";
887         code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
888                                 field);
889         code += "? " + field_var + ") {\n";
890         code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
891                 NumToString(offset) + ", ";
892         code += field_var;
893         if (field.value.type.enum_def) { code += "?.value"; }
894         code += ");\n";
895       } else if (IsStruct(field.value.type)) {
896         code += "  int " + add_field + "(int offset) {\n";
897         code +=
898             "    fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
899       } else {
900         code += "  int " + add_field + "Offset(int? offset) {\n";
901         code +=
902             "    fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
903       }
904       code += "    return fbBuilder.offset;\n";
905       code += "  }\n";
906     }
907 
908     code += "\n";
909     code += "  int finish() {\n";
910     code += "    return fbBuilder.endTable();\n";
911     code += "  }\n";
912   }
913 
GenObjectBuilder(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,const std::string & builder_name,std::string & code)914   void GenObjectBuilder(
915       const StructDef &struct_def,
916       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
917       const std::string &builder_name, std::string &code) {
918     code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
919     for (auto it = non_deprecated_fields.begin();
920          it != non_deprecated_fields.end(); ++it) {
921       const FieldDef &field = *it->second;
922 
923       code += "  final " +
924               GenDartTypeName(field.value.type, struct_def.defined_namespace,
925                               field, !struct_def.fixed, "ObjectBuilder") +
926               " _" + namer_.Variable(field) + ";\n";
927     }
928     code += "\n";
929     code += "  " + builder_name + "(";
930 
931     if (non_deprecated_fields.size() != 0) {
932       code += "{\n";
933       for (auto it = non_deprecated_fields.begin();
934            it != non_deprecated_fields.end(); ++it) {
935         const FieldDef &field = *it->second;
936 
937         code += "    ";
938         code += (struct_def.fixed ? "required " : "") +
939                 GenDartTypeName(field.value.type, struct_def.defined_namespace,
940                                 field, !struct_def.fixed, "ObjectBuilder") +
941                 " " + namer_.Variable(field) + ",\n";
942       }
943       code += "  })\n";
944       code += "      : ";
945       for (auto it = non_deprecated_fields.begin();
946            it != non_deprecated_fields.end(); ++it) {
947         const FieldDef &field = *it->second;
948 
949         code += "_" + namer_.Variable(field) + " = " + namer_.Variable(field);
950         if (it == non_deprecated_fields.end() - 1) {
951           code += ";\n\n";
952         } else {
953           code += ",\n        ";
954         }
955       }
956     } else {
957       code += ");\n\n";
958     }
959 
960     code += "  /// Finish building, and store into the [fbBuilder].\n";
961     code += "  @override\n";
962     code += "  int finish(" + _kFb + ".Builder fbBuilder) {\n";
963     code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields);
964     code += "  }\n\n";
965 
966     code += "  /// Convenience method to serialize to byte list.\n";
967     code += "  @override\n";
968     code += "  Uint8List toBytes([String? fileIdentifier]) {\n";
969     code += "    final fbBuilder = " + _kFb +
970             ".Builder(deduplicateTables: false);\n";
971     code += "    fbBuilder.finish(finish(fbBuilder), fileIdentifier);\n";
972     code += "    return fbBuilder.buffer;\n";
973     code += "  }\n";
974     code += "}\n";
975   }
976 
GenObjectBuilderImplementation(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)977   std::string GenObjectBuilderImplementation(
978       const StructDef &struct_def,
979       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
980       bool prependUnderscore = true, bool pack = false) {
981     std::string code;
982     for (auto it = non_deprecated_fields.begin();
983          it != non_deprecated_fields.end(); ++it) {
984       const FieldDef &field = *it->second;
985 
986       if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
987         continue;
988 
989       std::string offset_name = namer_.Variable(field) + "Offset";
990       std::string field_name =
991           (prependUnderscore ? "_" : "") + namer_.Variable(field);
992       // custom handling for fixed-sized struct in pack()
993       if (pack && IsVector(field.value.type) &&
994           field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
995           field.value.type.struct_def->fixed) {
996         code += "    int? " + offset_name + ";\n";
997         code += "    if (" + field_name + " != null) {\n";
998         code +=
999             "      for (var e in " + field_name + "!) { e.pack(fbBuilder); }\n";
1000         code += "      " + namer_.Variable(field) +
1001                 "Offset = fbBuilder.endStructVector(" + field_name +
1002                 "!.length);\n";
1003         code += "    }\n";
1004         continue;
1005       }
1006 
1007       code += "    final int? " + offset_name;
1008       if (IsVector(field.value.type)) {
1009         code += " = " + field_name + " == null ? null\n";
1010         code += "        : fbBuilder.writeList";
1011         switch (field.value.type.VectorType().base_type) {
1012           case BASE_TYPE_STRING:
1013             code +=
1014                 "(" + field_name + "!.map(fbBuilder.writeString).toList());\n";
1015             break;
1016           case BASE_TYPE_STRUCT:
1017             if (field.value.type.struct_def->fixed) {
1018               code += "OfStructs(" + field_name + "!);\n";
1019             } else {
1020               code += "(" + field_name + "!.map((b) => b." +
1021                       (pack ? "pack" : "getOrCreateOffset") +
1022                       "(fbBuilder)).toList());\n";
1023             }
1024             break;
1025           default:
1026             code +=
1027                 GenType(field.value.type.VectorType()) + "(" + field_name + "!";
1028             if (field.value.type.enum_def) {
1029               code += ".map((f) => f.value).toList()";
1030             }
1031             code += ");\n";
1032         }
1033       } else if (IsString(field.value.type)) {
1034         code += " = " + field_name + " == null ? null\n";
1035         code += "        : fbBuilder.writeString(" + field_name + "!);\n";
1036       } else {
1037         code += " = " + field_name + "?." +
1038                 (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n";
1039       }
1040     }
1041 
1042     if (struct_def.fixed) {
1043       code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore,
1044                                       pack);
1045     } else {
1046       code += TableObjectBuilderBody(struct_def, non_deprecated_fields,
1047                                      prependUnderscore, pack);
1048     }
1049     return code;
1050   }
1051 
StructObjectBuilderBody(const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)1052   std::string StructObjectBuilderBody(
1053       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1054       bool prependUnderscore = true, bool pack = false) {
1055     std::string code;
1056 
1057     for (auto it = non_deprecated_fields.rbegin();
1058          it != non_deprecated_fields.rend(); ++it) {
1059       const FieldDef &field = *it->second;
1060       const std::string field_name = namer_.Field(field);
1061 
1062       if (field.padding) {
1063         code += "    fbBuilder.pad(" + NumToString(field.padding) + ");\n";
1064       }
1065 
1066       if (IsStruct(field.value.type)) {
1067         code += "    ";
1068         if (prependUnderscore) { code += "_"; }
1069         code += field_name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n";
1070       } else {
1071         code += "    fbBuilder.put" + GenType(field.value.type) + "(";
1072         if (prependUnderscore) { code += "_"; }
1073         code += field_name;
1074         if (field.value.type.enum_def) { code += ".value"; }
1075         code += ");\n";
1076       }
1077     }
1078 
1079     code += "    return fbBuilder.offset;\n";
1080     return code;
1081   }
1082 
TableObjectBuilderBody(const StructDef & struct_def,const std::vector<std::pair<int,FieldDef * >> & non_deprecated_fields,bool prependUnderscore=true,bool pack=false)1083   std::string TableObjectBuilderBody(
1084       const StructDef &struct_def,
1085       const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1086       bool prependUnderscore = true, bool pack = false) {
1087     std::string code;
1088     code += "    fbBuilder.startTable(" +
1089             NumToString(struct_def.fields.vec.size()) + ");\n";
1090 
1091     for (auto it = non_deprecated_fields.begin();
1092          it != non_deprecated_fields.end(); ++it) {
1093       const FieldDef &field = *it->second;
1094       auto offset = it->first;
1095 
1096       std::string field_var =
1097           (prependUnderscore ? "_" : "") + namer_.Variable(field);
1098 
1099       if (IsScalar(field.value.type.base_type)) {
1100         code += "    fbBuilder.add" + GenType(field.value.type) + "(" +
1101                 NumToString(offset) + ", " + field_var;
1102         if (field.value.type.enum_def) {
1103           bool isNullable = getDefaultValue(field.value).empty();
1104           code += (isNullable || !pack) ? "?.value" : ".value";
1105         }
1106         code += ");\n";
1107       } else if (IsStruct(field.value.type)) {
1108         code += "    if (" + field_var + " != null) {\n";
1109         code += "      fbBuilder.addStruct(" + NumToString(offset) + ", " +
1110                 field_var + (pack ? "!.pack" : "!.finish") + "(fbBuilder));\n";
1111         code += "    }\n";
1112       } else {
1113         code += "    fbBuilder.addOffset(" + NumToString(offset) + ", " +
1114                 namer_.Variable(field) + "Offset);\n";
1115       }
1116     }
1117     code += "    return fbBuilder.endTable();\n";
1118     return code;
1119   }
1120 
1121   const IdlNamer namer_;
1122 };
1123 }  // namespace dart
1124 
GenerateDart(const Parser & parser,const std::string & path,const std::string & file_name)1125 static bool GenerateDart(const Parser &parser, const std::string &path,
1126                          const std::string &file_name) {
1127   dart::DartGenerator generator(parser, path, file_name);
1128   return generator.generate();
1129 }
1130 
DartMakeRule(const Parser & parser,const std::string & path,const std::string & file_name)1131 static std::string DartMakeRule(const Parser &parser, const std::string &path,
1132                                 const std::string &file_name) {
1133   auto filebase =
1134       flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
1135   dart::DartGenerator generator(parser, path, file_name);
1136   auto make_rule = generator.Filename("") + ": ";
1137 
1138   auto included_files = parser.GetIncludedFilesRecursive(file_name);
1139   for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1140     make_rule += " " + *it;
1141   }
1142   return make_rule;
1143 }
1144 
1145 namespace {
1146 
1147 class DartCodeGenerator : public CodeGenerator {
1148  public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)1149   Status GenerateCode(const Parser &parser, const std::string &path,
1150                       const std::string &filename) override {
1151     if (!GenerateDart(parser, path, filename)) { return Status::ERROR; }
1152     return Status::OK;
1153   }
1154 
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)1155   Status GenerateCode(const uint8_t *, int64_t,
1156                       const CodeGenOptions &) override {
1157     return Status::NOT_IMPLEMENTED;
1158   }
1159 
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)1160   Status GenerateMakeRule(const Parser &parser, const std::string &path,
1161                           const std::string &filename,
1162                           std::string &output) override {
1163     output = DartMakeRule(parser, path, filename);
1164     return Status::OK;
1165   }
1166 
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)1167   Status GenerateGrpcCode(const Parser &parser, const std::string &path,
1168                           const std::string &filename) override {
1169     (void)parser;
1170     (void)path;
1171     (void)filename;
1172     return Status::NOT_IMPLEMENTED;
1173   }
1174 
GenerateRootFile(const Parser & parser,const std::string & path)1175   Status GenerateRootFile(const Parser &parser,
1176                           const std::string &path) override {
1177     (void)parser;
1178     (void)path;
1179     return Status::NOT_IMPLEMENTED;
1180   }
1181 
IsSchemaOnly() const1182   bool IsSchemaOnly() const override { return true; }
1183 
SupportsBfbsGeneration() const1184   bool SupportsBfbsGeneration() const override { return false; }
1185 
SupportsRootFileGeneration() const1186   bool SupportsRootFileGeneration() const override { return false; }
1187 
Language() const1188   IDLOptions::Language Language() const override { return IDLOptions::kDart; }
1189 
LanguageName() const1190   std::string LanguageName() const override { return "Dart"; }
1191 };
1192 }  // namespace
1193 
NewDartCodeGenerator()1194 std::unique_ptr<CodeGenerator> NewDartCodeGenerator() {
1195   return std::unique_ptr<DartCodeGenerator>(new DartCodeGenerator());
1196 }
1197 
1198 }  // namespace flatbuffers
1199