blob: ff2c1a5d5e28df6049c6114104c134ff7f008d11 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
25namespace flatbuffers {
26
Austin Schuhe89fa2d2019-08-14 20:24:23 -070027namespace dart {
28
29const std::string _kFb = "fb";
30// see https://www.dartlang.org/guides/language/language-tour#keywords
31// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in
32static const char *keywords[] = {
33 "abstract", "deferred", "if", "super", "as", "do",
34 "implements", "switch", "assert", "dynamic", "import", "sync*",
35 "async", "else", "in", "this", "async*", "enum",
36 "is", "throw", "await", "export", "library", "true",
37 "break", "external", "new", "try", "case", "extends",
38 "null", "typedef", "catch", "factory", "operator", "var",
39 "class", "false", "part", "void", "const", "final",
40 "rethrow", "while", "continue", "finally", "return", "with",
41 "covariant", "for", "set", "yield", "default", "get",
42 "static", "yield*"
43};
44
45// Iterate through all definitions we haven't generate code for (enums, structs,
46// and tables) and output them to a single file.
47class DartGenerator : public BaseGenerator {
48 public:
49 typedef std::map<std::string, std::string> namespace_code_map;
50
51 DartGenerator(const Parser &parser, const std::string &path,
52 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -080053 : BaseGenerator(parser, path, file_name, "", ".", "dart") {}
Austin Schuhe89fa2d2019-08-14 20:24:23 -070054 // Iterate through all definitions we haven't generate code for (enums,
55 // structs, and tables) and output them to a single file.
56 bool generate() {
57 std::string code;
58 namespace_code_map namespace_code;
59 GenerateEnums(&namespace_code);
60 GenerateStructs(&namespace_code);
61
62 for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
63 code.clear();
64 code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
65 code = code +
James Kuszmaul8e62b022022-03-22 09:33:25 -070066 "// ignore_for_file: unused_import, unused_field, unused_element, "
Austin Schuhe89fa2d2019-08-14 20:24:23 -070067 "unused_local_variable\n\n";
68
Austin Schuh272c6132020-11-14 16:37:52 -080069 if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -070070
71 code += "import 'dart:typed_data' show Uint8List;\n";
72 code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
73 ";\n\n";
74
Austin Schuhe89fa2d2019-08-14 20:24:23 -070075 for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
76 ++kv2) {
77 if (kv2->first != kv->first) {
Austin Schuh272c6132020-11-14 16:37:52 -080078 code +=
79 "import '" +
80 GeneratedFileName(
81 "./",
82 file_name_ + (!kv2->first.empty() ? "_" + kv2->first : ""),
83 parser_.opts) +
84 "' as " + ImportAliasName(kv2->first) + ";\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070085 }
86 }
87 code += "\n";
88 code += kv->second;
89
90 if (!SaveFile(
Austin Schuh272c6132020-11-14 16:37:52 -080091 GeneratedFileName(
92 path_,
93 file_name_ + (!kv->first.empty() ? "_" + kv->first : ""),
94 parser_.opts)
95 .c_str(),
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 code, false)) {
97 return false;
98 }
99 }
100 return true;
101 }
102
103 private:
104 static std::string ImportAliasName(const std::string &ns) {
105 std::string ret;
106 ret.assign(ns);
107 size_t pos = ret.find('.');
108 while (pos != std::string::npos) {
109 ret.replace(pos, 1, "_");
110 pos = ret.find('.', pos + 1);
111 }
112
113 return ret;
114 }
115
116 static std::string BuildNamespaceName(const Namespace &ns) {
Austin Schuh272c6132020-11-14 16:37:52 -0800117 if (ns.components.empty()) { return ""; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700118 std::stringstream sstream;
119 std::copy(ns.components.begin(), ns.components.end() - 1,
120 std::ostream_iterator<std::string>(sstream, "."));
121
122 auto ret = sstream.str() + ns.components.back();
123 for (size_t i = 0; i < ret.size(); i++) {
Austin Schuh272c6132020-11-14 16:37:52 -0800124 auto lower = CharToLower(ret[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700125 if (lower != ret[i]) {
Austin Schuh272c6132020-11-14 16:37:52 -0800126 ret[i] = lower;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700127 if (i != 0 && ret[i - 1] != '.') {
128 ret.insert(i, "_");
129 i++;
130 }
131 }
132 }
Austin Schuh272c6132020-11-14 16:37:52 -0800133 // std::transform(ret.begin(), ret.end(), ret.begin(), CharToLower);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700134 return ret;
135 }
136
Austin Schuh272c6132020-11-14 16:37:52 -0800137 void GenIncludeDependencies(std::string *code,
138 const std::string &the_namespace) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700139 for (auto it = parser_.included_files_.begin();
140 it != parser_.included_files_.end(); ++it) {
141 if (it->second.empty()) continue;
142
143 auto noext = flatbuffers::StripExtension(it->second);
144 auto basename = flatbuffers::StripPath(noext);
145
Austin Schuh272c6132020-11-14 16:37:52 -0800146 *code +=
147 "import '" +
148 GeneratedFileName(
149 "", basename + (the_namespace == "" ? "" : "_" + the_namespace),
150 parser_.opts) +
151 "';\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700152 }
153 }
154
155 static std::string EscapeKeyword(const std::string &name) {
156 for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700157 if (name == keywords[i]) {
158 return ConvertCase(name + "_", Case::kLowerCamel);
159 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700160 }
161
James Kuszmaul8e62b022022-03-22 09:33:25 -0700162 return ConvertCase(name, Case::kLowerCamel);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700163 }
164
165 void GenerateEnums(namespace_code_map *namespace_code) {
166 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
167 ++it) {
168 auto &enum_def = **it;
169 GenEnum(enum_def, namespace_code); // enum_code_ptr);
170 }
171 }
172
173 void GenerateStructs(namespace_code_map *namespace_code) {
174 for (auto it = parser_.structs_.vec.begin();
175 it != parser_.structs_.vec.end(); ++it) {
176 auto &struct_def = **it;
177 GenStruct(struct_def, namespace_code);
178 }
179 }
180
181 // Generate a documentation comment, if available.
182 static void GenDocComment(const std::vector<std::string> &dc,
183 std::string *code_ptr,
184 const std::string &extra_lines,
185 const char *indent = nullptr) {
186 if (dc.empty() && extra_lines.empty()) {
187 // Don't output empty comment blocks with 0 lines of comment content.
188 return;
189 }
190
191 auto &code = *code_ptr;
192
193 for (auto it = dc.begin(); it != dc.end(); ++it) {
194 if (indent) code += indent;
195 code += "/// " + *it + "\n";
196 }
197 if (!extra_lines.empty()) {
198 if (!dc.empty()) {
199 if (indent) code += indent;
200 code += "///\n";
201 }
202 if (indent) code += indent;
203 std::string::size_type start = 0;
204 for (;;) {
205 auto end = extra_lines.find('\n', start);
206 if (end != std::string::npos) {
207 code += "/// " + extra_lines.substr(start, end - start) + "\n";
208 start = end + 1;
209 } else {
210 code += "/// " + extra_lines.substr(start) + "\n";
211 break;
212 }
213 }
214 }
215 }
216
217 static void GenDocComment(std::string *code_ptr,
218 const std::string &extra_lines) {
219 GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
220 }
221
222 // Generate an enum declaration and an enum string lookup table.
223 void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) {
224 if (enum_def.generated) return;
225 auto ns = BuildNamespaceName(*enum_def.defined_namespace);
226 std::string code;
227 GenDocComment(enum_def.doc_comment, &code, "");
228
229 auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700230 const bool is_bit_flags =
231 enum_def.attributes.Lookup("bit_flags") != nullptr;
232 // The flatbuffer schema language allows bit flag enums to potentially have
233 // a default value of zero, even if it's not a valid enum value...
234 const bool permit_zero = is_bit_flags;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700235
236 code += "class " + name + " {\n";
237 code += " final int value;\n";
238 code += " const " + name + "._(this.value);\n\n";
239 code += " factory " + name + ".fromValue(int value) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700240 code += " final result = values[value];\n";
241 code += " if (result == null) {\n";
242 if (permit_zero) {
243 code += " if (value == 0) {\n";
244 code += " return " + name + "._(0);\n";
245 code += " } else {\n";
246 }
247 code += " throw StateError('Invalid value $value for bit flag enum ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700248 code += name + "');\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700249 if (permit_zero) { code += " }\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700250 code += " }\n";
251
James Kuszmaul8e62b022022-03-22 09:33:25 -0700252 code += " return result;\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700253 code += " }\n\n";
254
James Kuszmaul8e62b022022-03-22 09:33:25 -0700255 code += " static " + name + "? _createOrNull(int? value) => \n";
256 code += " value == null ? null : " + name + ".fromValue(value);\n\n";
257
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700258 // this is meaningless for bit_flags
259 // however, note that unlike "regular" dart enums this enum can still have
260 // holes.
261 if (!is_bit_flags) {
262 code += " static const int minValue = " +
263 enum_def.ToString(*enum_def.MinValue()) + ";\n";
264 code += " static const int maxValue = " +
265 enum_def.ToString(*enum_def.MaxValue()) + ";\n";
266 }
267
268 code +=
269 " static bool containsValue(int value) =>"
270 " values.containsKey(value);\n\n";
271
272 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
273 auto &ev = **it;
274
275 if (!ev.doc_comment.empty()) {
276 if (it != enum_def.Vals().begin()) { code += '\n'; }
277 GenDocComment(ev.doc_comment, &code, "", " ");
278 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700279 code += " static const " + name + " " + ev.name + " = " + name + "._(" +
280 enum_def.ToString(ev) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700281 }
282
James Kuszmaul8e62b022022-03-22 09:33:25 -0700283 code += " static const Map<int, " + name + "> values = {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700284 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
285 auto &ev = **it;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700286 if (it != enum_def.Vals().begin()) code += ",\n";
287 code += " " + enum_def.ToString(ev) + ": " + ev.name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700288 }
289 code += "};\n\n";
290
James Kuszmaul8e62b022022-03-22 09:33:25 -0700291 code += " static const " + _kFb + ".Reader<" + name + "> reader = _" +
292 name + "Reader();\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700293 code += " @override\n";
294 code += " String toString() {\n";
295 code += " return '" + name + "{value: $value}';\n";
296 code += " }\n";
297 code += "}\n\n";
298
299 GenEnumReader(enum_def, name, &code);
300 (*namespace_code)[ns] += code;
301 }
302
303 void GenEnumReader(EnumDef &enum_def, const std::string &name,
304 std::string *code_ptr) {
305 auto &code = *code_ptr;
306
307 code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name +
308 "> {\n";
309 code += " const _" + name + "Reader();\n\n";
310 code += " @override\n";
311 code += " int get size => 1;\n\n";
312 code += " @override\n";
313 code +=
314 " " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700315 code += " " + name + ".fromValue(const " + _kFb + "." +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700316 GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
317 code += "}\n\n";
318 }
319
320 static std::string GenType(const Type &type) {
321 switch (type.base_type) {
322 case BASE_TYPE_BOOL: return "Bool";
323 case BASE_TYPE_CHAR: return "Int8";
324 case BASE_TYPE_UTYPE:
325 case BASE_TYPE_UCHAR: return "Uint8";
326 case BASE_TYPE_SHORT: return "Int16";
327 case BASE_TYPE_USHORT: return "Uint16";
328 case BASE_TYPE_INT: return "Int32";
329 case BASE_TYPE_UINT: return "Uint32";
330 case BASE_TYPE_LONG: return "Int64";
331 case BASE_TYPE_ULONG: return "Uint64";
332 case BASE_TYPE_FLOAT: return "Float32";
333 case BASE_TYPE_DOUBLE: return "Float64";
334 case BASE_TYPE_STRING: return "String";
335 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
336 case BASE_TYPE_STRUCT: return type.struct_def->name;
337 case BASE_TYPE_UNION: return type.enum_def->name + "TypeId";
338 default: return "Table";
339 }
340 }
341
342 std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
343 const FieldDef &def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700344 bool parent_is_vector = false, bool lazy = true,
345 bool constConstruct = true) {
346 std::string prefix = (constConstruct ? "const " : "") + _kFb;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700347 if (type.base_type == BASE_TYPE_BOOL) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700348 return prefix + ".BoolReader()";
Austin Schuh272c6132020-11-14 16:37:52 -0800349 } else if (IsVector(type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700350 if (!type.VectorType().enum_def) {
351 if (type.VectorType().base_type == BASE_TYPE_CHAR) {
352 return prefix + ".Int8ListReader(" + (lazy ? ")" : "lazy: false)");
353 }
354 if (type.VectorType().base_type == BASE_TYPE_UCHAR) {
355 return prefix + ".Uint8ListReader(" + (lazy ? ")" : "lazy: false)");
356 }
357 }
358 return prefix + ".ListReader<" +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700359 GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700360 GenReaderTypeName(type.VectorType(), current_namespace, def, true,
361 true, false) +
362 (lazy ? ")" : ", lazy: false)");
Austin Schuh272c6132020-11-14 16:37:52 -0800363 } else if (IsString(type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700364 return prefix + ".StringReader()";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700365 }
366 if (IsScalar(type.base_type)) {
367 if (type.enum_def && parent_is_vector) {
368 return GenDartTypeName(type, current_namespace, def) + ".reader";
369 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700370 return prefix + "." + GenType(type) + "Reader()";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700371 } else {
372 return GenDartTypeName(type, current_namespace, def) + ".reader";
373 }
374 }
375
376 std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700377 const FieldDef &def,
378 std::string struct_type_suffix = "") {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700379 if (type.enum_def) {
380 if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
381 return type.enum_def->name + "TypeId";
382 } else if (type.enum_def->is_union) {
383 return "dynamic";
384 } else if (type.base_type != BASE_TYPE_VECTOR) {
385 return type.enum_def->name;
386 }
387 }
388
389 switch (type.base_type) {
390 case BASE_TYPE_BOOL: return "bool";
391 case BASE_TYPE_LONG:
392 case BASE_TYPE_ULONG:
393 case BASE_TYPE_INT:
394 case BASE_TYPE_UINT:
395 case BASE_TYPE_SHORT:
396 case BASE_TYPE_USHORT:
397 case BASE_TYPE_CHAR:
398 case BASE_TYPE_UCHAR: return "int";
399 case BASE_TYPE_FLOAT:
400 case BASE_TYPE_DOUBLE: return "double";
401 case BASE_TYPE_STRING: return "String";
402 case BASE_TYPE_STRUCT:
James Kuszmaul8e62b022022-03-22 09:33:25 -0700403 return MaybeWrapNamespace(type.struct_def->name + struct_type_suffix,
404 current_namespace, def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700405 case BASE_TYPE_VECTOR:
406 return "List<" +
407 GenDartTypeName(type.VectorType(), current_namespace, def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700408 struct_type_suffix) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700409 ">";
410 default: assert(0); return "dynamic";
411 }
412 }
413
James Kuszmaul8e62b022022-03-22 09:33:25 -0700414 std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
415 const FieldDef &def, bool nullable,
416 std::string struct_type_suffix) {
417 std::string typeName =
418 GenDartTypeName(type, current_namespace, def, struct_type_suffix);
419 if (nullable && typeName != "dynamic") typeName += "?";
420 return typeName;
421 }
422
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700423 static const std::string MaybeWrapNamespace(const std::string &type_name,
424 Namespace *current_ns,
425 const FieldDef &field) {
426 auto curr_ns_str = BuildNamespaceName(*current_ns);
427 std::string field_ns_str = "";
428 if (field.value.type.struct_def) {
429 field_ns_str +=
430 BuildNamespaceName(*field.value.type.struct_def->defined_namespace);
431 } else if (field.value.type.enum_def) {
432 field_ns_str +=
433 BuildNamespaceName(*field.value.type.enum_def->defined_namespace);
434 }
435
436 if (field_ns_str != "" && field_ns_str != curr_ns_str) {
437 return ImportAliasName(field_ns_str) + "." + type_name;
438 } else {
439 return type_name;
440 }
441 }
442
443 // Generate an accessor struct with constructor for a flatbuffers struct.
444 void GenStruct(const StructDef &struct_def,
445 namespace_code_map *namespace_code) {
446 if (struct_def.generated) return;
447
448 auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace);
449 std::string code;
450
451 const auto &object_name = struct_def.name;
452
453 // Emit constructor
454
455 GenDocComment(struct_def.doc_comment, &code, "");
456
457 auto reader_name = "_" + object_name + "Reader";
458 auto builder_name = object_name + "Builder";
459 auto object_builder_name = object_name + "ObjectBuilder";
460
461 std::string reader_code, builder_code;
462
463 code += "class " + object_name + " {\n";
464
465 code += " " + object_name + "._(this._bc, this._bcOffset);\n";
466 if (!struct_def.fixed) {
467 code += " factory " + object_name + "(List<int> bytes) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700468 code +=
469 " final rootRef = " + _kFb + ".BufferContext.fromBytes(bytes);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700470 code += " return reader.read(rootRef, 0);\n";
471 code += " }\n";
472 }
473
474 code += "\n";
475 code += " static const " + _kFb + ".Reader<" + object_name +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700476 "> reader = " + reader_name + "();\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700477
478 code += " final " + _kFb + ".BufferContext _bc;\n";
479 code += " final int _bcOffset;\n\n";
480
Austin Schuh272c6132020-11-14 16:37:52 -0800481 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
482 for (auto it = struct_def.fields.vec.begin();
483 it != struct_def.fields.vec.end(); ++it) {
484 auto &field = **it;
485 if (field.deprecated) continue;
486 auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
487 non_deprecated_fields.push_back(std::make_pair(offset, &field));
488 }
489
490 GenImplementationGetters(struct_def, non_deprecated_fields, &code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700491
James Kuszmaul8e62b022022-03-22 09:33:25 -0700492 if (parser_.opts.generate_object_based_api) {
493 code +=
494 "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields);
495
496 code += "\n static int pack(fb.Builder fbBuilder, " + struct_def.name +
497 "T? object) {\n";
498 code += " if (object == null) return 0;\n";
499 code += " return object.pack(fbBuilder);\n";
500 code += " }\n";
501 }
502
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700503 code += "}\n\n";
504
James Kuszmaul8e62b022022-03-22 09:33:25 -0700505 if (parser_.opts.generate_object_based_api) {
506 code += GenStructObjectAPI(struct_def, non_deprecated_fields);
507 }
508
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700509 GenReader(struct_def, &reader_name, &reader_code);
Austin Schuh272c6132020-11-14 16:37:52 -0800510 GenBuilder(struct_def, non_deprecated_fields, &builder_name, &builder_code);
511 GenObjectBuilder(struct_def, non_deprecated_fields, &object_builder_name,
512 &builder_code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700513
514 code += reader_code;
515 code += builder_code;
516
517 (*namespace_code)[object_namespace] += code;
518 }
519
James Kuszmaul8e62b022022-03-22 09:33:25 -0700520 // Generate an accessor struct with constructor for a flatbuffers struct.
521 std::string GenStructObjectAPI(
522 const StructDef &struct_def,
523 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
524 std::string code;
525 GenDocComment(struct_def.doc_comment, &code, "");
526
527 std::string class_name = struct_def.name + "T";
528 code += "class " + class_name + " implements " + _kFb + ".Packable {\n";
529
530 std::string constructor_args;
531 for (auto it = non_deprecated_fields.begin();
532 it != non_deprecated_fields.end(); ++it) {
533 const FieldDef &field = *it->second;
534
535 std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
536 std::string defaultValue = getDefaultValue(field.value);
537 std::string type_name =
538 GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
539 defaultValue.empty() && !struct_def.fixed, "T");
540
541 GenDocComment(field.doc_comment, &code, "", " ");
542 code += " " + type_name + " " + field_name + ";\n";
543
544 if (!constructor_args.empty()) constructor_args += ",\n";
545 constructor_args += " ";
546 constructor_args += (struct_def.fixed ? "required " : "");
547 constructor_args += "this." + field_name;
548 if (!struct_def.fixed && !defaultValue.empty()) {
549 if (IsEnum(field.value.type)) {
550 auto &enum_def = *field.value.type.enum_def;
551 if (auto val = enum_def.FindByValue(defaultValue)) {
552 constructor_args += " = " + enum_def.name + "." + val->name;
553 } else {
554 constructor_args +=
555 " = const " + enum_def.name + "._(" + defaultValue + ")";
556 }
557 } else {
558 constructor_args += " = " + defaultValue;
559 }
560 }
561 }
562
563 if (!constructor_args.empty()) {
564 code += "\n " + class_name + "({\n" + constructor_args + "});\n\n";
565 }
566
567 code += GenStructObjectAPIPack(struct_def, non_deprecated_fields);
568 code += "\n";
569 code += GenToString(class_name, non_deprecated_fields);
570
571 code += "}\n\n";
572 return code;
573 }
574
575 // Generate function `StructNameT unpack()`
576 std::string GenStructObjectAPIUnpack(
577 const StructDef &struct_def,
578 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
579 std::string constructor_args;
580 for (auto it = non_deprecated_fields.begin();
581 it != non_deprecated_fields.end(); ++it) {
582 const FieldDef &field = *it->second;
583
584 std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
585 if (!constructor_args.empty()) constructor_args += ",\n";
586 constructor_args += " " + field_name + ": ";
587
588 const Type &type = field.value.type;
589 std::string defaultValue = getDefaultValue(field.value);
590 bool isNullable = defaultValue.empty() && !struct_def.fixed;
591 std::string nullableValueAccessOperator = isNullable ? "?" : "";
592 if (type.base_type == BASE_TYPE_STRUCT) {
593 constructor_args +=
594 field_name + nullableValueAccessOperator + ".unpack()";
595 } else if (type.base_type == BASE_TYPE_VECTOR) {
596 if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
597 constructor_args += field_name + nullableValueAccessOperator +
598 ".map((e) => e.unpack()).toList()";
599 } else {
600 constructor_args +=
601 GenReaderTypeName(field.value.type, struct_def.defined_namespace,
602 field, false, false);
603 constructor_args += ".vTableGet";
604 std::string offset = NumToString(field.value.offset);
605 constructor_args +=
606 isNullable
607 ? "Nullable(_bc, _bcOffset, " + offset + ")"
608 : "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
609 }
610 } else {
611 constructor_args += field_name;
612 }
613 }
614
615 std::string class_name = struct_def.name + "T";
616 std::string code = " " + class_name + " unpack() => " + class_name + "(";
617 if (!constructor_args.empty()) code += "\n" + constructor_args;
618 code += ");\n";
619 return code;
620 }
621
622 // Generate function `StructNameT pack()`
623 std::string GenStructObjectAPIPack(
624 const StructDef &struct_def,
625 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
626 std::string code;
627
628 code += " @override\n";
629 code += " int pack(fb.Builder fbBuilder) {\n";
630 code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields,
631 false, true);
632 code += " }\n";
633 return code;
634 }
635
Austin Schuh272c6132020-11-14 16:37:52 -0800636 std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
637 const Type &type) {
638 const std::vector<std::string> qualified_name_parts =
639 type.struct_def->defined_namespace->components;
640 if (std::equal(root_namespace->components.begin(),
641 root_namespace->components.end(),
642 qualified_name_parts.begin())) {
643 return type.struct_def->name;
644 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700645
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700646 std::string ns;
647
Austin Schuh272c6132020-11-14 16:37:52 -0800648 for (auto it = qualified_name_parts.begin();
649 it != qualified_name_parts.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700650 auto &part = *it;
651
652 for (size_t i = 0; i < part.length(); i++) {
Austin Schuh272c6132020-11-14 16:37:52 -0800653 if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700654 ns += "_";
Austin Schuh272c6132020-11-14 16:37:52 -0800655 ns += CharToLower(part[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700656 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800657 ns += CharToLower(part[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700658 }
659 }
Austin Schuh272c6132020-11-14 16:37:52 -0800660 if (it != qualified_name_parts.end() - 1) { ns += "_"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700661 }
662
Austin Schuh272c6132020-11-14 16:37:52 -0800663 return ns + "." + type.struct_def->name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700664 }
665
Austin Schuh272c6132020-11-14 16:37:52 -0800666 void GenImplementationGetters(
667 const StructDef &struct_def,
668 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
669 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700670 auto &code = *code_ptr;
671
Austin Schuh272c6132020-11-14 16:37:52 -0800672 for (auto it = non_deprecated_fields.begin();
673 it != non_deprecated_fields.end(); ++it) {
674 auto pair = *it;
675 auto &field = *pair.second;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700676
James Kuszmaul8e62b022022-03-22 09:33:25 -0700677 std::string field_name = ConvertCase(field.name, Case::kLowerCamel);
678 std::string defaultValue = getDefaultValue(field.value);
679 bool isNullable = defaultValue.empty() && !struct_def.fixed;
680 std::string type_name =
681 GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
682 isNullable, "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700683
684 GenDocComment(field.doc_comment, &code, "", " ");
685
686 code += " " + type_name + " get " + field_name;
687 if (field.value.type.base_type == BASE_TYPE_UNION) {
688 code += " {\n";
689 code += " switch (" + field_name + "Type?.value) {\n";
690 auto &enum_def = *field.value.type.enum_def;
691 for (auto en_it = enum_def.Vals().begin() + 1;
692 en_it != enum_def.Vals().end(); ++en_it) {
693 auto &ev = **en_it;
694
Austin Schuh272c6132020-11-14 16:37:52 -0800695 auto enum_name = NamespaceAliasFromUnionType(
696 enum_def.defined_namespace, ev.union_type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700697 code += " case " + enum_def.ToString(ev) + ": return " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700698 enum_name + ".reader.vTableGetNullable(_bc, _bcOffset, " +
699 NumToString(field.value.offset) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700700 }
701 code += " default: return null;\n";
702 code += " }\n";
703 code += " }\n";
704 } else {
705 code += " => ";
706 if (field.value.type.enum_def &&
707 field.value.type.base_type != BASE_TYPE_VECTOR) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700708 code += GenDartTypeName(field.value.type,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700709 struct_def.defined_namespace, field) +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700710 (isNullable ? "._createOrNull(" : ".fromValue(");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700711 }
712
713 code += GenReaderTypeName(field.value.type,
714 struct_def.defined_namespace, field);
715 if (struct_def.fixed) {
716 code +=
717 ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
718 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700719 code += ".vTableGet";
720 std::string offset = NumToString(field.value.offset);
721 if (isNullable) {
722 code += "Nullable(_bc, _bcOffset, " + offset + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700723 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700724 code += "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700725 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700726 }
727 if (field.value.type.enum_def &&
728 field.value.type.base_type != BASE_TYPE_VECTOR) {
729 code += ")";
730 }
731 code += ";\n";
732 }
733 }
734
735 code += "\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700736 code += GenToString(struct_def.name, non_deprecated_fields);
737 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700738
James Kuszmaul8e62b022022-03-22 09:33:25 -0700739 std::string GenToString(
740 const std::string &object_name,
741 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
742 std::string code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700743 code += " @override\n";
744 code += " String toString() {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700745 code += " return '" + object_name + "{";
Austin Schuh272c6132020-11-14 16:37:52 -0800746 for (auto it = non_deprecated_fields.begin();
747 it != non_deprecated_fields.end(); ++it) {
748 auto pair = *it;
749 auto &field = *pair.second;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700750 code += ConvertCase(field.name, Case::kLowerCamel) + ": $" +
751 ConvertCase(field.name, Case::kLowerCamel);
Austin Schuh272c6132020-11-14 16:37:52 -0800752 if (it != non_deprecated_fields.end() - 1) { code += ", "; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700753 }
754 code += "}';\n";
755 code += " }\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700756 return code;
757 }
758
759 std::string getDefaultValue(const Value &value) const {
760 if (!value.constant.empty() && value.constant != "0") {
761 if (IsBool(value.type.base_type)) {
762 return "true";
763 } else if (value.constant == "nan" || value.constant == "+nan" ||
764 value.constant == "-nan") {
765 return "double.nan";
766 } else if (value.constant == "inf" || value.constant == "+inf") {
767 return "double.infinity";
768 } else if (value.constant == "-inf") {
769 return "double.negativeInfinity";
770 } else {
771 return value.constant;
772 }
773 } else if (IsBool(value.type.base_type)) {
774 return "false";
775 } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
776 return "0";
777 } else {
778 return "";
779 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700780 }
781
782 void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
783 std::string *code_ptr) {
784 auto &code = *code_ptr;
785 auto &reader_name = *reader_name_ptr;
786 auto &impl_name = struct_def.name;
787
788 code += "class " + reader_name + " extends " + _kFb;
789 if (struct_def.fixed) {
790 code += ".StructReader<";
791 } else {
792 code += ".TableReader<";
793 }
794 code += impl_name + "> {\n";
795 code += " const " + reader_name + "();\n\n";
796
797 if (struct_def.fixed) {
798 code += " @override\n";
799 code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
800 }
801 code += " @override\n";
802 code += " " + impl_name +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700803 " createObject(fb.BufferContext bc, int offset) => \n " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700804 impl_name + "._(bc, offset);\n";
805 code += "}\n\n";
806 }
807
Austin Schuh272c6132020-11-14 16:37:52 -0800808 void GenBuilder(const StructDef &struct_def,
809 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
810 std::string *builder_name_ptr, std::string *code_ptr) {
811 if (non_deprecated_fields.size() == 0) { return; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700812 auto &code = *code_ptr;
813 auto &builder_name = *builder_name_ptr;
814
815 code += "class " + builder_name + " {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700816 code += " " + builder_name + "(this.fbBuilder);\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700817 code += " final " + _kFb + ".Builder fbBuilder;\n\n";
818
819 if (struct_def.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -0800820 StructBuilderBody(struct_def, non_deprecated_fields, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700821 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800822 TableBuilderBody(struct_def, non_deprecated_fields, code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700823 }
824
825 code += "}\n\n";
826 }
827
Austin Schuh272c6132020-11-14 16:37:52 -0800828 void StructBuilderBody(
829 const StructDef &struct_def,
830 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
831 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700832 auto &code = *code_ptr;
833
834 code += " int finish(";
Austin Schuh272c6132020-11-14 16:37:52 -0800835 for (auto it = non_deprecated_fields.begin();
836 it != non_deprecated_fields.end(); ++it) {
837 auto pair = *it;
838 auto &field = *pair.second;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700839
840 if (IsStruct(field.value.type)) {
841 code += "fb.StructBuilder";
842 } else {
843 code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
844 field);
845 }
846 code += " " + field.name;
Austin Schuh272c6132020-11-14 16:37:52 -0800847 if (it != non_deprecated_fields.end() - 1) { code += ", "; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700848 }
849 code += ") {\n";
850
Austin Schuh272c6132020-11-14 16:37:52 -0800851 for (auto it = non_deprecated_fields.rbegin();
852 it != non_deprecated_fields.rend(); ++it) {
853 auto pair = *it;
854 auto &field = *pair.second;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700855
856 if (field.padding) {
857 code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
858 }
859
860 if (IsStruct(field.value.type)) {
861 code += " " + field.name + "();\n";
862 } else {
863 code += " fbBuilder.put" + GenType(field.value.type) + "(";
864 code += field.name;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700865 if (field.value.type.enum_def) { code += ".value"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700866 code += ");\n";
867 }
868 }
869 code += " return fbBuilder.offset;\n";
870 code += " }\n\n";
871 }
872
Austin Schuh272c6132020-11-14 16:37:52 -0800873 void TableBuilderBody(
874 const StructDef &struct_def,
875 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
876 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700877 auto &code = *code_ptr;
878
879 code += " void begin() {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700880 code += " fbBuilder.startTable(" +
881 NumToString(struct_def.fields.vec.size()) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700882 code += " }\n\n";
883
Austin Schuh272c6132020-11-14 16:37:52 -0800884 for (auto it = non_deprecated_fields.begin();
885 it != non_deprecated_fields.end(); ++it) {
886 auto pair = *it;
887 auto &field = *pair.second;
888 auto offset = pair.first;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700889
890 if (IsScalar(field.value.type.base_type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700891 code += " int add" + ConvertCase(field.name, Case::kUpperCamel) + "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700892 code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
893 field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700894 code += "? " + ConvertCase(field.name, Case::kLowerCamel) + ") {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700895 code += " fbBuilder.add" + GenType(field.value.type) + "(" +
896 NumToString(offset) + ", ";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700897 code += ConvertCase(field.name, Case::kLowerCamel);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700898 if (field.value.type.enum_def) { code += "?.value"; }
899 code += ");\n";
900 } else if (IsStruct(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700901 code += " int add" + ConvertCase(field.name, Case::kUpperCamel) +
902 "(int offset) {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700903 code +=
904 " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
905 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700906 code += " int add" + ConvertCase(field.name, Case::kUpperCamel) +
907 "Offset(int? offset) {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700908 code +=
909 " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
910 }
911 code += " return fbBuilder.offset;\n";
912 code += " }\n";
913 }
914
915 code += "\n";
916 code += " int finish() {\n";
917 code += " return fbBuilder.endTable();\n";
918 code += " }\n";
919 }
920
Austin Schuh272c6132020-11-14 16:37:52 -0800921 void GenObjectBuilder(
922 const StructDef &struct_def,
923 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields,
924 std::string *builder_name_ptr, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700925 auto &code = *code_ptr;
926 auto &builder_name = *builder_name_ptr;
927
928 code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800929 for (auto it = non_deprecated_fields.begin();
930 it != non_deprecated_fields.end(); ++it) {
931 auto pair = *it;
932 auto &field = *pair.second;
933
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700934 code += " final " +
935 GenDartTypeName(field.value.type, struct_def.defined_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700936 field, !struct_def.fixed, "ObjectBuilder") +
937 " _" + ConvertCase(field.name, Case::kLowerCamel) + ";\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700938 }
939 code += "\n";
940 code += " " + builder_name + "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700941
Austin Schuh272c6132020-11-14 16:37:52 -0800942 if (non_deprecated_fields.size() != 0) {
943 code += "{\n";
944 for (auto it = non_deprecated_fields.begin();
945 it != non_deprecated_fields.end(); ++it) {
946 auto pair = *it;
947 auto &field = *pair.second;
948
James Kuszmaul8e62b022022-03-22 09:33:25 -0700949 code += " ";
950 code += (struct_def.fixed ? "required " : "") +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700951 GenDartTypeName(field.value.type, struct_def.defined_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700952 field, !struct_def.fixed, "ObjectBuilder") +
953 " " + ConvertCase(field.name, Case::kLowerCamel) + ",\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700954 }
955 code += " })\n";
956 code += " : ";
Austin Schuh272c6132020-11-14 16:37:52 -0800957 for (auto it = non_deprecated_fields.begin();
958 it != non_deprecated_fields.end(); ++it) {
959 auto pair = *it;
960 auto &field = *pair.second;
961
James Kuszmaul8e62b022022-03-22 09:33:25 -0700962 code += "_" + ConvertCase(field.name, Case::kLowerCamel) + " = " +
963 ConvertCase(field.name, Case::kLowerCamel);
Austin Schuh272c6132020-11-14 16:37:52 -0800964 if (it == non_deprecated_fields.end() - 1) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700965 code += ";\n\n";
966 } else {
967 code += ",\n ";
968 }
969 }
970 } else {
971 code += ");\n\n";
972 }
973
974 code += " /// Finish building, and store into the [fbBuilder].\n";
975 code += " @override\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700976 code += " int finish(" + _kFb + ".Builder fbBuilder) {\n";
977 code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700978 code += " }\n\n";
979
980 code += " /// Convenience method to serialize to byte list.\n";
981 code += " @override\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700982 code += " Uint8List toBytes([String? fileIdentifier]) {\n";
983 code += " final fbBuilder = " + _kFb +
984 ".Builder(deduplicateTables: false);\n";
985 code += " fbBuilder.finish(finish(fbBuilder), fileIdentifier);\n";
986 code += " return fbBuilder.buffer;\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700987 code += " }\n";
988 code += "}\n";
989 }
990
James Kuszmaul8e62b022022-03-22 09:33:25 -0700991 std::string GenObjectBuilderImplementation(
992 const StructDef &struct_def,
993 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
994 bool prependUnderscore = true, bool pack = false) {
995 std::string code;
996 for (auto it = non_deprecated_fields.begin();
997 it != non_deprecated_fields.end(); ++it) {
998 const FieldDef &field = *it->second;
999
1000 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
1001 continue;
1002
1003 std::string offset_name =
1004 ConvertCase(field.name, Case::kLowerCamel) + "Offset";
1005 std::string field_name = (prependUnderscore ? "_" : "") +
1006 ConvertCase(field.name, Case::kLowerCamel);
1007
1008 // custom handling for fixed-sized struct in pack()
1009 if (pack && IsVector(field.value.type) &&
1010 field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
1011 field.value.type.struct_def->fixed) {
1012 code += " int? " + offset_name + ";\n";
1013 code += " if (" + field_name + " != null) {\n";
1014 code +=
1015 " for (var e in " + field_name + "!) { e.pack(fbBuilder); }\n";
1016 code += " " + ConvertCase(field.name, Case::kLowerCamel) +
1017 "Offset = fbBuilder.endStructVector(" + field_name +
1018 "!.length);\n";
1019 code += " }\n";
1020 continue;
1021 }
1022
1023 code += " final int? " + offset_name;
1024 if (IsVector(field.value.type)) {
1025 code += " = " + field_name + " == null ? null\n";
1026 code += " : fbBuilder.writeList";
1027 switch (field.value.type.VectorType().base_type) {
1028 case BASE_TYPE_STRING:
1029 code +=
1030 "(" + field_name + "!.map(fbBuilder.writeString).toList());\n";
1031 break;
1032 case BASE_TYPE_STRUCT:
1033 if (field.value.type.struct_def->fixed) {
1034 code += "OfStructs(" + field_name + "!);\n";
1035 } else {
1036 code += "(" + field_name + "!.map((b) => b." +
1037 (pack ? "pack" : "getOrCreateOffset") +
1038 "(fbBuilder)).toList());\n";
1039 }
1040 break;
1041 default:
1042 code +=
1043 GenType(field.value.type.VectorType()) + "(" + field_name + "!";
1044 if (field.value.type.enum_def) {
1045 code += ".map((f) => f.value).toList()";
1046 }
1047 code += ");\n";
1048 }
1049 } else if (IsString(field.value.type)) {
1050 code += " = " + field_name + " == null ? null\n";
1051 code += " : fbBuilder.writeString(" + field_name + "!);\n";
1052 } else {
1053 code += " = " + field_name + "?." +
1054 (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n";
1055 }
1056 }
1057
1058 if (struct_def.fixed) {
1059 code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore,
1060 pack);
1061 } else {
1062 code += TableObjectBuilderBody(struct_def, non_deprecated_fields,
1063 prependUnderscore, pack);
1064 }
1065 return code;
1066 }
1067
1068 std::string StructObjectBuilderBody(
1069 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1070 bool prependUnderscore = true, bool pack = false) {
1071 std::string code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001072
Austin Schuh272c6132020-11-14 16:37:52 -08001073 for (auto it = non_deprecated_fields.rbegin();
1074 it != non_deprecated_fields.rend(); ++it) {
1075 auto pair = *it;
1076 auto &field = *pair.second;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001077
1078 if (field.padding) {
1079 code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
1080 }
1081
1082 if (IsStruct(field.value.type)) {
1083 code += " ";
1084 if (prependUnderscore) { code += "_"; }
James Kuszmaul8e62b022022-03-22 09:33:25 -07001085 code += field.name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001086 } else {
1087 code += " fbBuilder.put" + GenType(field.value.type) + "(";
1088 if (prependUnderscore) { code += "_"; }
1089 code += field.name;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001090 if (field.value.type.enum_def) { code += ".value"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001091 code += ");\n";
1092 }
1093 }
1094
1095 code += " return fbBuilder.offset;\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001096 return code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001097 }
1098
James Kuszmaul8e62b022022-03-22 09:33:25 -07001099 std::string TableObjectBuilderBody(
1100 const StructDef &struct_def,
1101 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1102 bool prependUnderscore = true, bool pack = false) {
1103 std::string code;
1104 code += " fbBuilder.startTable(" +
1105 NumToString(struct_def.fields.vec.size()) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001106
Austin Schuh272c6132020-11-14 16:37:52 -08001107 for (auto it = non_deprecated_fields.begin();
1108 it != non_deprecated_fields.end(); ++it) {
1109 auto pair = *it;
1110 auto &field = *pair.second;
1111 auto offset = pair.first;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001112
James Kuszmaul8e62b022022-03-22 09:33:25 -07001113 std::string field_name = (prependUnderscore ? "_" : "") +
1114 ConvertCase(field.name, Case::kLowerCamel);
1115
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001116 if (IsScalar(field.value.type.base_type)) {
1117 code += " fbBuilder.add" + GenType(field.value.type) + "(" +
James Kuszmaul8e62b022022-03-22 09:33:25 -07001118 NumToString(offset) + ", " + field_name;
1119 if (field.value.type.enum_def) {
1120 bool isNullable = getDefaultValue(field.value).empty();
1121 code += (isNullable || !pack) ? "?.value" : ".value";
1122 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001123 code += ");\n";
1124 } else if (IsStruct(field.value.type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001125 code += " if (" + field_name + " != null) {\n";
1126 code += " fbBuilder.addStruct(" + NumToString(offset) + ", " +
1127 field_name + (pack ? "!.pack" : "!.finish") + "(fbBuilder));\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001128 code += " }\n";
1129 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001130 code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
1131 ConvertCase(field.name, Case::kLowerCamel) + "Offset);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001132 }
1133 }
1134 code += " return fbBuilder.endTable();\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001135 return code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001136 }
1137};
1138} // namespace dart
1139
1140bool GenerateDart(const Parser &parser, const std::string &path,
1141 const std::string &file_name) {
1142 dart::DartGenerator generator(parser, path, file_name);
1143 return generator.generate();
1144}
1145
1146std::string DartMakeRule(const Parser &parser, const std::string &path,
1147 const std::string &file_name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001148 auto filebase =
1149 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08001150 dart::DartGenerator generator(parser, path, file_name);
1151 auto make_rule =
1152 generator.GeneratedFileName(path, file_name, parser.opts) + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001153
1154 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1155 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1156 make_rule += " " + *it;
1157 }
1158 return make_rule;
1159}
1160
1161} // namespace flatbuffers