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