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