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