[Kotlin] Fix union vector accessor after change in Java API (#5605)
[platform/upstream/flatbuffers.git] / src / idl_gen_kotlin.cpp
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
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
19 #include <functional>
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)
26 #include <cctype>
27 #endif  // defined(FLATBUFFERS_CPP98_STL)
28
29 namespace flatbuffers {
30
31 namespace kotlin {
32
33 typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
34 static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
35                                                   "POSITIVE_INFINITY",
36                                                   "NEGATIVE_INFINITY");
37
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"};
46
47 // Escape Keywords
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);
52     }
53   }
54
55   return MakeCamel(name, false);
56 }
57
58 class KotlinGenerator : public BaseGenerator {
59  public:
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) {}
64
65   KotlinGenerator &operator=(const KotlinGenerator &);
66   bool generate() FLATBUFFERS_OVERRIDE {
67     std::string one_file_code;
68
69     cur_name_space_ = parser_.current_namespace_;
70     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
71          ++it) {
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();
78       } else {
79         if (!SaveType(enum_def.name, *enum_def.defined_namespace,
80                       enumWriter.ToString(), false))
81           return false;
82       }
83     }
84
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();
94       } else {
95         if (!SaveType(struct_def.name, *struct_def.defined_namespace,
96                       structWriter.ToString(), true))
97           return false;
98       }
99     }
100
101     if (parser_.opts.one_file) {
102       return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
103                       true);
104     }
105     return true;
106   }
107
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;
113
114     std::string code =
115         "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
116
117     std::string namespace_name = FullNamespace(".", ns);
118     if (!namespace_name.empty()) {
119       code += "package " + namespace_name;
120       code += "\n\n";
121     }
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";
126     }
127     code += classcode;
128     auto filename = NamespaceDir(ns) + defname + ".kt";
129     return SaveFile(filename.c_str(), code, false);
130   }
131
132   const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
133     return cur_name_space_;
134   }
135
136   static bool IsEnum(const Type &type) {
137     return type.enum_def != nullptr && IsInteger(type.base_type);
138   }
139
140   static std::string GenTypeBasic(const BaseType &type) {
141     // clang-format off
142         static const char * const kotlin_typename[] = {
143     #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
144         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
145     #KTYPE,
146         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
147     #undef FLATBUFFERS_TD
148         };
149         return kotlin_typename[type];
150
151     }
152
153     std::string GenTypePointer(const Type &type) const {
154         switch (type.base_type) {
155         case BASE_TYPE_STRING:
156             return "String";
157         case BASE_TYPE_VECTOR:
158             return GenTypeGet(type.VectorType());
159         case BASE_TYPE_STRUCT:
160             return WrapInNameSpace(*type.struct_def);
161         default:
162             return "Table";
163         }
164     }
165
166     std::string GenTypeGet(const Type &type) const {
167         return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
168                                         : GenTypePointer(type);
169     }
170
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)
177                         : value.constant;
178     }
179
180
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");
192             }
193         }
194         //Guarantee all values are doubles
195         if (out.back() == 'f')
196             out.pop_back();
197         return out;
198     }
199
200
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);
206         }
207         return "";
208     }
209
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 &&
217                     val.back() == 'f') {
218                 val.pop_back();
219             }
220             return val;
221         }
222
223         if (base_type  == BASE_TYPE_BOOL) {
224             return value.constant == "0" ? "false" : "true";
225         }
226
227         std::string suffix = "";
228
229         if (base_type == BASE_TYPE_LONG || !force_signed) {
230             suffix = LiteralSuffix(base_type);
231         }
232         return value.constant + suffix;
233     }
234
235     void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
236         if (enum_def.generated) return;
237
238         GenerateComment(enum_def.doc_comment, writer, &comment_config);
239
240         writer += "@Suppress(\"unused\")";
241         writer += "@ExperimentalUnsignedTypes";
242         writer += "class " + Esc(enum_def.name) + " private constructor() {";
243         writer.IncrementIdentLevel();
244
245         GenerateCompanionObject(writer, [&](){
246             // Write all properties
247             auto vals = enum_def.Vals();
248             for (auto it = vals.begin(); it != vals.end(); ++it) {
249                 auto &ev = **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}}";
258             }
259
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>",
270                                [&](){
271                     writer += "arrayOf(\\";
272                     auto val = enum_def.Vals().front();
273                     for (auto it = vals.begin(); it != vals.end(); ++it) {
274                         auto ev = *it;
275                         for (auto k = enum_def.Distance(val, ev); k > 1; --k)
276                             writer += "\"\", \\";
277                         val = ev;
278                         writer += "\"" + (*it)->name + "\"\\";
279                         if (it+1 != vals.end()) {
280                             writer += ", \\";
281                         }
282                     }
283                     writer += ")";
284                 });
285                 GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
286                     writer += "names[e\\";
287                     if (enum_def.MinValue()->IsNonZero())
288                         writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
289                     writer += "]";
290                 });
291             }
292         });
293         writer.DecrementIdentLevel();
294         writer += "}";
295     }
296
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:
301             return "__string";
302         case BASE_TYPE_STRUCT:
303             return "__struct";
304         case BASE_TYPE_UNION:
305             return "__union";
306         case BASE_TYPE_VECTOR:
307             return ByteBufferGetter(type.VectorType(), bb_var_name);
308         case BASE_TYPE_INT:
309         case BASE_TYPE_UINT:
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:
315         case BASE_TYPE_LONG:
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";
321         case BASE_TYPE_CHAR:
322         case BASE_TYPE_UCHAR:
323         case BASE_TYPE_NONE:
324         case BASE_TYPE_UTYPE:
325             return bb_var_name + ".get";
326         case BASE_TYPE_BOOL:
327             return "0.toByte() != " + bb_var_name + ".get";
328         default:
329             return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
330         }
331     }
332
333     std::string ByteBufferSetter(const Type &type) const {
334         if (IsScalar(type.base_type)) {
335             switch (type.base_type) {
336             case BASE_TYPE_INT:
337             case BASE_TYPE_UINT:
338                 return "bb.putInt";
339             case BASE_TYPE_SHORT:
340             case BASE_TYPE_USHORT:
341                 return "bb.putShort";
342             case BASE_TYPE_ULONG:
343             case BASE_TYPE_LONG:
344                 return "bb.putLong";
345             case BASE_TYPE_FLOAT:
346                 return "bb.putFloat";
347             case BASE_TYPE_DOUBLE:
348                 return "bb.putDouble";
349             case BASE_TYPE_CHAR:
350             case BASE_TYPE_UCHAR:
351             case BASE_TYPE_BOOL:
352             case BASE_TYPE_NONE:
353             case BASE_TYPE_UTYPE:
354                 return "bb.put";
355             default:
356                 return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
357             }
358         }
359         return "";
360     }
361
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) + ")";
368
369     }
370
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");
375     }
376
377     // Recursively generate arguments for a constructor, to deal with nested
378     // structs.
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) {
383             auto &field = **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
388                 // name.
389                 GenStructArgs(*field.value.type.struct_def, writer,
390                               (nameprefix + (field.name + "_")).c_str());
391             } else {
392                 writer += std::string(", ") + nameprefix + "\\";
393                 writer += MakeCamel(field.name) + ": \\";
394                 writer += GenTypeBasic(field.value.type.base_type) + "\\";
395             }
396         }
397     }
398
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) {
409             auto &field = **it;
410
411             if (field.padding) {
412                 writer.SetValue("pad", NumToString(field.padding));
413                 writer += "builder.pad({{pad}})";
414             }
415             if (IsStruct(field.value.type)) {
416                 GenStructBody(*field.value.type.struct_def, writer,
417                               (nameprefix + (field.name + "_")).c_str());
418             } else {
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}})";
424             }
425         }
426     }
427
428     std::string GenByteBufferLength(const char *bb_name) const {
429         std::string bb_len = bb_name;
430         bb_len += ".capacity()";
431         return bb_len;
432     }
433
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) + ", ";
438         if (num) {
439             key_offset += num;
440             key_offset += ", _bb)";
441         } else {
442             key_offset += GenByteBufferLength("bb");
443             key_offset += " - tableOffset, bb)";
444         }
445         return key_offset;
446     }
447
448     void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
449         if (struct_def.generated) return;
450
451         GenerateComment(struct_def.doc_comment, writer, &comment_config);
452         auto fixed = struct_def.fixed;
453
454         writer.SetValue("struct_name", Esc(struct_def.name));
455         writer.SetValue("superclass", fixed ? "Struct" : "Table");
456
457         writer += "@Suppress(\"unused\")";
458         writer += "@ExperimentalUnsignedTypes";
459         writer += "class {{struct_name}} : {{superclass}}() {\n";
460
461         writer.IncrementIdentLevel();
462
463         {
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)";
468             });
469
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";
475             });
476
477             // Generate all getters
478             GenerateStructGetters(struct_def, writer);
479
480             // Generate Static Fields
481             GenerateCompanionObject(writer, [&](){
482
483                 if (!struct_def.fixed) {
484                     FieldDef *key_field = nullptr;
485
486                     // Generate verson check method.
487                     // Force compile time error if not using the same version
488                     // runtime.
489                     GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
490                         writer += "Constants.FLATBUFFERS_1_11_1()";
491                     });
492
493                     GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
494                     GenerateBufferHasIdentifier(struct_def, writer);
495                     GenerateTableCreator(struct_def, writer);
496
497                     GenerateStartStructMethod(struct_def, writer);
498
499                     // Static Add for fields
500                     auto fields = struct_def.fields.vec;
501                     int field_pos = -1;
502                     for (auto it = fields.begin(); it != fields.end(); ++it) {
503                         auto &field = **it;
504                         field_pos++;
505                         if (field.deprecated) continue;
506                         if (field.key) key_field = &field;
507                         GenerateAddField(NumToString(field_pos), field, writer);
508
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);
513                             }
514                             GenerateStartVectorField(field, writer);
515                         }
516                     }
517
518                     GenerateEndStructMethod(struct_def, writer);
519                     auto file_identifier = parser_.file_identifier_;
520                     if (parser_.root_struct_def_ == &struct_def) {
521                         GenerateFinishStructBuffer(struct_def,
522                                                    file_identifier,
523                                                    writer);
524                         GenerateFinishSizePrefixed(struct_def,
525                                                    file_identifier,
526                                                    writer);
527                     }
528
529                     if (struct_def.has_key) {
530                         GenerateLookupByKey(key_field, struct_def, writer);
531                     }
532                 } else {
533                     GenerateStaticConstructor(struct_def, writer);
534                 }
535             });
536         }
537
538         // class closing
539         writer.DecrementIdentLevel();
540         writer += "}";
541     }
542
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";
551
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()!!)";
558             }
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)";
570             } else {
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)";
575             }
576             writer += "when {";
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";
596         };
597         GenerateFun(writer, "__lookup_by_key",
598                     params.str(),
599                     Esc(struct_def.name) + "?",
600                     statements);
601     }
602
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  + ")";
611         });
612     }
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 + ")";
621         });
622     }
623
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;
630
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) {
635                 auto &field = **it;
636                 if (field.deprecated || !field.required) {
637                     continue;
638                 }
639                 writer.SetValue("offset", NumToString(field.value.offset));
640                 writer += "builder.required(o, {{offset}})";
641             }
642             writer.DecrementIdentLevel();
643             writer += "return o";
644         });
645     }
646
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));
657
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();
664             writer += "}";
665             writer += "return builder.endVector()";
666         });
667     }
668
669     void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
670         // Generate a method to start a vector, data to be added manually
671         // after.
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)));
676
677         GenerateFunOneLine(writer,
678                            "start" + MakeCamel(Esc(field.name) + "Vector", true),
679                            params,
680                            "",
681                            [&]() {
682             writer += "builder.startVector({{size}}, numElems, {{align}})";
683         });
684     }
685
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));
698
699             writer += "builder.add{{method_name}}({{pos}}, \\";
700             writer += "{{field_name}}{{cast}}, {{default}})";
701         });
702     }
703
704     static std::string ToSignedType(const Type & type) {
705         switch(type.base_type) {
706         case BASE_TYPE_UINT:
707             return GenTypeBasic(BASE_TYPE_INT);
708         case BASE_TYPE_ULONG:
709             return GenTypeBasic(BASE_TYPE_LONG);
710         case BASE_TYPE_UCHAR:
711         case BASE_TYPE_NONE:
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());
718         default:
719             return GenTypeBasic(type.base_type);
720         }
721     }
722
723     static std::string FlexBufferBuilderCast(const std::string &method,
724                                       FieldDef &field,
725                                       bool isFirst) {
726         auto field_type = GenTypeBasic(field.value.type.base_type);
727         std::string to_type;
728         if (method == "Boolean")
729             to_type = "Boolean";
730         else if (method == "Long")
731             to_type = "Long";
732         else if (method == "Int" || method == "Offset" || method == "Struct")
733             to_type = "Int";
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")
739             to_type =  "Double";
740         else if (method == "Float")
741             to_type =  isFirst ? "Float" : "Double";
742         else if (method == "UByte")
743
744         if (field_type != to_type)
745             return ".to" + to_type + "()";
746         return "";
747     }
748
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()) + ")";
754         });
755     }
756
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;
762         int num_fields = 0;
763         auto fields_vec = struct_def.fields.vec;
764
765         for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
766             auto &field = **it;
767             if (field.deprecated) continue;
768             if (IsStruct(field.value.type)) {
769                 has_no_struct_fields = false;
770             } else {
771                 num_fields++;
772             }
773         }
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...)
779
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) {
784                 auto &field = **it;
785                 if (field.deprecated) continue;
786                 params << ", " << MakeCamel(Esc(field.name), false);
787                 if (!IsScalar(field.value.type.base_type)){
788                     params << "Offset: ";
789                 } else {
790                     params << ": ";
791                 }
792                 params << GenTypeBasic(field.value.type.base_type);
793             }
794
795             GenerateFun(writer, name, params.str(), "Int", [&]() {
796                 writer.SetValue("vec_size", NumToString(fields_vec.size()));
797
798                 writer += "builder.startTable({{vec_size}})";
799
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();
804                          ++it) {
805                         auto &field = **it;
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));
813
814                             writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
815                             if (!IsScalar(field.value.type.base_type)){
816                                 writer += "Offset\\";
817                             }
818                             writer += ")";
819                         }
820                     }
821                 }
822               writer += "return end{{struct_name}}(builder)";
823             });
824         }
825
826     }
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())
832             return;
833         auto name = MakeCamel(Esc(struct_def.name), false);
834         GenerateFunOneLine(writer, name + "BufferHasIdentifier",
835                            "_bb: ByteBuffer",
836                            "Boolean",
837                            [&]() {
838             writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
839         });
840     }
841
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) {
846             auto &field = **it;
847             if (field.deprecated) continue;
848             if (field.key) key_field = &field;
849
850             GenerateComment(field.doc_comment, writer, &comment_config);
851
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);
871
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
876                 // new object.
877                 // val pos
878                 //     get() = pos(Vec3())
879                 GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
880                     writer += "{{field_name}}({{field_type}}())";
881                 });
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)";
889                 });
890             }
891
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}}";
896                     });
897                 } else {
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 "
902                                   "{{field_default}}";
903                     });
904                 }
905             } else {
906                 switch (value_base_type) {
907                 case BASE_TYPE_STRUCT:
908                     if (struct_def.fixed) {
909                         // create getter with object reuse
910                         // ex:
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)";
917                         });
918                     } else {
919                         // create getter with object reuse
920                         // ex:
921                         //  fun pos(obj: Vec3) : Vec3? {
922                         //      val o = __offset(4)
923                         //      return if(o != 0) {
924                         //          obj.__assign(o + bb_pos, bb)
925                         //      else {
926                         //          null
927                         //      }
928                         //  }
929                         // ? adds nullability annotation
930                         GenerateFun(writer, field_name, "obj: " + field_type,
931                                     return_type + "?", [&](){
932                             auto fixed = field.value.type.struct_def->fixed;
933
934                             writer.SetValue("seek", Indirect("o + bb_pos", fixed));
935                             OffsetWrapper(writer,
936                                           offset_val,
937                                           [&]() { writer += "obj.__assign({{seek}}, bb)"; },
938                                           [&]() { writer += "null"; });
939                         });
940                     }
941                     break;
942                 case BASE_TYPE_STRING:
943                     // create string getter
944                     // e.g.
945                     // val Name : String?
946                     //     get() = {
947                     //         val o = __offset(10)
948                     //         return if (o != 0) __string(o + bb_pos) else null
949                     //     }
950                     // ? adds nullability annotation
951                     GenerateGetter(writer, field_name, return_type + "?", [&](){
952
953                         writer += "val o = __offset({{offset}})";
954                         writer += "return if (o != 0) __string(o + bb_pos) else null";
955                     });
956                     break;
957                 case BASE_TYPE_VECTOR: {
958                     // e.g.
959                     // fun inventory(j: Int) : UByte {
960                     //     val o = __offset(14)
961                     //     return if (o != 0) {
962                     //         bb.get(__vector(o) + j * 1).toUByte()
963                     //     } else {
964                     //        0
965                     //     }
966                     // }
967
968                     auto vectortype = field.value.type.VectorType();
969                     std::string params = "j: Int";
970                     std::string nullable = IsScalar(vectortype.base_type) ? ""
971                                                                           : "?";
972
973                     if (vectortype.base_type == BASE_TYPE_STRUCT ||
974                             vectortype.base_type == BASE_TYPE_UNION) {
975                         params = "obj: " + field_type + ", j: Int";
976                     }
977
978                     auto ret_type = return_type + nullable;
979                     GenerateFun(writer, field_name, params, ret_type, [&](){
980                         auto inline_size = NumToString(InlineSize(vectortype));
981                         auto index = "__vector(o) + j * " + inline_size;
982                         auto not_found = NotFoundReturn(field.value.type.element);
983                         auto found = "";
984                         writer.SetValue("index", index);
985                         switch(vectortype.base_type) {
986                         case BASE_TYPE_STRUCT: {
987                             bool fixed = vectortype.struct_def->fixed;
988                             writer.SetValue("index", Indirect(index, fixed));
989                             found = "obj.__assign({{index}}, bb)";
990                             break;
991                         }
992                         case BASE_TYPE_UNION:
993                             found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
994                             break;
995                         default:
996                             found = "{{bbgetter}}({{index}}){{ucast}}";
997                         }
998                         OffsetWrapper(writer, offset_val,
999                                       [&]() { writer += found; } ,
1000                                       [&]() { writer += not_found; });
1001                     });
1002                     break;
1003                 }
1004                 case BASE_TYPE_UNION:
1005                     GenerateFun(writer, field_name, "obj: " + field_type,
1006                                 return_type + "?", [&](){
1007                         writer += OffsetWrapperOneLine(offset_val,
1008                                                        bbgetter + "(obj, o + bb_pos)",
1009                                                        "null");
1010                     });
1011                     break;
1012                 default:
1013                     FLATBUFFERS_ASSERT(0);
1014                 }
1015             }
1016
1017             if (value_base_type == BASE_TYPE_VECTOR) {
1018                 // Generate Lenght functions for vectors
1019                 GenerateGetter(writer, field_name + "Length", "Int", [&](){
1020                     writer += OffsetWrapperOneLine(offset_val,
1021                                                    "__vector_len(o)", "0");
1022                 });
1023
1024                 // See if we should generate a by-key accessor.
1025                 if (field.value.type.element == BASE_TYPE_STRUCT &&
1026                         !field.value.type.struct_def->fixed) {
1027                     auto &sd = *field.value.type.struct_def;
1028                     auto &fields = sd.fields.vec;
1029                     for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1030                         auto &kfield = **kit;
1031                         if (kfield.key) {
1032                             auto qualified_name = WrapInNameSpace(sd);
1033                             auto name = MakeCamel(Esc(field.name), false) + "ByKey";
1034                             auto params = "key: " + GenTypeGet(kfield.value.type);
1035                             auto rtype = qualified_name + "?";
1036                             GenerateFun(writer, name, params, rtype, [&] () {
1037                                 OffsetWrapper(writer, offset_val,
1038                                 [&] () {
1039                                     writer += qualified_name +
1040                                     ".__lookup_by_key(null, __vector(o), key, bb)";
1041                                 },
1042                                 [&] () {
1043                                     writer += "null";
1044                                 });
1045                             });
1046
1047                             auto param2 = "obj: " + qualified_name +
1048                                     ", key: " +
1049                                     GenTypeGet(kfield.value.type);
1050                             GenerateFun(writer, name, param2, rtype, [&](){
1051                                 OffsetWrapper(writer, offset_val,
1052                                 [&] () {
1053                                     writer += qualified_name +
1054                                     ".__lookup_by_key(obj, __vector(o), key, bb)";
1055                                 },
1056                                 [&]() { writer += "null"; });
1057                             });
1058
1059                             break;
1060                         }
1061                     }
1062                 }
1063             }
1064
1065             if ((value_base_type == BASE_TYPE_VECTOR &&
1066                  IsScalar(field.value.type.VectorType().base_type)) ||
1067                     value_base_type == BASE_TYPE_STRING) {
1068
1069                 auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
1070                                            ? 1
1071                                            : InlineSize(field.value.type.VectorType()));
1072                 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1073                 // e.g.
1074                 // val inventoryByteBuffer: ByteBuffer
1075                 //     get =  __vector_as_bytebuffer(14, 1)
1076
1077                 GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
1078                                       "ByteBuffer", [&](){
1079                     writer.SetValue("end", end_idx);
1080                     writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
1081                 });
1082
1083                 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1084                 // e.g.
1085                 // fun inventoryInByteBuffer(_bb: Bytebuffer):
1086                 //     ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
1087                 GenerateFunOneLine(writer, field_name + "InByteBuffer",
1088                                    "_bb: ByteBuffer", "ByteBuffer", [&](){
1089                     writer.SetValue("end", end_idx);
1090                     writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
1091                 });
1092             }
1093
1094             // generate object accessors if is nested_flatbuffer
1095             //fun testnestedflatbufferAsMonster() : Monster?
1096             //{ return testnestedflatbufferAsMonster(new Monster()); }
1097
1098             if (field.nested_flatbuffer) {
1099                 auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
1100                 auto nested_method_name =
1101                         field_name + "As" +
1102                         field.nested_flatbuffer->name;
1103
1104                 GenerateGetterOneLine(writer,
1105                                       nested_method_name,
1106                                       nested_type_name + "?", [&](){
1107                     writer += nested_method_name + "(" + nested_type_name + "())";
1108                 });
1109
1110                 GenerateFun(writer,
1111                             nested_method_name,
1112                             "obj: " + nested_type_name,
1113                             nested_type_name + "?", [&](){
1114                     OffsetWrapper(writer, offset_val,
1115                                   [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
1116                                   [&]() { writer += "null";});
1117                 });
1118             }
1119
1120             // Generate mutators for scalar fields or vectors of scalars.
1121             if (parser_.opts.mutable_buffer) {
1122                 auto value_type = field.value.type;
1123                 auto underlying_type = value_base_type == BASE_TYPE_VECTOR
1124                         ? value_type.VectorType()
1125                         : value_type;
1126                 auto name = "mutate" + MakeCamel(Esc(field.name), true);
1127                 auto size = NumToString(InlineSize(underlying_type));
1128                 auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
1129                 // A vector mutator also needs the index of the vector element it should
1130                 // mutate.
1131                 if (value_base_type == BASE_TYPE_VECTOR)
1132                     params.insert(0, "j: Int, ");
1133
1134                 // Boolean parameters have to be explicitly converted to byte
1135                 // representation.
1136                 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
1137                         ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
1138                         : Esc(field.name);
1139
1140                 auto setter_index = value_base_type == BASE_TYPE_VECTOR
1141                         ? "__vector(o) + j * " + size
1142                         : (struct_def.fixed
1143                            ? "bb_pos + " + offset_val
1144                            : "o + bb_pos");
1145                 if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
1146                          IsScalar(value_type.VectorType().base_type))) {
1147
1148                     auto statements = [&] () {
1149                         writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
1150                         writer.SetValue("index", setter_index);
1151                         writer.SetValue("params", setter_parameter);
1152                         writer.SetValue("cast", CastToSigned(field));
1153                         if (struct_def.fixed) {
1154                             writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1155                         } else {
1156                             OffsetWrapper(writer, offset_val, [&](){
1157                                 writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1158                                 writer += "true";
1159                             }, [&](){ writer += "false";});
1160                         }
1161                     };
1162
1163                     if (struct_def.fixed) {
1164                         GenerateFunOneLine(writer, name, params, "ByteBuffer",
1165                                     statements);
1166                     } else {
1167                         GenerateFun(writer, name, params, "Boolean",
1168                                     statements);
1169                     }
1170                 }
1171             }
1172         }
1173         if (struct_def.has_key && !struct_def.fixed) {
1174             // Key Comparison method
1175             GenerateOverrideFun(
1176                         writer,
1177                         "keysCompare",
1178                         "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
1179                 if (key_field->value.type.base_type == BASE_TYPE_STRING) {
1180                     writer.SetValue("offset", NumToString(key_field->value.offset));
1181                     writer += " return compareStrings(__offset({{offset}}, o1, "
1182                             "_bb), __offset({{offset}}, o2, _bb), _bb)";
1183
1184                 } else {
1185                     auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
1186                     auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
1187                     writer += "val val_1 = " + getter1;
1188                     writer += "val val_2 = " + getter2;
1189                     writer += "return (val_1 - val_2).sign";
1190                 }
1191             });
1192         }
1193     }
1194
1195     static std::string CastToUsigned(const FieldDef &field) {
1196         return CastToUsigned(field.value.type);
1197     }
1198
1199     static std::string CastToUsigned(const Type type) {
1200         switch (type.base_type) {
1201         case BASE_TYPE_UINT:
1202             return ".toUInt()";
1203         case BASE_TYPE_UCHAR:
1204         case BASE_TYPE_UTYPE:
1205             return ".toUByte()";
1206         case BASE_TYPE_USHORT:
1207             return ".toUShort()";
1208         case BASE_TYPE_ULONG:
1209             return ".toULong()";
1210         case BASE_TYPE_VECTOR:
1211             return CastToUsigned(type.VectorType());
1212         default:
1213             return "";
1214         }
1215     }
1216
1217     static std::string CastToSigned(const FieldDef &field) {
1218         return CastToSigned(field.value.type);
1219     }
1220
1221     static std::string CastToSigned(const Type type) {
1222         switch (type.base_type) {
1223         case BASE_TYPE_UINT:
1224             return ".toInt()";
1225         case BASE_TYPE_UCHAR:
1226         case BASE_TYPE_UTYPE:
1227             return ".toByte()";
1228         case BASE_TYPE_USHORT:
1229             return ".toShort()";
1230         case BASE_TYPE_ULONG:
1231             return ".toLong()";
1232         case BASE_TYPE_VECTOR:
1233             return CastToSigned(type.VectorType());
1234         default:
1235             return "";
1236         }
1237     }
1238
1239     static std::string LiteralSuffix(const BaseType type) {
1240         switch (type) {
1241         case BASE_TYPE_UINT:
1242         case BASE_TYPE_UCHAR:
1243         case BASE_TYPE_UTYPE:
1244         case BASE_TYPE_USHORT:
1245             return "u";
1246         case BASE_TYPE_ULONG:
1247             return "UL";
1248         case BASE_TYPE_LONG:
1249             return "L";
1250         default:
1251             return "";
1252         }
1253     }
1254
1255     void GenerateCompanionObject(CodeWriter &code,
1256                                  const std::function<void()> &callback) const {
1257         code += "companion object {";
1258         code.IncrementIdentLevel();
1259         callback();
1260         code.DecrementIdentLevel();
1261         code += "}";
1262     }
1263
1264     // Generate a documentation comment, if available.
1265     void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
1266                     const CommentConfig *config) const {
1267       if (dc.begin() == dc.end()) {
1268         // Don't output empty comment blocks with 0 lines of comment content.
1269         return;
1270       }
1271
1272       if (config != nullptr && config->first_line != nullptr) {
1273         writer += std::string(config->first_line);
1274       }
1275       std::string line_prefix =
1276           ((config != nullptr && config->content_line_prefix != nullptr)
1277                ? config->content_line_prefix
1278                : "///");
1279       for (auto it = dc.begin(); it != dc.end(); ++it) {
1280         writer += line_prefix + *it;
1281       }
1282       if (config != nullptr && config->last_line != nullptr) {
1283         writer += std::string(config->last_line);
1284       }
1285     }
1286
1287     static void GenerateGetRootAsAccessors(const std::string &struct_name,
1288                                            CodeWriter &writer) {
1289         // Generate a special accessor for the table that when used as the root
1290         // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
1291         writer.SetValue("gr_name", struct_name);
1292         writer.SetValue("gr_method", "getRootAs" + struct_name);
1293
1294         // create convenience method that doesn't require an existing object
1295         writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
1296         writer += "{{gr_method}}(_bb, {{gr_name}}())";
1297
1298         // create method that allows object reuse
1299         // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
1300         writer += "fun {{gr_method}}"
1301                  "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
1302         writer.IncrementIdentLevel();
1303         writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
1304         writer += "return (obj.__assign(_bb.getInt(_bb.position())"
1305                  " + _bb.position(), _bb))";
1306         writer.DecrementIdentLevel();
1307         writer += "}";
1308     }
1309
1310     static void GenerateStaticConstructor(const StructDef &struct_def,
1311                                           CodeWriter &code) {
1312         // create a struct constructor function
1313         auto params = StructConstructorParams(struct_def);
1314         GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
1315             GenStructBody(struct_def, code, "");
1316             code += "return builder.offset()";
1317         });
1318     }
1319
1320     static std::string StructConstructorParams(const StructDef &struct_def,
1321                                                const std::string &prefix = "") {
1322         //builder: FlatBufferBuilder
1323         std::stringstream out;
1324         auto field_vec = struct_def.fields.vec;
1325         if (prefix.empty()) {
1326             out << "builder: FlatBufferBuilder";
1327         }
1328         for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
1329             auto &field = **it;
1330             if (IsStruct(field.value.type)) {
1331                 // Generate arguments for a struct inside a struct. To ensure
1332                 // names don't clash, and to make it obvious these arguments are
1333                 // constructing a nested struct, prefix the name with the field
1334                 // name.
1335                 out << StructConstructorParams(*field.value.type.struct_def,
1336                                               prefix + (Esc(field.name) + "_"));
1337             } else {
1338                 out << ", " << prefix << MakeCamel(Esc(field.name), false)
1339                     << ": "
1340                     << GenTypeBasic(field.value.type.base_type);
1341             }
1342         }
1343         return out.str();
1344     }
1345
1346     static void GeneratePropertyOneLine(CodeWriter &writer,
1347                                const std::string &name,
1348                                const std::string &type,
1349                                const std::function<void()> &body) {
1350         // Generates Kotlin getter for properties
1351         // e.g.:
1352         // val prop: Mytype = x
1353         writer.SetValue("_name", name);
1354         writer.SetValue("_type", type);
1355         writer += "val {{_name}} : {{_type}} = \\";
1356         body();
1357     }
1358     static void GenerateGetterOneLine(CodeWriter &writer,
1359                                const std::string &name,
1360                                const std::string &type,
1361                                const std::function<void()> &body) {
1362         // Generates Kotlin getter for properties
1363         // e.g.:
1364         // val prop: Mytype get() = x
1365         writer.SetValue("_name", name);
1366         writer.SetValue("_type", type);
1367         writer += "val {{_name}} : {{_type}} get() = \\";
1368         body();
1369     }
1370
1371     static void GenerateGetter(CodeWriter &writer,
1372                                const std::string &name,
1373                                const std::string &type,
1374                                const std::function<void()> &body) {
1375         // Generates Kotlin getter for properties
1376         // e.g.:
1377         // val prop: Mytype
1378         //     get() = {
1379         //       return x
1380         //     }
1381         writer.SetValue("name", name);
1382         writer.SetValue("type", type);
1383         writer += "val {{name}} : {{type}}";
1384         writer.IncrementIdentLevel();
1385         writer += "get() {";
1386         writer.IncrementIdentLevel();
1387         body();
1388         writer.DecrementIdentLevel();
1389         writer += "}";
1390         writer.DecrementIdentLevel();
1391     }
1392
1393     static void GenerateFun(CodeWriter &writer,
1394                             const std::string &name,
1395                             const std::string &params,
1396                             const std::string &returnType,
1397                             const std::function<void()> &body) {
1398         // Generates Kotlin function
1399         // e.g.:
1400         // fun path(j: Int): Vec3 {
1401         //     return path(Vec3(), j)
1402         // }
1403         auto noreturn = returnType.empty();
1404         writer.SetValue("name", name);
1405         writer.SetValue("params", params);
1406         writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
1407         writer += "fun {{name}}({{params}}) {{return_type}} {";
1408         writer.IncrementIdentLevel();
1409         body();
1410         writer.DecrementIdentLevel();
1411         writer += "}";
1412     }
1413
1414     static void GenerateFunOneLine(CodeWriter &writer,
1415                                    const std::string &name,
1416                                    const std::string &params,
1417                                    const std::string &returnType,
1418                                    const std::function<void()> &body) {
1419         // Generates Kotlin function
1420         // e.g.:
1421         // fun path(j: Int): Vec3 = return path(Vec3(), j)
1422         writer.SetValue("name", name);
1423         writer.SetValue("params", params);
1424         writer.SetValue("return_type_p", returnType.empty() ? "" :
1425                                                           " : " + returnType);
1426         writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
1427         body();
1428     }
1429
1430     static void GenerateOverrideFun(CodeWriter &writer,
1431                                    const std::string &name,
1432                                    const std::string &params,
1433                                    const std::string &returnType,
1434                                    const std::function<void()> &body) {
1435         // Generates Kotlin function
1436         // e.g.:
1437         // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1438         writer += "override \\";
1439         GenerateFun(writer, name, params, returnType, body);
1440     }
1441
1442     static void GenerateOverrideFunOneLine(CodeWriter &writer,
1443                                    const std::string &name,
1444                                    const std::string &params,
1445                                    const std::string &returnType,
1446                                    const std::string &statement) {
1447         // Generates Kotlin function
1448         // e.g.:
1449         // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1450         writer.SetValue("name", name);
1451         writer.SetValue("params", params);
1452         writer.SetValue("return_type", returnType.empty() ? "" :
1453                                                           " : " + returnType);
1454         writer += "override fun {{name}}({{params}}){{return_type}} = \\";
1455         writer += statement;
1456     }
1457
1458     static std::string OffsetWrapperOneLine(const std::string &offset,
1459                                             const std::string &found,
1460                                             const std::string &not_found) {
1461         return "val o = __offset(" + offset + "); return if (o != 0) " + found +
1462                 " else " + not_found;
1463     }
1464
1465     static void OffsetWrapper(CodeWriter &code,
1466                        const std::string &offset,
1467                        const std::function<void()> &found,
1468                        const std::function<void()> &not_found) {
1469         code += "val o = __offset(" + offset + ")";
1470         code +="return if (o != 0) {";
1471         code.IncrementIdentLevel();
1472         found();
1473         code.DecrementIdentLevel();
1474         code += "} else {";
1475         code.IncrementIdentLevel();
1476         not_found();
1477         code.DecrementIdentLevel();
1478         code += "}";
1479     }
1480
1481     static std::string Indirect(const std::string &index, bool fixed) {
1482         // We apply __indirect() and struct is not fixed.
1483         if (!fixed)
1484             return "__indirect(" + index + ")";
1485         return index;
1486     }
1487
1488     static std::string NotFoundReturn(BaseType el) {
1489         switch (el) {
1490         case BASE_TYPE_FLOAT:
1491            return "0.0f";
1492          case BASE_TYPE_DOUBLE:
1493             return "0.0";
1494         case BASE_TYPE_BOOL:
1495             return "false";
1496         case BASE_TYPE_LONG:
1497         case BASE_TYPE_INT:
1498         case BASE_TYPE_CHAR:
1499         case BASE_TYPE_SHORT:
1500             return "0";
1501         case BASE_TYPE_UINT:
1502         case BASE_TYPE_UCHAR:
1503         case BASE_TYPE_USHORT:
1504         case BASE_TYPE_UTYPE:
1505             return "0u";
1506         case BASE_TYPE_ULONG:
1507             return "0uL";
1508         default:
1509             return "null";
1510         }
1511     }
1512
1513     // This tracks the current namespace used to determine if a type need to be
1514     // prefixed by its namespace
1515     const Namespace *cur_name_space_;
1516 };
1517 }  // namespace kotlin
1518
1519 bool GenerateKotlin(const Parser &parser, const std::string &path,
1520                     const std::string &file_name) {
1521     kotlin::KotlinGenerator generator(parser, path, file_name);
1522     return generator.generate();
1523 }
1524 }  // namespace flatbuffers