2 * Copyright 2014 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // independent from idl_parser, since this code is not needed for most clients
20 #include <unordered_set>
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/idl.h"
24 #include "flatbuffers/util.h"
25 #if defined(FLATBUFFERS_CPP98_STL)
27 #endif // defined(FLATBUFFERS_CPP98_STL)
29 namespace flatbuffers {
33 typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
34 static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
38 static const CommentConfig comment_config = {"/**", " *", " */"};
39 static const std::string ident_pad = " ";
40 static const char *keywords[] = {
41 "package", "as", "typealias", "class", "this", "super",
42 "val", "var", "fun", "for", "null", "true",
43 "false", "is", "in", "throw", "return", "break",
44 "continue", "object", "if", "try", "else", "while",
45 "do", "when", "interface", "typeof", "Any", "Character"};
48 static std::string Esc(const std::string &name) {
49 for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
50 if (name == keywords[i]) {
51 return MakeCamel(name + "_", false);
55 return MakeCamel(name, false);
58 class KotlinGenerator : public BaseGenerator {
60 KotlinGenerator(const Parser &parser, const std::string &path,
61 const std::string &file_name)
62 : BaseGenerator(parser, path, file_name, "", "."),
63 cur_name_space_(nullptr) {}
65 KotlinGenerator &operator=(const KotlinGenerator &);
66 bool generate() FLATBUFFERS_OVERRIDE {
67 std::string one_file_code;
69 cur_name_space_ = parser_.current_namespace_;
70 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
72 CodeWriter enumWriter(ident_pad);
73 auto &enum_def = **it;
74 if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
75 GenEnum(enum_def, enumWriter);
76 if (parser_.opts.one_file) {
77 one_file_code += enumWriter.ToString();
79 if (!SaveType(enum_def.name, *enum_def.defined_namespace,
80 enumWriter.ToString(), false))
85 for (auto it = parser_.structs_.vec.begin();
86 it != parser_.structs_.vec.end(); ++it) {
87 CodeWriter structWriter(ident_pad);
88 auto &struct_def = **it;
89 if (!parser_.opts.one_file)
90 cur_name_space_ = struct_def.defined_namespace;
91 GenStruct(struct_def, structWriter);
92 if (parser_.opts.one_file) {
93 one_file_code += structWriter.ToString();
95 if (!SaveType(struct_def.name, *struct_def.defined_namespace,
96 structWriter.ToString(), true))
101 if (parser_.opts.one_file) {
102 return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
108 // Save out the generated code for a single class while adding
109 // declaration boilerplate.
110 bool SaveType(const std::string &defname, const Namespace &ns,
111 const std::string &classcode, bool needs_includes) const {
112 if (!classcode.length()) return true;
115 "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
117 std::string namespace_name = FullNamespace(".", ns);
118 if (!namespace_name.empty()) {
119 code += "package " + namespace_name;
122 if (needs_includes) {
123 code += "import java.nio.*\n";
124 code += "import kotlin.math.sign\n";
125 code += "import com.google.flatbuffers.*\n\n";
128 auto filename = NamespaceDir(ns) + defname + ".kt";
129 return SaveFile(filename.c_str(), code, false);
132 const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
133 return cur_name_space_;
136 static bool IsEnum(const Type &type) {
137 return type.enum_def != nullptr && IsInteger(type.base_type);
140 static std::string GenTypeBasic(const BaseType &type) {
142 static const char * const kotlin_typename[] = {
143 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
144 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
146 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
147 #undef FLATBUFFERS_TD
149 return kotlin_typename[type];
153 std::string GenTypePointer(const Type &type) const {
154 switch (type.base_type) {
155 case BASE_TYPE_STRING:
157 case BASE_TYPE_VECTOR:
158 return GenTypeGet(type.VectorType());
159 case BASE_TYPE_STRUCT:
160 return WrapInNameSpace(*type.struct_def);
166 std::string GenTypeGet(const Type &type) const {
167 return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
168 : GenTypePointer(type);
171 std::string GenEnumDefaultValue(const FieldDef &field) const {
172 auto &value = field.value;
173 FLATBUFFERS_ASSERT(value.type.enum_def);
174 auto &enum_def = *value.type.enum_def;
175 auto enum_val = enum_def.FindByValue(value.constant);
176 return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
181 // Generate default values to compare against a default value when
182 // `force_defaults` is `false`.
183 // Main differences are:
184 // - Floats are upcasted to doubles
185 // - Unsigned are casted to signed
186 std::string GenFBBDefaultValue(const FieldDef &field) const {
187 auto out = GenDefaultValue(field, true);
188 // All FlatBufferBuilder default floating point values are doubles
189 if (field.value.type.base_type == BASE_TYPE_FLOAT) {
190 if (out.find("Float") != std::string::npos) {
191 out.replace(0, 5, "Double");
194 //Guarantee all values are doubles
195 if (out.back() == 'f')
201 // FlatBufferBuilder only store signed types, so this function
202 // returns a cast for unsigned values
203 std::string GenFBBValueCast(const FieldDef &field) const {
204 if (IsUnsigned(field.value.type.base_type)) {
205 return CastToSigned(field.value.type);
210 std::string GenDefaultValue(const FieldDef &field,
211 bool force_signed = false) const {
212 auto &value = field.value;
213 auto base_type = field.value.type.base_type;
214 if (IsFloat(base_type)) {
215 auto val = KotlinFloatGen.GenFloatConstant(field);
216 if (base_type == BASE_TYPE_DOUBLE &&
223 if (base_type == BASE_TYPE_BOOL) {
224 return value.constant == "0" ? "false" : "true";
227 std::string suffix = "";
229 if (base_type == BASE_TYPE_LONG || !force_signed) {
230 suffix = LiteralSuffix(base_type);
232 return value.constant + suffix;
235 void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
236 if (enum_def.generated) return;
238 GenerateComment(enum_def.doc_comment, writer, &comment_config);
240 writer += "@Suppress(\"unused\")";
241 writer += "@ExperimentalUnsignedTypes";
242 writer += "class " + Esc(enum_def.name) + " private constructor() {";
243 writer.IncrementIdentLevel();
245 GenerateCompanionObject(writer, [&](){
246 // Write all properties
247 auto vals = enum_def.Vals();
248 for (auto it = vals.begin(); it != vals.end(); ++it) {
250 auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
251 auto val = enum_def.ToString(ev);
252 auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
253 writer.SetValue("name", Esc(ev.name));
254 writer.SetValue("type", field_type);
255 writer.SetValue("val", val + suffix);
256 GenerateComment(ev.doc_comment, writer, &comment_config);
257 writer += "const val {{name}}: {{type}} = {{val}}";
260 // Generate a generate string table for enum values.
261 // Problem is, if values are very sparse that could generate really
262 // big tables. Ideally in that case we generate a map lookup
263 // instead, but for the moment we simply don't output a table at all.
264 auto range = enum_def.Distance();
265 // Average distance between values above which we consider a table
266 // "too sparse". Change at will.
267 static const uint64_t kMaxSparseness = 5;
268 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
269 GeneratePropertyOneLine(writer, "names", "Array<String>",
271 writer += "arrayOf(\\";
272 auto val = enum_def.Vals().front();
273 for (auto it = vals.begin(); it != vals.end(); ++it) {
275 for (auto k = enum_def.Distance(val, ev); k > 1; --k)
276 writer += "\"\", \\";
278 writer += "\"" + (*it)->name + "\"\\";
279 if (it+1 != vals.end()) {
285 GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
286 writer += "names[e\\";
287 if (enum_def.MinValue()->IsNonZero())
288 writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
293 writer.DecrementIdentLevel();
297 // Returns the function name that is able to read a value of the given type.
298 std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const {
299 switch (type.base_type) {
300 case BASE_TYPE_STRING:
302 case BASE_TYPE_STRUCT:
304 case BASE_TYPE_UNION:
306 case BASE_TYPE_VECTOR:
307 return ByteBufferGetter(type.VectorType(), bb_var_name);
310 return bb_var_name + ".getInt";
311 case BASE_TYPE_SHORT:
312 case BASE_TYPE_USHORT:
313 return bb_var_name + ".getShort";
314 case BASE_TYPE_ULONG:
316 return bb_var_name + ".getLong";
317 case BASE_TYPE_FLOAT:
318 return bb_var_name + ".getFloat";
319 case BASE_TYPE_DOUBLE:
320 return bb_var_name + ".getDouble";
322 case BASE_TYPE_UCHAR:
324 case BASE_TYPE_UTYPE:
325 return bb_var_name + ".get";
327 return "0.toByte() != " + bb_var_name + ".get";
329 return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
333 std::string ByteBufferSetter(const Type &type) const {
334 if (IsScalar(type.base_type)) {
335 switch (type.base_type) {
339 case BASE_TYPE_SHORT:
340 case BASE_TYPE_USHORT:
341 return "bb.putShort";
342 case BASE_TYPE_ULONG:
345 case BASE_TYPE_FLOAT:
346 return "bb.putFloat";
347 case BASE_TYPE_DOUBLE:
348 return "bb.putDouble";
350 case BASE_TYPE_UCHAR:
353 case BASE_TYPE_UTYPE:
356 return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
362 // Returns the function name that is able to read a value of the given type.
363 std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
364 const std::string &bb_var_name,
365 const char *num = nullptr) const {
366 auto type = key_field->value.type;
367 return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")";
371 // Returns the method name for use with add/put calls.
372 static std::string GenMethod(const Type &type) {
373 return IsScalar(type.base_type) ? ToSignedType(type)
374 : (IsStruct(type) ? "Struct" : "Offset");
377 // Recursively generate arguments for a constructor, to deal with nested
379 static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
380 const char *nameprefix) {
381 for (auto it = struct_def.fields.vec.begin();
382 it != struct_def.fields.vec.end(); ++it) {
384 if (IsStruct(field.value.type)) {
385 // Generate arguments for a struct inside a struct. To ensure
386 // names don't clash, and to make it obvious these arguments are
387 // constructing a nested struct, prefix the name with the field
389 GenStructArgs(*field.value.type.struct_def, writer,
390 (nameprefix + (field.name + "_")).c_str());
392 writer += std::string(", ") + nameprefix + "\\";
393 writer += MakeCamel(field.name) + ": \\";
394 writer += GenTypeBasic(field.value.type.base_type) + "\\";
399 // Recusively generate struct construction statements of the form:
400 // builder.putType(name);
401 // and insert manual padding.
402 static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
403 const char *nameprefix) {
404 writer.SetValue("align", NumToString(struct_def.minalign));
405 writer.SetValue("size", NumToString(struct_def.bytesize));
406 writer += "builder.prep({{align}}, {{size}})";
407 auto fields_vec = struct_def.fields.vec;
408 for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
412 writer.SetValue("pad", NumToString(field.padding));
413 writer += "builder.pad({{pad}})";
415 if (IsStruct(field.value.type)) {
416 GenStructBody(*field.value.type.struct_def, writer,
417 (nameprefix + (field.name + "_")).c_str());
419 writer.SetValue("type", GenMethod(field.value.type));
420 writer.SetValue("argname", nameprefix +
421 MakeCamel(field.name, false));
422 writer.SetValue("cast", CastToSigned(field.value.type));
423 writer += "builder.put{{type}}({{argname}}{{cast}})";
428 std::string GenByteBufferLength(const char *bb_name) const {
429 std::string bb_len = bb_name;
430 bb_len += ".capacity()";
434 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
435 const char *num = nullptr) const {
436 std::string key_offset = "__offset(" +
437 NumToString(key_field->value.offset) + ", ";
440 key_offset += ", _bb)";
442 key_offset += GenByteBufferLength("bb");
443 key_offset += " - tableOffset, bb)";
448 void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
449 if (struct_def.generated) return;
451 GenerateComment(struct_def.doc_comment, writer, &comment_config);
452 auto fixed = struct_def.fixed;
454 writer.SetValue("struct_name", Esc(struct_def.name));
455 writer.SetValue("superclass", fixed ? "Struct" : "Table");
457 writer += "@Suppress(\"unused\")";
458 writer += "@ExperimentalUnsignedTypes";
459 writer += "class {{struct_name}} : {{superclass}}() {\n";
461 writer.IncrementIdentLevel();
464 // Generate the __init() method that sets the field in a pre-existing
465 // accessor object. This is to allow object reuse.
466 GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() {
467 writer += "__reset(_i, _bb)";
470 // Generate assign method
471 GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
472 Esc(struct_def.name), [&]() {
473 writer += "__init(_i, _bb)";
474 writer += "return this";
477 // Generate all getters
478 GenerateStructGetters(struct_def, writer);
480 // Generate Static Fields
481 GenerateCompanionObject(writer, [&](){
483 if (!struct_def.fixed) {
484 FieldDef *key_field = nullptr;
486 // Generate verson check method.
487 // Force compile time error if not using the same version
489 GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
490 writer += "Constants.FLATBUFFERS_1_11_1()";
493 GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
494 GenerateBufferHasIdentifier(struct_def, writer);
495 GenerateTableCreator(struct_def, writer);
497 GenerateStartStructMethod(struct_def, writer);
499 // Static Add for fields
500 auto fields = struct_def.fields.vec;
502 for (auto it = fields.begin(); it != fields.end(); ++it) {
505 if (field.deprecated) continue;
506 if (field.key) key_field = &field;
507 GenerateAddField(NumToString(field_pos), field, writer);
509 if (field.value.type.base_type == BASE_TYPE_VECTOR) {
510 auto vector_type = field.value.type.VectorType();
511 if (!IsStruct(vector_type)) {
512 GenerateCreateVectorField(field, writer);
514 GenerateStartVectorField(field, writer);
518 GenerateEndStructMethod(struct_def, writer);
519 auto file_identifier = parser_.file_identifier_;
520 if (parser_.root_struct_def_ == &struct_def) {
521 GenerateFinishStructBuffer(struct_def,
524 GenerateFinishSizePrefixed(struct_def,
529 if (struct_def.has_key) {
530 GenerateLookupByKey(key_field, struct_def, writer);
533 GenerateStaticConstructor(struct_def, writer);
539 writer.DecrementIdentLevel();
543 // TODO: move key_field to reference instead of pointer
544 void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
545 CodeWriter &writer) const {
546 std::stringstream params;
547 params << "obj: " << Esc(struct_def.name) << "?" << ", ";
548 params << "vectorLocation: Int, ";
549 params << "key: " << GenTypeGet(key_field->value.type) << ", ";
550 params << "bb: ByteBuffer";
552 auto statements = [&]() {
553 auto base_type = key_field->value.type.base_type;
554 writer.SetValue("struct_name", Esc(struct_def.name));
555 if (base_type == BASE_TYPE_STRING) {
556 writer += "val byteKey = key."
557 "toByteArray(Table.UTF8_CHARSET.get()!!)";
559 writer += "var span = bb.getInt(vectorLocation - 4)";
560 writer += "var start = 0";
561 writer += "while (span != 0) {";
562 writer.IncrementIdentLevel();
563 writer += "var middle = span / 2";
564 writer += "val tableOffset = __indirect(vector"
565 "Location + 4 * (start + middle), bb)";
566 if (key_field->value.type.base_type == BASE_TYPE_STRING) {
567 writer += "val comp = compareStrings(\\";
568 writer += GenOffsetGetter(key_field) + "\\";
569 writer += ", byteKey, bb)";
571 auto cast = CastToUsigned(key_field->value.type);
572 auto get_val = GenLookupByKey(key_field, "bb");
573 writer += "val value = " + get_val + cast;
574 writer += "val comp = value.compareTo(key)";
577 writer.IncrementIdentLevel();
578 writer += "comp > 0 -> span = middle";
579 writer += "comp < 0 -> {";
580 writer.IncrementIdentLevel();
581 writer += "middle++";
582 writer += "start += middle";
583 writer += "span -= middle";
584 writer.DecrementIdentLevel();
585 writer += "}"; // end comp < 0
586 writer += "else -> {";
587 writer.IncrementIdentLevel();
588 writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
589 writer.DecrementIdentLevel();
590 writer += "}"; // end else
591 writer.DecrementIdentLevel();
592 writer += "}"; // end when
593 writer.DecrementIdentLevel();
594 writer += "}"; // end while
595 writer += "return null";
597 GenerateFun(writer, "__lookup_by_key",
599 Esc(struct_def.name) + "?",
603 void GenerateFinishSizePrefixed(StructDef &struct_def,
604 const std::string &identifier,
605 CodeWriter &writer) const {
606 auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
607 auto params = "builder: FlatBufferBuilder, offset: Int";
608 auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
609 GenerateFunOneLine(writer, method_name, params, "", [&]() {
610 writer += "builder.finishSizePrefixed(offset" + id + ")";
613 void GenerateFinishStructBuffer(StructDef &struct_def,
614 const std::string &identifier,
615 CodeWriter &writer) const {
616 auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
617 auto params = "builder: FlatBufferBuilder, offset: Int";
618 auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
619 GenerateFunOneLine(writer, method_name, params, "", [&]() {
620 writer += "builder.finish(offset" + id + ")";
624 void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const {
625 // Generate end{{TableName}}(builder: FlatBufferBuilder) method
626 auto name = "end" + Esc(struct_def.name);
627 auto params = "builder: FlatBufferBuilder";
628 auto returns = "Int";
629 auto field_vec = struct_def.fields.vec;
631 GenerateFun(writer, name, params, returns, [&](){
632 writer += "val o = builder.endTable()";
633 writer.IncrementIdentLevel();
634 for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
636 if (field.deprecated || !field.required) {
639 writer.SetValue("offset", NumToString(field.value.offset));
640 writer += "builder.required(o, {{offset}})";
642 writer.DecrementIdentLevel();
643 writer += "return o";
647 // Generate a method to create a vector from a Kotlin array.
648 void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const {
649 auto vector_type = field.value.type.VectorType();
650 auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
651 auto params = "builder: FlatBufferBuilder, data: " +
652 GenTypeBasic(vector_type.base_type) + "Array";
653 writer.SetValue("size", NumToString(InlineSize(vector_type)));
654 writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
655 writer.SetValue("root", GenMethod(vector_type));
656 writer.SetValue("cast", CastToSigned(vector_type));
658 GenerateFun(writer, method_name, params, "Int", [&](){
659 writer += "builder.startVector({{size}}, data.size, {{align}})";
660 writer += "for (i in data.size - 1 downTo 0) {";
661 writer.IncrementIdentLevel();
662 writer += "builder.add{{root}}(data[i]{{cast}})";
663 writer.DecrementIdentLevel();
665 writer += "return builder.endVector()";
669 void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
670 // Generate a method to start a vector, data to be added manually
672 auto vector_type = field.value.type.VectorType();
673 auto params = "builder: FlatBufferBuilder, numElems: Int";
674 writer.SetValue("size", NumToString(InlineSize(vector_type)));
675 writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
677 GenerateFunOneLine(writer,
678 "start" + MakeCamel(Esc(field.name) + "Vector", true),
682 writer += "builder.startVector({{size}}, numElems, {{align}})";
686 void GenerateAddField(std::string field_pos, FieldDef &field,
687 CodeWriter &writer) const {
688 auto field_type = GenTypeBasic(field.value.type.base_type);
689 auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
690 GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true),
691 "builder: FlatBufferBuilder, " + secondArg, "", [&](){
692 auto method = GenMethod(field.value.type);
693 writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
694 writer.SetValue("method_name", method);
695 writer.SetValue("pos", field_pos);
696 writer.SetValue("default", GenFBBDefaultValue(field));
697 writer.SetValue("cast", GenFBBValueCast(field));
699 writer += "builder.add{{method_name}}({{pos}}, \\";
700 writer += "{{field_name}}{{cast}}, {{default}})";
704 static std::string ToSignedType(const Type & type) {
705 switch(type.base_type) {
707 return GenTypeBasic(BASE_TYPE_INT);
708 case BASE_TYPE_ULONG:
709 return GenTypeBasic(BASE_TYPE_LONG);
710 case BASE_TYPE_UCHAR:
712 case BASE_TYPE_UTYPE:
713 return GenTypeBasic(BASE_TYPE_CHAR);
714 case BASE_TYPE_USHORT:
715 return GenTypeBasic(BASE_TYPE_SHORT);
716 case BASE_TYPE_VECTOR:
717 return ToSignedType(type.VectorType());
719 return GenTypeBasic(type.base_type);
723 static std::string FlexBufferBuilderCast(const std::string &method,
726 auto field_type = GenTypeBasic(field.value.type.base_type);
728 if (method == "Boolean")
730 else if (method == "Long")
732 else if (method == "Int" || method == "Offset" || method == "Struct")
734 else if (method == "Byte" || method.empty())
735 to_type = isFirst ? "Byte" : "Int";
736 else if (method == "Short")
737 to_type = isFirst ? "Short" : "Int";
738 else if (method == "Double")
740 else if (method == "Float")
741 to_type = isFirst ? "Float" : "Double";
742 else if (method == "UByte")
744 if (field_type != to_type)
745 return ".to" + to_type + "()";
749 // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
750 void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const {
751 GenerateFunOneLine(code, "start" + Esc(struct_def.name),
752 "builder: FlatBufferBuilder", "", [&] () {
753 code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")";
757 void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const {
758 // Generate a method that creates a table in one go. This is only possible
759 // when the table has no struct fields, since those have to be created
760 // inline, and there's no way to do so in Java.
761 bool has_no_struct_fields = true;
763 auto fields_vec = struct_def.fields.vec;
765 for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
767 if (field.deprecated) continue;
768 if (IsStruct(field.value.type)) {
769 has_no_struct_fields = false;
774 // JVM specifications restrict default constructor params to be < 255.
775 // Longs and doubles take up 2 units, so we set the limit to be < 127.
776 if (has_no_struct_fields && num_fields && num_fields < 127) {
777 // Generate a table constructor of the form:
778 // public static int createName(FlatBufferBuilder builder, args...)
780 auto name = "create" + Esc(struct_def.name);
781 std::stringstream params;
782 params << "builder: FlatBufferBuilder";
783 for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
785 if (field.deprecated) continue;
786 params << ", " << MakeCamel(Esc(field.name), false);
787 if (!IsScalar(field.value.type.base_type)){
788 params << "Offset: ";
792 params << GenTypeBasic(field.value.type.base_type);
795 GenerateFun(writer, name, params.str(), "Int", [&]() {
796 writer.SetValue("vec_size", NumToString(fields_vec.size()));
798 writer += "builder.startTable({{vec_size}})";
800 auto sortbysize = struct_def.sortbysize;
801 auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
802 for (size_t size = largest; size; size /= 2) {
803 for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
806 auto base_type_size = SizeOf(field.value.type.base_type);
807 if (!field.deprecated &&
808 (!sortbysize || size == base_type_size)) {
809 writer.SetValue("camel_field_name",
810 MakeCamel(Esc(field.name), true));
811 writer.SetValue("field_name",
812 MakeCamel(Esc(field.name), false));
814 writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
815 if (!IsScalar(field.value.type.base_type)){
816 writer += "Offset\\";
822 writer += "return end{{struct_name}}(builder)";
827 void GenerateBufferHasIdentifier(StructDef &struct_def,
828 CodeWriter &writer) const {
829 auto file_identifier = parser_.file_identifier_;
830 // Check if a buffer has the identifier.
831 if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
833 auto name = MakeCamel(Esc(struct_def.name), false);
834 GenerateFunOneLine(writer, name + "BufferHasIdentifier",
838 writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
842 void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
843 auto fields_vec = struct_def.fields.vec;
844 FieldDef *key_field = nullptr;
845 for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
847 if (field.deprecated) continue;
848 if (field.key) key_field = &field;
850 GenerateComment(field.doc_comment, writer, &comment_config);
852 auto field_name = MakeCamel(Esc(field.name), false);
853 auto field_type = GenTypeGet(field.value.type);
854 auto field_default_value = GenDefaultValue(field);
855 auto return_type = GenTypeGet(field.value.type);
856 auto bbgetter = ByteBufferGetter(field.value.type, "bb");
857 auto ucast = CastToUsigned(field);
858 auto offset_val = NumToString(field.value.offset);
859 auto offset_prefix = "val o = __offset(" + offset_val
860 + "); return o != 0 ? ";
861 auto value_base_type = field.value.type.base_type;
862 // Most field accessors need to retrieve and test the field offset
863 // first, this is the offset value for that:
864 writer.SetValue("offset", NumToString(field.value.offset));
865 writer.SetValue("return_type", return_type);
866 writer.SetValue("field_type", field_type);
867 writer.SetValue("field_name", field_name);
868 writer.SetValue("field_default", field_default_value);
869 writer.SetValue("bbgetter", bbgetter);
870 writer.SetValue("ucast", ucast);
872 auto opt_ret_type = return_type + "?";
873 // Generate the accessors that don't do object reuse.
874 if (value_base_type == BASE_TYPE_STRUCT) {
875 // Calls the accessor that takes an accessor object with a
878 // get() = pos(Vec3())
879 GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
880 writer += "{{field_name}}({{field_type}}())";
882 } else if (value_base_type == BASE_TYPE_VECTOR &&
883 field.value.type.element == BASE_TYPE_STRUCT) {
884 // Accessors for vectors of structs also take accessor objects,
885 // this generates a variant without that argument.
886 // ex: fun weapons(j: Int) = weapons(Weapon(), j)
887 GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){
888 writer += "{{field_name}}({{return_type}}(), j)";
892 if (IsScalar(value_base_type)) {
893 if (struct_def.fixed) {
894 GenerateGetterOneLine(writer, field_name, return_type, [&](){
895 writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
898 GenerateGetter(writer, field_name, return_type, [&](){
899 writer += "val o = __offset({{offset}})";
900 writer += "return if(o != 0) {{bbgetter}}"
901 "(o + bb_pos){{ucast}} else "
906 switch (value_base_type) {
907 case BASE_TYPE_STRUCT:
908 if (struct_def.fixed) {
909 // create getter with object reuse
911 // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
912 // ? adds nullability annotation
913 GenerateFunOneLine(writer,
914 field_name, "obj: " + field_type ,
915 return_type + "?", [&](){
916 writer += "obj.__assign(bb_pos + {{offset}}, bb)";
919 // create getter with object reuse
921 // fun pos(obj: Vec3) : Vec3? {
922 // val o = __offset(4)
923 // return if(o != 0) {
924 // obj.__assign(o + bb_pos, bb)
929 // ? adds nullability annotation
930 GenerateFun(writer, field_name, "obj: " + field_type,
931 return_type + "?", [&](){
932 auto fixed = field.value.type.struct_def->fixed;
934 writer.SetValue("seek", Indirect("o + bb_pos", fixed));
935 OffsetWrapper(writer,
937 [&]() { writer += "obj.__assign({{seek}}, bb)"; },
938 [&]() { writer += "null"; });
942 case BASE_TYPE_STRING:
943 // create string getter
945 // val Name : String?
947 // val o = __offset(10)
948 // return if (o != 0) __string(o + bb_pos) else null
950 // ? adds nullability annotation
951 GenerateGetter(writer, field_name, return_type + "?", [&](){
953 writer += "val o = __offset({{offset}})";
954 writer += "return if (o != 0) __string(o + bb_pos) else null";
957 case BASE_TYPE_VECTOR: {
959 // fun inventory(j: Int) : UByte {
960 // val o = __offset(14)
961 // return if (o != 0) {
962 // bb.get(__vector(o) + j * 1).toUByte()
968 auto vectortype = field.value.type.VectorType();
969 std::string params = "j: Int";
970 std::string nullable = IsScalar(vectortype.base_type) ? ""
973 if (vectortype.base_type == BASE_TYPE_STRUCT ||
974 vectortype.base_type == BASE_TYPE_UNION) {
975 params = "obj: " + field_type + ", j: Int";
979 writer.SetValue("toType", "YYYYY");
981 auto ret_type = return_type + nullable;
982 GenerateFun(writer, field_name, params, ret_type, [&](){
983 auto inline_size = NumToString(InlineSize(vectortype));
984 auto index = "__vector(o) + j * " + inline_size;
985 auto not_found = NotFoundReturn(field.value.type.element);
987 writer.SetValue("index", index);
988 switch(vectortype.base_type) {
989 case BASE_TYPE_STRUCT: {
990 bool fixed = vectortype.struct_def->fixed;
991 writer.SetValue("index", Indirect(index, fixed));
992 found = "obj.__assign({{index}}, bb)";
995 case BASE_TYPE_UNION:
996 found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
999 found = "{{bbgetter}}({{index}}){{ucast}}";
1001 OffsetWrapper(writer, offset_val,
1002 [&]() { writer += found; } ,
1003 [&]() { writer += not_found; });
1007 case BASE_TYPE_UNION:
1008 GenerateFun(writer, field_name, "obj: " + field_type,
1009 return_type + "?", [&](){
1010 writer += OffsetWrapperOneLine(offset_val,
1011 bbgetter + "(obj, o)",
1016 FLATBUFFERS_ASSERT(0);
1020 if (value_base_type == BASE_TYPE_VECTOR) {
1021 // Generate Lenght functions for vectors
1022 GenerateGetter(writer, field_name + "Length", "Int", [&](){
1023 writer += OffsetWrapperOneLine(offset_val,
1024 "__vector_len(o)", "0");
1027 // See if we should generate a by-key accessor.
1028 if (field.value.type.element == BASE_TYPE_STRUCT &&
1029 !field.value.type.struct_def->fixed) {
1030 auto &sd = *field.value.type.struct_def;
1031 auto &fields = sd.fields.vec;
1032 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1033 auto &kfield = **kit;
1035 auto qualified_name = WrapInNameSpace(sd);
1036 auto name = MakeCamel(Esc(field.name), false) + "ByKey";
1037 auto params = "key: " + GenTypeGet(kfield.value.type);
1038 auto rtype = qualified_name + "?";
1039 GenerateFun(writer, name, params, rtype, [&] () {
1040 OffsetWrapper(writer, offset_val,
1042 writer += qualified_name +
1043 ".__lookup_by_key(null, __vector(o), key, bb)";
1050 auto param2 = "obj: " + qualified_name +
1052 GenTypeGet(kfield.value.type);
1053 GenerateFun(writer, name, param2, rtype, [&](){
1054 OffsetWrapper(writer, offset_val,
1056 writer += qualified_name +
1057 ".__lookup_by_key(obj, __vector(o), key, bb)";
1059 [&]() { writer += "null"; });
1068 if ((value_base_type == BASE_TYPE_VECTOR &&
1069 IsScalar(field.value.type.VectorType().base_type)) ||
1070 value_base_type == BASE_TYPE_STRING) {
1072 auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
1074 : InlineSize(field.value.type.VectorType()));
1075 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1077 // val inventoryByteBuffer: ByteBuffer
1078 // get = __vector_as_bytebuffer(14, 1)
1080 GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
1081 "ByteBuffer", [&](){
1082 writer.SetValue("end", end_idx);
1083 writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
1086 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1088 // fun inventoryInByteBuffer(_bb: Bytebuffer):
1089 // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
1090 GenerateFunOneLine(writer, field_name + "InByteBuffer",
1091 "_bb: ByteBuffer", "ByteBuffer", [&](){
1092 writer.SetValue("end", end_idx);
1093 writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
1097 // generate object accessors if is nested_flatbuffer
1098 //fun testnestedflatbufferAsMonster() : Monster?
1099 //{ return testnestedflatbufferAsMonster(new Monster()); }
1101 if (field.nested_flatbuffer) {
1102 auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
1103 auto nested_method_name =
1105 field.nested_flatbuffer->name;
1107 GenerateGetterOneLine(writer,
1109 nested_type_name + "?", [&](){
1110 writer += nested_method_name + "(" + nested_type_name + "())";
1115 "obj: " + nested_type_name,
1116 nested_type_name + "?", [&](){
1117 OffsetWrapper(writer, offset_val,
1118 [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
1119 [&]() { writer += "null";});
1123 // Generate mutators for scalar fields or vectors of scalars.
1124 if (parser_.opts.mutable_buffer) {
1125 auto value_type = field.value.type;
1126 auto underlying_type = value_base_type == BASE_TYPE_VECTOR
1127 ? value_type.VectorType()
1129 auto name = "mutate" + MakeCamel(Esc(field.name), true);
1130 auto size = NumToString(InlineSize(underlying_type));
1131 auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
1132 // A vector mutator also needs the index of the vector element it should
1134 if (value_base_type == BASE_TYPE_VECTOR)
1135 params.insert(0, "j: Int, ");
1137 // Boolean parameters have to be explicitly converted to byte
1139 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
1140 ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
1143 auto setter_index = value_base_type == BASE_TYPE_VECTOR
1144 ? "__vector(o) + j * " + size
1146 ? "bb_pos + " + offset_val
1148 if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
1149 IsScalar(value_type.VectorType().base_type))) {
1151 auto statements = [&] () {
1152 writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
1153 writer.SetValue("index", setter_index);
1154 writer.SetValue("params", setter_parameter);
1155 writer.SetValue("cast", CastToSigned(field));
1156 if (struct_def.fixed) {
1157 writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1159 OffsetWrapper(writer, offset_val, [&](){
1160 writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1162 }, [&](){ writer += "false";});
1166 if (struct_def.fixed) {
1167 GenerateFunOneLine(writer, name, params, "ByteBuffer",
1170 GenerateFun(writer, name, params, "Boolean",
1176 if (struct_def.has_key && !struct_def.fixed) {
1177 // Key Comparison method
1178 GenerateOverrideFun(
1181 "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
1182 if (key_field->value.type.base_type == BASE_TYPE_STRING) {
1183 writer.SetValue("offset", NumToString(key_field->value.offset));
1184 writer += " return compareStrings(__offset({{offset}}, o1, "
1185 "_bb), __offset({{offset}}, o2, _bb), _bb)";
1188 auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
1189 auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
1190 writer += "val val_1 = " + getter1;
1191 writer += "val val_2 = " + getter2;
1192 writer += "return (val_1 - val_2).sign";
1198 static std::string CastToUsigned(const FieldDef &field) {
1199 return CastToUsigned(field.value.type);
1202 static std::string CastToUsigned(const Type type) {
1203 switch (type.base_type) {
1204 case BASE_TYPE_UINT:
1206 case BASE_TYPE_UCHAR:
1207 case BASE_TYPE_UTYPE:
1208 return ".toUByte()";
1209 case BASE_TYPE_USHORT:
1210 return ".toUShort()";
1211 case BASE_TYPE_ULONG:
1212 return ".toULong()";
1213 case BASE_TYPE_VECTOR:
1214 return CastToUsigned(type.VectorType());
1220 static std::string CastToSigned(const FieldDef &field) {
1221 return CastToSigned(field.value.type);
1224 static std::string CastToSigned(const Type type) {
1225 switch (type.base_type) {
1226 case BASE_TYPE_UINT:
1228 case BASE_TYPE_UCHAR:
1229 case BASE_TYPE_UTYPE:
1231 case BASE_TYPE_USHORT:
1232 return ".toShort()";
1233 case BASE_TYPE_ULONG:
1235 case BASE_TYPE_VECTOR:
1236 return CastToSigned(type.VectorType());
1242 static std::string LiteralSuffix(const BaseType type) {
1244 case BASE_TYPE_UINT:
1245 case BASE_TYPE_UCHAR:
1246 case BASE_TYPE_UTYPE:
1247 case BASE_TYPE_USHORT:
1249 case BASE_TYPE_ULONG:
1251 case BASE_TYPE_LONG:
1258 void GenerateCompanionObject(CodeWriter &code,
1259 const std::function<void()> &callback) const {
1260 code += "companion object {";
1261 code.IncrementIdentLevel();
1263 code.DecrementIdentLevel();
1267 // Generate a documentation comment, if available.
1268 void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
1269 const CommentConfig *config) const {
1270 if (dc.begin() == dc.end()) {
1271 // Don't output empty comment blocks with 0 lines of comment content.
1275 if (config != nullptr && config->first_line != nullptr) {
1276 writer += std::string(config->first_line);
1278 std::string line_prefix =
1279 ((config != nullptr && config->content_line_prefix != nullptr)
1280 ? config->content_line_prefix
1282 for (auto it = dc.begin(); it != dc.end(); ++it) {
1283 writer += line_prefix + *it;
1285 if (config != nullptr && config->last_line != nullptr) {
1286 writer += std::string(config->last_line);
1290 static void GenerateGetRootAsAccessors(const std::string &struct_name,
1291 CodeWriter &writer) {
1292 // Generate a special accessor for the table that when used as the root
1293 // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
1294 writer.SetValue("gr_name", struct_name);
1295 writer.SetValue("gr_method", "getRootAs" + struct_name);
1297 // create convenience method that doesn't require an existing object
1298 writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
1299 writer += "{{gr_method}}(_bb, {{gr_name}}())";
1301 // create method that allows object reuse
1302 // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
1303 writer += "fun {{gr_method}}"
1304 "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
1305 writer.IncrementIdentLevel();
1306 writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
1307 writer += "return (obj.__assign(_bb.getInt(_bb.position())"
1308 " + _bb.position(), _bb))";
1309 writer.DecrementIdentLevel();
1313 static void GenerateStaticConstructor(const StructDef &struct_def,
1315 // create a struct constructor function
1316 auto params = StructConstructorParams(struct_def);
1317 GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
1318 GenStructBody(struct_def, code, "");
1319 code += "return builder.offset()";
1323 static std::string StructConstructorParams(const StructDef &struct_def,
1324 const std::string &prefix = "") {
1325 //builder: FlatBufferBuilder
1326 std::stringstream out;
1327 auto field_vec = struct_def.fields.vec;
1328 if (prefix.empty()) {
1329 out << "builder: FlatBufferBuilder";
1331 for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
1333 if (IsStruct(field.value.type)) {
1334 // Generate arguments for a struct inside a struct. To ensure
1335 // names don't clash, and to make it obvious these arguments are
1336 // constructing a nested struct, prefix the name with the field
1338 out << StructConstructorParams(*field.value.type.struct_def,
1339 prefix + (Esc(field.name) + "_"));
1341 out << ", " << prefix << MakeCamel(Esc(field.name), false)
1343 << GenTypeBasic(field.value.type.base_type);
1349 static void GeneratePropertyOneLine(CodeWriter &writer,
1350 const std::string &name,
1351 const std::string &type,
1352 const std::function<void()> &body) {
1353 // Generates Kotlin getter for properties
1355 // val prop: Mytype = x
1356 writer.SetValue("_name", name);
1357 writer.SetValue("_type", type);
1358 writer += "val {{_name}} : {{_type}} = \\";
1361 static void GenerateGetterOneLine(CodeWriter &writer,
1362 const std::string &name,
1363 const std::string &type,
1364 const std::function<void()> &body) {
1365 // Generates Kotlin getter for properties
1367 // val prop: Mytype get() = x
1368 writer.SetValue("_name", name);
1369 writer.SetValue("_type", type);
1370 writer += "val {{_name}} : {{_type}} get() = \\";
1374 static void GenerateGetter(CodeWriter &writer,
1375 const std::string &name,
1376 const std::string &type,
1377 const std::function<void()> &body) {
1378 // Generates Kotlin getter for properties
1384 writer.SetValue("name", name);
1385 writer.SetValue("type", type);
1386 writer += "val {{name}} : {{type}}";
1387 writer.IncrementIdentLevel();
1388 writer += "get() {";
1389 writer.IncrementIdentLevel();
1391 writer.DecrementIdentLevel();
1393 writer.DecrementIdentLevel();
1396 static void GenerateFun(CodeWriter &writer,
1397 const std::string &name,
1398 const std::string ¶ms,
1399 const std::string &returnType,
1400 const std::function<void()> &body) {
1401 // Generates Kotlin function
1403 // fun path(j: Int): Vec3 {
1404 // return path(Vec3(), j)
1406 auto noreturn = returnType.empty();
1407 writer.SetValue("name", name);
1408 writer.SetValue("params", params);
1409 writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
1410 writer += "fun {{name}}({{params}}) {{return_type}} {";
1411 writer.IncrementIdentLevel();
1413 writer.DecrementIdentLevel();
1417 static void GenerateFunOneLine(CodeWriter &writer,
1418 const std::string &name,
1419 const std::string ¶ms,
1420 const std::string &returnType,
1421 const std::function<void()> &body) {
1422 // Generates Kotlin function
1424 // fun path(j: Int): Vec3 = return path(Vec3(), j)
1425 writer.SetValue("name", name);
1426 writer.SetValue("params", params);
1427 writer.SetValue("return_type_p", returnType.empty() ? "" :
1428 " : " + returnType);
1429 writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
1433 static void GenerateOverrideFun(CodeWriter &writer,
1434 const std::string &name,
1435 const std::string ¶ms,
1436 const std::string &returnType,
1437 const std::function<void()> &body) {
1438 // Generates Kotlin function
1440 // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1441 writer += "override \\";
1442 GenerateFun(writer, name, params, returnType, body);
1445 static void GenerateOverrideFunOneLine(CodeWriter &writer,
1446 const std::string &name,
1447 const std::string ¶ms,
1448 const std::string &returnType,
1449 const std::string &statement) {
1450 // Generates Kotlin function
1452 // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1453 writer.SetValue("name", name);
1454 writer.SetValue("params", params);
1455 writer.SetValue("return_type", returnType.empty() ? "" :
1456 " : " + returnType);
1457 writer += "override fun {{name}}({{params}}){{return_type}} = \\";
1458 writer += statement;
1461 static std::string OffsetWrapperOneLine(const std::string &offset,
1462 const std::string &found,
1463 const std::string ¬_found) {
1464 return "val o = __offset(" + offset + "); return if (o != 0) " + found +
1465 " else " + not_found;
1468 static void OffsetWrapper(CodeWriter &code,
1469 const std::string &offset,
1470 const std::function<void()> &found,
1471 const std::function<void()> ¬_found) {
1472 code += "val o = __offset(" + offset + ")";
1473 code +="return if (o != 0) {";
1474 code.IncrementIdentLevel();
1476 code.DecrementIdentLevel();
1478 code.IncrementIdentLevel();
1480 code.DecrementIdentLevel();
1484 static std::string Indirect(const std::string &index, bool fixed) {
1485 // We apply __indirect() and struct is not fixed.
1487 return "__indirect(" + index + ")";
1491 static std::string NotFoundReturn(BaseType el) {
1493 case BASE_TYPE_FLOAT:
1495 case BASE_TYPE_DOUBLE:
1497 case BASE_TYPE_BOOL:
1499 case BASE_TYPE_LONG:
1501 case BASE_TYPE_CHAR:
1502 case BASE_TYPE_SHORT:
1504 case BASE_TYPE_UINT:
1505 case BASE_TYPE_UCHAR:
1506 case BASE_TYPE_USHORT:
1507 case BASE_TYPE_UTYPE:
1509 case BASE_TYPE_ULONG:
1516 // This tracks the current namespace used to determine if a type need to be
1517 // prefixed by its namespace
1518 const Namespace *cur_name_space_;
1520 } // namespace kotlin
1522 bool GenerateKotlin(const Parser &parser, const std::string &path,
1523 const std::string &file_name) {
1524 kotlin::KotlinGenerator generator(parser, path, file_name);
1525 return generator.generate();
1527 } // namespace flatbuffers