blob: ada59560818574d2162ae319ed9860798bef9a55 [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>
James Kuszmaul3b15b0c2022-11-08 14:03:16 -080019#include <cmath>
Austin Schuhe89fa2d2019-08-14 20:24:23 -070020
21#include "flatbuffers/code_generators.h"
22#include "flatbuffers/flatbuffers.h"
23#include "flatbuffers/idl.h"
24#include "flatbuffers/util.h"
Austin Schuh2dd86a92022-09-14 21:19:23 -070025#include "idl_namer.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070026
27namespace flatbuffers {
28
Austin Schuhe89fa2d2019-08-14 20:24:23 -070029namespace dart {
30
Austin Schuh2dd86a92022-09-14 21:19:23 -070031namespace {
32
33static Namer::Config DartDefaultConfig() {
34 return { /*types=*/Case::kUpperCamel,
35 /*constants=*/Case::kScreamingSnake,
36 /*methods=*/Case::kLowerCamel,
37 /*functions=*/Case::kUnknown, // unused.
38 /*fields=*/Case::kLowerCamel,
39 /*variables=*/Case::kLowerCamel,
40 /*variants=*/Case::kKeep,
41 /*enum_variant_seperator=*/".",
42 /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
43 /*namespaces=*/Case::kSnake2,
44 /*namespace_seperator=*/".",
45 /*object_prefix=*/"",
46 /*object_suffix=*/"T",
47 /*keyword_prefix=*/"$",
48 /*keyword_suffix=*/"",
49 /*filenames=*/Case::kKeep,
50 /*directories=*/Case::kKeep,
51 /*output_path=*/"",
52 /*filename_suffix=*/"_generated",
53 /*filename_extension=*/".dart" };
54}
55
56static std::set<std::string> DartKeywords() {
57 // see https://www.dartlang.org/guides/language/language-tour#keywords
58 // yield*, async*, and sync* shouldn't be proble
59 return {
60 "abstract", "else", "import", "show", "as", "enum",
61 "in", "static", "assert", "export", "interface", "super",
62 "async", "extends", "is", "switch", "await", "extension",
63 "late", "sync", "break", "external", "library", "this",
64 "case", "factory", "mixin", "throw", "catch", "false",
65 "new", "true", "class", "final", "null", "try",
66 "const", "finally", "on", "typedef", "continue", "for",
67 "operator", "var", "covariant", "Function", "part", "void",
68 "default", "get", "required", "while", "deferred", "hide",
69 "rethrow", "with", "do", "if", "return", "yield",
70 "dynamic", "implements", "set",
71 };
72}
73} // namespace
74
Austin Schuhe89fa2d2019-08-14 20:24:23 -070075const std::string _kFb = "fb";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070076
77// Iterate through all definitions we haven't generate code for (enums, structs,
78// and tables) and output them to a single file.
79class DartGenerator : public BaseGenerator {
80 public:
81 typedef std::map<std::string, std::string> namespace_code_map;
82
83 DartGenerator(const Parser &parser, const std::string &path,
84 const std::string &file_name)
Austin Schuh2dd86a92022-09-14 21:19:23 -070085 : BaseGenerator(parser, path, file_name, "", ".", "dart"),
86 namer_(WithFlagOptions(DartDefaultConfig(), parser.opts, path),
87 DartKeywords()) {}
Austin Schuhe89fa2d2019-08-14 20:24:23 -070088 // Iterate through all definitions we haven't generate code for (enums,
89 // structs, and tables) and output them to a single file.
90 bool generate() {
91 std::string code;
92 namespace_code_map namespace_code;
Austin Schuh2dd86a92022-09-14 21:19:23 -070093 GenerateEnums(namespace_code);
94 GenerateStructs(namespace_code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -070095
96 for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
97 code.clear();
98 code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
99 code = code +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700100 "// ignore_for_file: unused_import, unused_field, unused_element, "
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700101 "unused_local_variable\n\n";
102
Austin Schuh272c6132020-11-14 16:37:52 -0800103 if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700104
105 code += "import 'dart:typed_data' show Uint8List;\n";
106 code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
107 ";\n\n";
108
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700109 for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
110 ++kv2) {
111 if (kv2->first != kv->first) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700112 code += "import './" + Filename(kv2->first, /*path=*/false) +
113 "' as " + ImportAliasName(kv2->first) + ";\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700114 }
115 }
116 code += "\n";
117 code += kv->second;
118
Austin Schuh2dd86a92022-09-14 21:19:23 -0700119 if (!SaveFile(Filename(kv->first).c_str(), code, false)) { return false; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700120 }
121 return true;
122 }
123
Austin Schuh2dd86a92022-09-14 21:19:23 -0700124 std::string Filename(const std::string &suffix, bool path = true) const {
125 return (path ? path_ : "") +
126 namer_.File(file_name_ + (suffix.empty() ? "" : "_" + suffix));
127 }
128
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700129 private:
130 static std::string ImportAliasName(const std::string &ns) {
131 std::string ret;
132 ret.assign(ns);
133 size_t pos = ret.find('.');
134 while (pos != std::string::npos) {
135 ret.replace(pos, 1, "_");
136 pos = ret.find('.', pos + 1);
137 }
138
139 return ret;
140 }
141
Austin Schuh2dd86a92022-09-14 21:19:23 -0700142 void GenerateEnums(namespace_code_map &namespace_code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700143 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
144 ++it) {
145 auto &enum_def = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700146 GenEnum(enum_def, namespace_code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700147 }
148 }
149
Austin Schuh2dd86a92022-09-14 21:19:23 -0700150 void GenerateStructs(namespace_code_map &namespace_code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700151 for (auto it = parser_.structs_.vec.begin();
152 it != parser_.structs_.vec.end(); ++it) {
153 auto &struct_def = **it;
154 GenStruct(struct_def, namespace_code);
155 }
156 }
157
158 // Generate a documentation comment, if available.
159 static void GenDocComment(const std::vector<std::string> &dc,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700160 const char *indent, std::string &code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700161 for (auto it = dc.begin(); it != dc.end(); ++it) {
162 if (indent) code += indent;
163 code += "/// " + *it + "\n";
164 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700165 }
166
167 // Generate an enum declaration and an enum string lookup table.
Austin Schuh2dd86a92022-09-14 21:19:23 -0700168 void GenEnum(EnumDef &enum_def, namespace_code_map &namespace_code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700169 if (enum_def.generated) return;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700170 std::string &code =
171 namespace_code[namer_.Namespace(*enum_def.defined_namespace)];
172 GenDocComment(enum_def.doc_comment, "", code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700173
Austin Schuh2dd86a92022-09-14 21:19:23 -0700174 const std::string enum_type =
175 namer_.Type(enum_def) + (enum_def.is_union ? "TypeId" : "");
James Kuszmaul8e62b022022-03-22 09:33:25 -0700176 const bool is_bit_flags =
177 enum_def.attributes.Lookup("bit_flags") != nullptr;
178 // The flatbuffer schema language allows bit flag enums to potentially have
179 // a default value of zero, even if it's not a valid enum value...
180 const bool permit_zero = is_bit_flags;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700181
Austin Schuh2dd86a92022-09-14 21:19:23 -0700182 code += "class " + enum_type + " {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700183 code += " final int value;\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700184 code += " const " + enum_type + "._(this.value);\n\n";
185 code += " factory " + enum_type + ".fromValue(int value) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700186 code += " final result = values[value];\n";
187 code += " if (result == null) {\n";
188 if (permit_zero) {
189 code += " if (value == 0) {\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700190 code += " return " + enum_type + "._(0);\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700191 code += " } else {\n";
192 }
193 code += " throw StateError('Invalid value $value for bit flag enum ";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700194 code += enum_type + "');\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700195 if (permit_zero) { code += " }\n"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700196 code += " }\n";
197
James Kuszmaul8e62b022022-03-22 09:33:25 -0700198 code += " return result;\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700199 code += " }\n\n";
200
Austin Schuh2dd86a92022-09-14 21:19:23 -0700201 code += " static " + enum_type + "? _createOrNull(int? value) => \n";
202 code +=
203 " value == null ? null : " + enum_type + ".fromValue(value);\n\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700204
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700205 // this is meaningless for bit_flags
206 // however, note that unlike "regular" dart enums this enum can still have
207 // holes.
208 if (!is_bit_flags) {
209 code += " static const int minValue = " +
210 enum_def.ToString(*enum_def.MinValue()) + ";\n";
211 code += " static const int maxValue = " +
212 enum_def.ToString(*enum_def.MaxValue()) + ";\n";
213 }
214
215 code +=
216 " static bool containsValue(int value) =>"
217 " values.containsKey(value);\n\n";
218
219 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
220 auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700221 const auto enum_var = namer_.Variant(ev);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700222
223 if (!ev.doc_comment.empty()) {
224 if (it != enum_def.Vals().begin()) { code += '\n'; }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700225 GenDocComment(ev.doc_comment, " ", code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700226 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700227 code += " static const " + enum_type + " " + enum_var + " = " +
228 enum_type + "._(" + enum_def.ToString(ev) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700229 }
230
Austin Schuh2dd86a92022-09-14 21:19:23 -0700231 code += " static const Map<int, " + enum_type + "> values = {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700232 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
233 auto &ev = **it;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700234 const auto enum_var = namer_.Variant(ev);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700235 if (it != enum_def.Vals().begin()) code += ",\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700236 code += " " + enum_def.ToString(ev) + ": " + enum_var;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700237 }
238 code += "};\n\n";
239
Austin Schuh2dd86a92022-09-14 21:19:23 -0700240 code += " static const " + _kFb + ".Reader<" + enum_type + "> reader = _" +
241 enum_type + "Reader();\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700242 code += " @override\n";
243 code += " String toString() {\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700244 code += " return '" + enum_type + "{value: $value}';\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700245 code += " }\n";
246 code += "}\n\n";
247
Austin Schuh2dd86a92022-09-14 21:19:23 -0700248 GenEnumReader(enum_def, enum_type, code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700249 }
250
Austin Schuh2dd86a92022-09-14 21:19:23 -0700251 void GenEnumReader(EnumDef &enum_def, const std::string &enum_type,
252 std::string &code) {
253 code += "class _" + enum_type + "Reader extends " + _kFb + ".Reader<" +
254 enum_type + "> {\n";
255 code += " const _" + enum_type + "Reader();\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700256 code += " @override\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700257 code += " int get size => " + EnumSize(enum_def.underlying_type) + ";\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700258 code += " @override\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700259 code += " " + enum_type + " read(" + _kFb +
260 ".BufferContext bc, int offset) =>\n";
261 code += " " + enum_type + ".fromValue(const " + _kFb + "." +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700262 GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
263 code += "}\n\n";
264 }
265
Austin Schuh2dd86a92022-09-14 21:19:23 -0700266 std::string GenType(const Type &type) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700267 switch (type.base_type) {
268 case BASE_TYPE_BOOL: return "Bool";
269 case BASE_TYPE_CHAR: return "Int8";
270 case BASE_TYPE_UTYPE:
271 case BASE_TYPE_UCHAR: return "Uint8";
272 case BASE_TYPE_SHORT: return "Int16";
273 case BASE_TYPE_USHORT: return "Uint16";
274 case BASE_TYPE_INT: return "Int32";
275 case BASE_TYPE_UINT: return "Uint32";
276 case BASE_TYPE_LONG: return "Int64";
277 case BASE_TYPE_ULONG: return "Uint64";
278 case BASE_TYPE_FLOAT: return "Float32";
279 case BASE_TYPE_DOUBLE: return "Float64";
280 case BASE_TYPE_STRING: return "String";
281 case BASE_TYPE_VECTOR: return GenType(type.VectorType());
Austin Schuh2dd86a92022-09-14 21:19:23 -0700282 case BASE_TYPE_STRUCT: return namer_.Type(*type.struct_def);
283 case BASE_TYPE_UNION: return namer_.Type(*type.enum_def) + "TypeId";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700284 default: return "Table";
285 }
286 }
287
Austin Schuh2dd86a92022-09-14 21:19:23 -0700288 static std::string EnumSize(const Type &type) {
289 switch (type.base_type) {
290 case BASE_TYPE_BOOL:
291 case BASE_TYPE_CHAR:
292 case BASE_TYPE_UTYPE:
293 case BASE_TYPE_UCHAR: return "1";
294 case BASE_TYPE_SHORT:
295 case BASE_TYPE_USHORT: return "2";
296 case BASE_TYPE_INT:
297 case BASE_TYPE_UINT:
298 case BASE_TYPE_FLOAT: return "4";
299 case BASE_TYPE_LONG:
300 case BASE_TYPE_ULONG:
301 case BASE_TYPE_DOUBLE: return "8";
302 default: return "1";
303 }
304 }
305
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700306 std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
307 const FieldDef &def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700308 bool parent_is_vector = false, bool lazy = true,
309 bool constConstruct = true) {
310 std::string prefix = (constConstruct ? "const " : "") + _kFb;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700311 if (type.base_type == BASE_TYPE_BOOL) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700312 return prefix + ".BoolReader()";
Austin Schuh272c6132020-11-14 16:37:52 -0800313 } else if (IsVector(type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700314 if (!type.VectorType().enum_def) {
315 if (type.VectorType().base_type == BASE_TYPE_CHAR) {
316 return prefix + ".Int8ListReader(" + (lazy ? ")" : "lazy: false)");
317 }
318 if (type.VectorType().base_type == BASE_TYPE_UCHAR) {
319 return prefix + ".Uint8ListReader(" + (lazy ? ")" : "lazy: false)");
320 }
321 }
322 return prefix + ".ListReader<" +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700323 GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700324 GenReaderTypeName(type.VectorType(), current_namespace, def, true,
325 true, false) +
326 (lazy ? ")" : ", lazy: false)");
Austin Schuh272c6132020-11-14 16:37:52 -0800327 } else if (IsString(type)) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700328 return prefix + ".StringReader()";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700329 }
330 if (IsScalar(type.base_type)) {
331 if (type.enum_def && parent_is_vector) {
332 return GenDartTypeName(type, current_namespace, def) + ".reader";
333 }
James Kuszmaul8e62b022022-03-22 09:33:25 -0700334 return prefix + "." + GenType(type) + "Reader()";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700335 } else {
336 return GenDartTypeName(type, current_namespace, def) + ".reader";
337 }
338 }
339
340 std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700341 const FieldDef &def,
342 std::string struct_type_suffix = "") {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700343 if (type.enum_def) {
344 if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700345 return namer_.Type(*type.enum_def) + "TypeId";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700346 } else if (type.enum_def->is_union) {
347 return "dynamic";
348 } else if (type.base_type != BASE_TYPE_VECTOR) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700349 return namer_.Type(*type.enum_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700350 }
351 }
352
353 switch (type.base_type) {
354 case BASE_TYPE_BOOL: return "bool";
355 case BASE_TYPE_LONG:
356 case BASE_TYPE_ULONG:
357 case BASE_TYPE_INT:
358 case BASE_TYPE_UINT:
359 case BASE_TYPE_SHORT:
360 case BASE_TYPE_USHORT:
361 case BASE_TYPE_CHAR:
362 case BASE_TYPE_UCHAR: return "int";
363 case BASE_TYPE_FLOAT:
364 case BASE_TYPE_DOUBLE: return "double";
365 case BASE_TYPE_STRING: return "String";
366 case BASE_TYPE_STRUCT:
Austin Schuh2dd86a92022-09-14 21:19:23 -0700367 return MaybeWrapNamespace(
368 namer_.Type(*type.struct_def) + struct_type_suffix,
369 current_namespace, def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700370 case BASE_TYPE_VECTOR:
371 return "List<" +
372 GenDartTypeName(type.VectorType(), current_namespace, def,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700373 struct_type_suffix) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700374 ">";
375 default: assert(0); return "dynamic";
376 }
377 }
378
James Kuszmaul8e62b022022-03-22 09:33:25 -0700379 std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
380 const FieldDef &def, bool nullable,
381 std::string struct_type_suffix) {
382 std::string typeName =
383 GenDartTypeName(type, current_namespace, def, struct_type_suffix);
384 if (nullable && typeName != "dynamic") typeName += "?";
385 return typeName;
386 }
387
Austin Schuh2dd86a92022-09-14 21:19:23 -0700388 std::string MaybeWrapNamespace(const std::string &type_name,
389 Namespace *current_ns,
390 const FieldDef &field) const {
391 const std::string current_namespace = namer_.Namespace(*current_ns);
392 const std::string field_namespace =
393 field.value.type.struct_def
394 ? namer_.Namespace(*field.value.type.struct_def->defined_namespace)
395 : field.value.type.enum_def
396 ? namer_.Namespace(*field.value.type.enum_def->defined_namespace)
397 : "";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700398
Austin Schuh2dd86a92022-09-14 21:19:23 -0700399 if (field_namespace != "" && field_namespace != current_namespace) {
400 return ImportAliasName(field_namespace) + "." + type_name;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700401 } else {
402 return type_name;
403 }
404 }
405
406 // Generate an accessor struct with constructor for a flatbuffers struct.
407 void GenStruct(const StructDef &struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700408 namespace_code_map &namespace_code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700409 if (struct_def.generated) return;
410
Austin Schuh2dd86a92022-09-14 21:19:23 -0700411 std::string &code =
412 namespace_code[namer_.Namespace(*struct_def.defined_namespace)];
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700413
Austin Schuh2dd86a92022-09-14 21:19:23 -0700414 const auto &struct_type = namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700415
416 // Emit constructor
417
Austin Schuh2dd86a92022-09-14 21:19:23 -0700418 GenDocComment(struct_def.doc_comment, "", code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700419
Austin Schuh2dd86a92022-09-14 21:19:23 -0700420 auto reader_name = "_" + struct_type + "Reader";
421 auto builder_name = struct_type + "Builder";
422 auto object_builder_name = struct_type + "ObjectBuilder";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700423
424 std::string reader_code, builder_code;
425
Austin Schuh2dd86a92022-09-14 21:19:23 -0700426 code += "class " + struct_type + " {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700427
Austin Schuh2dd86a92022-09-14 21:19:23 -0700428 code += " " + struct_type + "._(this._bc, this._bcOffset);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700429 if (!struct_def.fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700430 code += " factory " + struct_type + "(List<int> bytes) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700431 code +=
432 " final rootRef = " + _kFb + ".BufferContext.fromBytes(bytes);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700433 code += " return reader.read(rootRef, 0);\n";
434 code += " }\n";
435 }
436
437 code += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700438 code += " static const " + _kFb + ".Reader<" + struct_type +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700439 "> reader = " + reader_name + "();\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700440
441 code += " final " + _kFb + ".BufferContext _bc;\n";
442 code += " final int _bcOffset;\n\n";
443
Austin Schuh272c6132020-11-14 16:37:52 -0800444 std::vector<std::pair<int, FieldDef *>> non_deprecated_fields;
445 for (auto it = struct_def.fields.vec.begin();
446 it != struct_def.fields.vec.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700447 FieldDef &field = **it;
Austin Schuh272c6132020-11-14 16:37:52 -0800448 if (field.deprecated) continue;
449 auto offset = static_cast<int>(it - struct_def.fields.vec.begin());
450 non_deprecated_fields.push_back(std::make_pair(offset, &field));
451 }
452
Austin Schuh2dd86a92022-09-14 21:19:23 -0700453 GenImplementationGetters(struct_def, non_deprecated_fields, code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700454
James Kuszmaul8e62b022022-03-22 09:33:25 -0700455 if (parser_.opts.generate_object_based_api) {
456 code +=
457 "\n" + GenStructObjectAPIUnpack(struct_def, non_deprecated_fields);
458
Austin Schuh2dd86a92022-09-14 21:19:23 -0700459 code += "\n static int pack(fb.Builder fbBuilder, " +
460 namer_.ObjectType(struct_def) + "? object) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700461 code += " if (object == null) return 0;\n";
462 code += " return object.pack(fbBuilder);\n";
463 code += " }\n";
464 }
465
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700466 code += "}\n\n";
467
James Kuszmaul8e62b022022-03-22 09:33:25 -0700468 if (parser_.opts.generate_object_based_api) {
469 code += GenStructObjectAPI(struct_def, non_deprecated_fields);
470 }
471
Austin Schuh2dd86a92022-09-14 21:19:23 -0700472 GenReader(struct_def, reader_name, reader_code);
473 GenBuilder(struct_def, non_deprecated_fields, builder_name, builder_code);
474 GenObjectBuilder(struct_def, non_deprecated_fields, object_builder_name,
475 builder_code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700476
477 code += reader_code;
478 code += builder_code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700479 }
480
James Kuszmaul8e62b022022-03-22 09:33:25 -0700481 // Generate an accessor struct with constructor for a flatbuffers struct.
482 std::string GenStructObjectAPI(
483 const StructDef &struct_def,
484 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
485 std::string code;
Austin Schuh2dd86a92022-09-14 21:19:23 -0700486 GenDocComment(struct_def.doc_comment, "", code);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700487
Austin Schuh2dd86a92022-09-14 21:19:23 -0700488 std::string object_type = namer_.ObjectType(struct_def);
489 code += "class " + object_type + " implements " + _kFb + ".Packable {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700490
491 std::string constructor_args;
492 for (auto it = non_deprecated_fields.begin();
493 it != non_deprecated_fields.end(); ++it) {
494 const FieldDef &field = *it->second;
495
Austin Schuh2dd86a92022-09-14 21:19:23 -0700496 const std::string field_name = namer_.Field(field);
497 const std::string defaultValue = getDefaultValue(field.value);
498 const std::string type_name =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700499 GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
500 defaultValue.empty() && !struct_def.fixed, "T");
501
Austin Schuh2dd86a92022-09-14 21:19:23 -0700502 GenDocComment(field.doc_comment, " ", code);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700503 code += " " + type_name + " " + field_name + ";\n";
504
505 if (!constructor_args.empty()) constructor_args += ",\n";
506 constructor_args += " ";
507 constructor_args += (struct_def.fixed ? "required " : "");
508 constructor_args += "this." + field_name;
509 if (!struct_def.fixed && !defaultValue.empty()) {
510 if (IsEnum(field.value.type)) {
511 auto &enum_def = *field.value.type.enum_def;
512 if (auto val = enum_def.FindByValue(defaultValue)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700513 constructor_args += " = " + namer_.EnumVariant(enum_def, *val);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700514 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700515 constructor_args += " = const " + namer_.Type(enum_def) + "._(" +
516 defaultValue + ")";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700517 }
518 } else {
519 constructor_args += " = " + defaultValue;
520 }
521 }
522 }
523
524 if (!constructor_args.empty()) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700525 code += "\n " + object_type + "({\n" + constructor_args + "});\n\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700526 }
527
528 code += GenStructObjectAPIPack(struct_def, non_deprecated_fields);
529 code += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700530 code += GenToString(object_type, non_deprecated_fields);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700531
532 code += "}\n\n";
533 return code;
534 }
535
536 // Generate function `StructNameT unpack()`
537 std::string GenStructObjectAPIUnpack(
538 const StructDef &struct_def,
539 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
540 std::string constructor_args;
541 for (auto it = non_deprecated_fields.begin();
542 it != non_deprecated_fields.end(); ++it) {
543 const FieldDef &field = *it->second;
544
Austin Schuh2dd86a92022-09-14 21:19:23 -0700545 const std::string field_name = namer_.Field(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700546 if (!constructor_args.empty()) constructor_args += ",\n";
547 constructor_args += " " + field_name + ": ";
548
549 const Type &type = field.value.type;
550 std::string defaultValue = getDefaultValue(field.value);
551 bool isNullable = defaultValue.empty() && !struct_def.fixed;
552 std::string nullableValueAccessOperator = isNullable ? "?" : "";
553 if (type.base_type == BASE_TYPE_STRUCT) {
554 constructor_args +=
555 field_name + nullableValueAccessOperator + ".unpack()";
556 } else if (type.base_type == BASE_TYPE_VECTOR) {
557 if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
558 constructor_args += field_name + nullableValueAccessOperator +
559 ".map((e) => e.unpack()).toList()";
560 } else {
561 constructor_args +=
562 GenReaderTypeName(field.value.type, struct_def.defined_namespace,
563 field, false, false);
564 constructor_args += ".vTableGet";
565 std::string offset = NumToString(field.value.offset);
566 constructor_args +=
567 isNullable
568 ? "Nullable(_bc, _bcOffset, " + offset + ")"
569 : "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
570 }
571 } else {
572 constructor_args += field_name;
573 }
574 }
575
Austin Schuh2dd86a92022-09-14 21:19:23 -0700576 const std::string object_type = namer_.ObjectType(struct_def);
577 std::string code = " " + object_type + " unpack() => " + object_type + "(";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700578 if (!constructor_args.empty()) code += "\n" + constructor_args;
579 code += ");\n";
580 return code;
581 }
582
583 // Generate function `StructNameT pack()`
584 std::string GenStructObjectAPIPack(
585 const StructDef &struct_def,
586 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
587 std::string code;
588
589 code += " @override\n";
590 code += " int pack(fb.Builder fbBuilder) {\n";
591 code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields,
592 false, true);
593 code += " }\n";
594 return code;
595 }
596
Austin Schuh272c6132020-11-14 16:37:52 -0800597 std::string NamespaceAliasFromUnionType(Namespace *root_namespace,
598 const Type &type) {
599 const std::vector<std::string> qualified_name_parts =
600 type.struct_def->defined_namespace->components;
601 if (std::equal(root_namespace->components.begin(),
602 root_namespace->components.end(),
603 qualified_name_parts.begin())) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700604 return namer_.Type(*type.struct_def);
Austin Schuh272c6132020-11-14 16:37:52 -0800605 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700606
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700607 std::string ns;
608
Austin Schuh272c6132020-11-14 16:37:52 -0800609 for (auto it = qualified_name_parts.begin();
610 it != qualified_name_parts.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700611 auto &part = *it;
612
613 for (size_t i = 0; i < part.length(); i++) {
Austin Schuh272c6132020-11-14 16:37:52 -0800614 if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700615 ns += "_";
Austin Schuh272c6132020-11-14 16:37:52 -0800616 ns += CharToLower(part[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700617 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800618 ns += CharToLower(part[i]);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700619 }
620 }
Austin Schuh272c6132020-11-14 16:37:52 -0800621 if (it != qualified_name_parts.end() - 1) { ns += "_"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700622 }
623
Austin Schuh2dd86a92022-09-14 21:19:23 -0700624 return ns + "." + namer_.Type(*type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700625 }
626
Austin Schuh272c6132020-11-14 16:37:52 -0800627 void GenImplementationGetters(
628 const StructDef &struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700629 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
630 std::string &code) {
Austin Schuh272c6132020-11-14 16:37:52 -0800631 for (auto it = non_deprecated_fields.begin();
632 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700633 const FieldDef &field = *it->second;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700634
Austin Schuh2dd86a92022-09-14 21:19:23 -0700635 const std::string field_name = namer_.Field(field);
636 const std::string defaultValue = getDefaultValue(field.value);
637 const bool isNullable = defaultValue.empty() && !struct_def.fixed;
638 const std::string type_name =
James Kuszmaul8e62b022022-03-22 09:33:25 -0700639 GenDartTypeName(field.value.type, struct_def.defined_namespace, field,
640 isNullable, "");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700641
Austin Schuh2dd86a92022-09-14 21:19:23 -0700642 GenDocComment(field.doc_comment, " ", code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700643
644 code += " " + type_name + " get " + field_name;
645 if (field.value.type.base_type == BASE_TYPE_UNION) {
646 code += " {\n";
647 code += " switch (" + field_name + "Type?.value) {\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700648 const auto &enum_def = *field.value.type.enum_def;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700649 for (auto en_it = enum_def.Vals().begin() + 1;
650 en_it != enum_def.Vals().end(); ++en_it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700651 const auto &ev = **en_it;
652 const auto enum_name = NamespaceAliasFromUnionType(
Austin Schuh272c6132020-11-14 16:37:52 -0800653 enum_def.defined_namespace, ev.union_type);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700654 code += " case " + enum_def.ToString(ev) + ": return " +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700655 enum_name + ".reader.vTableGetNullable(_bc, _bcOffset, " +
656 NumToString(field.value.offset) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700657 }
658 code += " default: return null;\n";
659 code += " }\n";
660 code += " }\n";
661 } else {
662 code += " => ";
663 if (field.value.type.enum_def &&
664 field.value.type.base_type != BASE_TYPE_VECTOR) {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700665 code += GenDartTypeName(field.value.type,
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700666 struct_def.defined_namespace, field) +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700667 (isNullable ? "._createOrNull(" : ".fromValue(");
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700668 }
669
670 code += GenReaderTypeName(field.value.type,
671 struct_def.defined_namespace, field);
672 if (struct_def.fixed) {
673 code +=
674 ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
675 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700676 code += ".vTableGet";
677 std::string offset = NumToString(field.value.offset);
678 if (isNullable) {
679 code += "Nullable(_bc, _bcOffset, " + offset + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700680 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700681 code += "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700682 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700683 }
684 if (field.value.type.enum_def &&
685 field.value.type.base_type != BASE_TYPE_VECTOR) {
686 code += ")";
687 }
688 code += ";\n";
689 }
690 }
691
692 code += "\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700693 code += GenToString(namer_.Type(struct_def), non_deprecated_fields);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700694 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700695
James Kuszmaul8e62b022022-03-22 09:33:25 -0700696 std::string GenToString(
697 const std::string &object_name,
698 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields) {
699 std::string code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700700 code += " @override\n";
701 code += " String toString() {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700702 code += " return '" + object_name + "{";
Austin Schuh272c6132020-11-14 16:37:52 -0800703 for (auto it = non_deprecated_fields.begin();
704 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700705 const std::string field = namer_.Field(*it->second);
706 // We need to escape the fact that some fields have $ in the name which is
707 // also used in symbol/string substitution.
708 std::string escaped_field;
709 for (size_t i = 0; i < field.size(); i++) {
710 if (field[i] == '$') escaped_field.push_back('\\');
711 escaped_field.push_back(field[i]);
712 }
713 code += escaped_field + ": ${" + field + "}";
Austin Schuh272c6132020-11-14 16:37:52 -0800714 if (it != non_deprecated_fields.end() - 1) { code += ", "; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700715 }
716 code += "}';\n";
717 code += " }\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700718 return code;
719 }
720
721 std::string getDefaultValue(const Value &value) const {
722 if (!value.constant.empty() && value.constant != "0") {
723 if (IsBool(value.type.base_type)) {
724 return "true";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700725 }
James Kuszmaul3b15b0c2022-11-08 14:03:16 -0800726 if (IsScalar(value.type.base_type)) {
727 if (StringIsFlatbufferNan(value.constant)) {
728 return "double.nan";
729 } else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
730 return "double.infinity";
731 } else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
732 return "double.negativeInfinity";
733 }
734 }
735 return value.constant;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700736 } else if (IsBool(value.type.base_type)) {
737 return "false";
738 } else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
739 return "0";
740 } else {
741 return "";
742 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700743 }
744
Austin Schuh2dd86a92022-09-14 21:19:23 -0700745 void GenReader(const StructDef &struct_def, const std::string &reader_name,
746 std::string &code) {
747 const auto struct_type = namer_.Type(struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700748
749 code += "class " + reader_name + " extends " + _kFb;
750 if (struct_def.fixed) {
751 code += ".StructReader<";
752 } else {
753 code += ".TableReader<";
754 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700755 code += struct_type + "> {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700756 code += " const " + reader_name + "();\n\n";
757
758 if (struct_def.fixed) {
759 code += " @override\n";
760 code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
761 }
762 code += " @override\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700763 code += " " + struct_type +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700764 " createObject(fb.BufferContext bc, int offset) => \n " +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700765 struct_type + "._(bc, offset);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700766 code += "}\n\n";
767 }
768
Austin Schuh2dd86a92022-09-14 21:19:23 -0700769 void GenBuilder(
770 const StructDef &struct_def,
771 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
772 const std::string &builder_name, std::string &code) {
Austin Schuh272c6132020-11-14 16:37:52 -0800773 if (non_deprecated_fields.size() == 0) { return; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700774
775 code += "class " + builder_name + " {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700776 code += " " + builder_name + "(this.fbBuilder);\n\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700777 code += " final " + _kFb + ".Builder fbBuilder;\n\n";
778
779 if (struct_def.fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700780 StructBuilderBody(struct_def, non_deprecated_fields, code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700781 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700782 TableBuilderBody(struct_def, non_deprecated_fields, code);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700783 }
784
785 code += "}\n\n";
786 }
787
Austin Schuh272c6132020-11-14 16:37:52 -0800788 void StructBuilderBody(
789 const StructDef &struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700790 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
791 std::string &code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700792 code += " int finish(";
Austin Schuh272c6132020-11-14 16:37:52 -0800793 for (auto it = non_deprecated_fields.begin();
794 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700795 const FieldDef &field = *it->second;
796 const std::string field_name = namer_.Field(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700797
798 if (IsStruct(field.value.type)) {
799 code += "fb.StructBuilder";
800 } else {
801 code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
802 field);
803 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700804 code += " " + field_name;
Austin Schuh272c6132020-11-14 16:37:52 -0800805 if (it != non_deprecated_fields.end() - 1) { code += ", "; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700806 }
807 code += ") {\n";
808
Austin Schuh272c6132020-11-14 16:37:52 -0800809 for (auto it = non_deprecated_fields.rbegin();
810 it != non_deprecated_fields.rend(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700811 const FieldDef &field = *it->second;
812 const std::string field_name = namer_.Field(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700813
814 if (field.padding) {
815 code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
816 }
817
818 if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700819 code += " " + field_name + "();\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700820 } else {
821 code += " fbBuilder.put" + GenType(field.value.type) + "(";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700822 code += field_name;
James Kuszmaul8e62b022022-03-22 09:33:25 -0700823 if (field.value.type.enum_def) { code += ".value"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700824 code += ");\n";
825 }
826 }
827 code += " return fbBuilder.offset;\n";
828 code += " }\n\n";
829 }
830
Austin Schuh272c6132020-11-14 16:37:52 -0800831 void TableBuilderBody(
832 const StructDef &struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700833 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
834 std::string &code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700835 code += " void begin() {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700836 code += " fbBuilder.startTable(" +
837 NumToString(struct_def.fields.vec.size()) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700838 code += " }\n\n";
839
Austin Schuh272c6132020-11-14 16:37:52 -0800840 for (auto it = non_deprecated_fields.begin();
841 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700842 const auto &field = *it->second;
843 const auto offset = it->first;
844 const std::string add_field = namer_.Method("add", field);
845 const std::string field_var = namer_.Variable(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700846
847 if (IsScalar(field.value.type.base_type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700848 code += " int " + add_field + "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700849 code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
850 field);
Austin Schuh2dd86a92022-09-14 21:19:23 -0700851 code += "? " + field_var + ") {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700852 code += " fbBuilder.add" + GenType(field.value.type) + "(" +
853 NumToString(offset) + ", ";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700854 code += field_var;
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700855 if (field.value.type.enum_def) { code += "?.value"; }
856 code += ");\n";
857 } else if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700858 code += " int " + add_field + "(int offset) {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700859 code +=
860 " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
861 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700862 code += " int " + add_field + "Offset(int? offset) {\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700863 code +=
864 " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
865 }
866 code += " return fbBuilder.offset;\n";
867 code += " }\n";
868 }
869
870 code += "\n";
871 code += " int finish() {\n";
872 code += " return fbBuilder.endTable();\n";
873 code += " }\n";
874 }
875
Austin Schuh272c6132020-11-14 16:37:52 -0800876 void GenObjectBuilder(
877 const StructDef &struct_def,
Austin Schuh2dd86a92022-09-14 21:19:23 -0700878 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
879 const std::string &builder_name, std::string &code) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700880 code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
Austin Schuh272c6132020-11-14 16:37:52 -0800881 for (auto it = non_deprecated_fields.begin();
882 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700883 const FieldDef &field = *it->second;
Austin Schuh272c6132020-11-14 16:37:52 -0800884
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700885 code += " final " +
886 GenDartTypeName(field.value.type, struct_def.defined_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700887 field, !struct_def.fixed, "ObjectBuilder") +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700888 " _" + namer_.Variable(field) + ";\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700889 }
890 code += "\n";
891 code += " " + builder_name + "(";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700892
Austin Schuh272c6132020-11-14 16:37:52 -0800893 if (non_deprecated_fields.size() != 0) {
894 code += "{\n";
895 for (auto it = non_deprecated_fields.begin();
896 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700897 const FieldDef &field = *it->second;
Austin Schuh272c6132020-11-14 16:37:52 -0800898
James Kuszmaul8e62b022022-03-22 09:33:25 -0700899 code += " ";
900 code += (struct_def.fixed ? "required " : "") +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700901 GenDartTypeName(field.value.type, struct_def.defined_namespace,
James Kuszmaul8e62b022022-03-22 09:33:25 -0700902 field, !struct_def.fixed, "ObjectBuilder") +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700903 " " + namer_.Variable(field) + ",\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700904 }
905 code += " })\n";
906 code += " : ";
Austin Schuh272c6132020-11-14 16:37:52 -0800907 for (auto it = non_deprecated_fields.begin();
908 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700909 const FieldDef &field = *it->second;
Austin Schuh272c6132020-11-14 16:37:52 -0800910
Austin Schuh2dd86a92022-09-14 21:19:23 -0700911 code += "_" + namer_.Variable(field) + " = " + namer_.Variable(field);
Austin Schuh272c6132020-11-14 16:37:52 -0800912 if (it == non_deprecated_fields.end() - 1) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700913 code += ";\n\n";
914 } else {
915 code += ",\n ";
916 }
917 }
918 } else {
919 code += ");\n\n";
920 }
921
922 code += " /// Finish building, and store into the [fbBuilder].\n";
923 code += " @override\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700924 code += " int finish(" + _kFb + ".Builder fbBuilder) {\n";
925 code += GenObjectBuilderImplementation(struct_def, non_deprecated_fields);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700926 code += " }\n\n";
927
928 code += " /// Convenience method to serialize to byte list.\n";
929 code += " @override\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700930 code += " Uint8List toBytes([String? fileIdentifier]) {\n";
931 code += " final fbBuilder = " + _kFb +
932 ".Builder(deduplicateTables: false);\n";
933 code += " fbBuilder.finish(finish(fbBuilder), fileIdentifier);\n";
934 code += " return fbBuilder.buffer;\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700935 code += " }\n";
936 code += "}\n";
937 }
938
James Kuszmaul8e62b022022-03-22 09:33:25 -0700939 std::string GenObjectBuilderImplementation(
940 const StructDef &struct_def,
941 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
942 bool prependUnderscore = true, bool pack = false) {
943 std::string code;
944 for (auto it = non_deprecated_fields.begin();
945 it != non_deprecated_fields.end(); ++it) {
946 const FieldDef &field = *it->second;
947
948 if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
949 continue;
950
Austin Schuh2dd86a92022-09-14 21:19:23 -0700951 std::string offset_name = namer_.Variable(field) + "Offset";
952 std::string field_name =
953 (prependUnderscore ? "_" : "") + namer_.Variable(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700954 // custom handling for fixed-sized struct in pack()
955 if (pack && IsVector(field.value.type) &&
956 field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
957 field.value.type.struct_def->fixed) {
958 code += " int? " + offset_name + ";\n";
959 code += " if (" + field_name + " != null) {\n";
960 code +=
961 " for (var e in " + field_name + "!) { e.pack(fbBuilder); }\n";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700962 code += " " + namer_.Variable(field) +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700963 "Offset = fbBuilder.endStructVector(" + field_name +
964 "!.length);\n";
965 code += " }\n";
966 continue;
967 }
968
969 code += " final int? " + offset_name;
970 if (IsVector(field.value.type)) {
971 code += " = " + field_name + " == null ? null\n";
972 code += " : fbBuilder.writeList";
973 switch (field.value.type.VectorType().base_type) {
974 case BASE_TYPE_STRING:
975 code +=
976 "(" + field_name + "!.map(fbBuilder.writeString).toList());\n";
977 break;
978 case BASE_TYPE_STRUCT:
979 if (field.value.type.struct_def->fixed) {
980 code += "OfStructs(" + field_name + "!);\n";
981 } else {
982 code += "(" + field_name + "!.map((b) => b." +
983 (pack ? "pack" : "getOrCreateOffset") +
984 "(fbBuilder)).toList());\n";
985 }
986 break;
987 default:
988 code +=
989 GenType(field.value.type.VectorType()) + "(" + field_name + "!";
990 if (field.value.type.enum_def) {
991 code += ".map((f) => f.value).toList()";
992 }
993 code += ");\n";
994 }
995 } else if (IsString(field.value.type)) {
996 code += " = " + field_name + " == null ? null\n";
997 code += " : fbBuilder.writeString(" + field_name + "!);\n";
998 } else {
999 code += " = " + field_name + "?." +
1000 (pack ? "pack" : "getOrCreateOffset") + "(fbBuilder);\n";
1001 }
1002 }
1003
1004 if (struct_def.fixed) {
1005 code += StructObjectBuilderBody(non_deprecated_fields, prependUnderscore,
1006 pack);
1007 } else {
1008 code += TableObjectBuilderBody(struct_def, non_deprecated_fields,
1009 prependUnderscore, pack);
1010 }
1011 return code;
1012 }
1013
1014 std::string StructObjectBuilderBody(
1015 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1016 bool prependUnderscore = true, bool pack = false) {
1017 std::string code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001018
Austin Schuh272c6132020-11-14 16:37:52 -08001019 for (auto it = non_deprecated_fields.rbegin();
1020 it != non_deprecated_fields.rend(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001021 const FieldDef &field = *it->second;
1022 const std::string field_name = namer_.Field(field);
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001023
1024 if (field.padding) {
1025 code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
1026 }
1027
1028 if (IsStruct(field.value.type)) {
1029 code += " ";
1030 if (prependUnderscore) { code += "_"; }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001031 code += field_name + (pack ? ".pack" : ".finish") + "(fbBuilder);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001032 } else {
1033 code += " fbBuilder.put" + GenType(field.value.type) + "(";
1034 if (prependUnderscore) { code += "_"; }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001035 code += field_name;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001036 if (field.value.type.enum_def) { code += ".value"; }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001037 code += ");\n";
1038 }
1039 }
1040
1041 code += " return fbBuilder.offset;\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001042 return code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001043 }
1044
James Kuszmaul8e62b022022-03-22 09:33:25 -07001045 std::string TableObjectBuilderBody(
1046 const StructDef &struct_def,
1047 const std::vector<std::pair<int, FieldDef *>> &non_deprecated_fields,
1048 bool prependUnderscore = true, bool pack = false) {
1049 std::string code;
1050 code += " fbBuilder.startTable(" +
1051 NumToString(struct_def.fields.vec.size()) + ");\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001052
Austin Schuh272c6132020-11-14 16:37:52 -08001053 for (auto it = non_deprecated_fields.begin();
1054 it != non_deprecated_fields.end(); ++it) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001055 const FieldDef &field = *it->second;
1056 auto offset = it->first;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001057
Austin Schuh2dd86a92022-09-14 21:19:23 -07001058 std::string field_var =
1059 (prependUnderscore ? "_" : "") + namer_.Variable(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -07001060
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001061 if (IsScalar(field.value.type.base_type)) {
1062 code += " fbBuilder.add" + GenType(field.value.type) + "(" +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001063 NumToString(offset) + ", " + field_var;
James Kuszmaul8e62b022022-03-22 09:33:25 -07001064 if (field.value.type.enum_def) {
1065 bool isNullable = getDefaultValue(field.value).empty();
1066 code += (isNullable || !pack) ? "?.value" : ".value";
1067 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001068 code += ");\n";
1069 } else if (IsStruct(field.value.type)) {
Austin Schuh2dd86a92022-09-14 21:19:23 -07001070 code += " if (" + field_var + " != null) {\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001071 code += " fbBuilder.addStruct(" + NumToString(offset) + ", " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001072 field_var + (pack ? "!.pack" : "!.finish") + "(fbBuilder));\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001073 code += " }\n";
1074 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -07001075 code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
Austin Schuh2dd86a92022-09-14 21:19:23 -07001076 namer_.Variable(field) + "Offset);\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001077 }
1078 }
1079 code += " return fbBuilder.endTable();\n";
James Kuszmaul8e62b022022-03-22 09:33:25 -07001080 return code;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001081 }
Austin Schuh2dd86a92022-09-14 21:19:23 -07001082
1083 const IdlNamer namer_;
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001084};
1085} // namespace dart
1086
1087bool GenerateDart(const Parser &parser, const std::string &path,
1088 const std::string &file_name) {
1089 dart::DartGenerator generator(parser, path, file_name);
1090 return generator.generate();
1091}
1092
1093std::string DartMakeRule(const Parser &parser, const std::string &path,
1094 const std::string &file_name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001095 auto filebase =
1096 flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
Austin Schuh272c6132020-11-14 16:37:52 -08001097 dart::DartGenerator generator(parser, path, file_name);
Austin Schuh2dd86a92022-09-14 21:19:23 -07001098 auto make_rule = generator.Filename("") + ": ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001099
1100 auto included_files = parser.GetIncludedFilesRecursive(file_name);
1101 for (auto it = included_files.begin(); it != included_files.end(); ++it) {
1102 make_rule += " " + *it;
1103 }
1104 return make_rule;
1105}
1106
1107} // namespace flatbuffers