Add basic Kotlin support (#5409)
[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
979                     writer.SetValue("toType", "YYYYY");
980
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);
986                         auto found = "";
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)";
993                             break;
994                         }
995                         case BASE_TYPE_UNION:
996                             found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
997                             break;
998                         default:
999                             found = "{{bbgetter}}({{index}}){{ucast}}";
1000                         }
1001                         OffsetWrapper(writer, offset_val,
1002                                       [&]() { writer += found; } ,
1003                                       [&]() { writer += not_found; });
1004                     });
1005                     break;
1006                 }
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)",
1012                                                        "null");
1013                     });
1014                     break;
1015                 default:
1016                     FLATBUFFERS_ASSERT(0);
1017                 }
1018             }
1019
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");
1025                 });
1026
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;
1034                         if (kfield.key) {
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,
1041                                 [&] () {
1042                                     writer += qualified_name +
1043                                     ".__lookup_by_key(null, __vector(o), key, bb)";
1044                                 },
1045                                 [&] () {
1046                                     writer += "null";
1047                                 });
1048                             });
1049
1050                             auto param2 = "obj: " + qualified_name +
1051                                     ", key: " +
1052                                     GenTypeGet(kfield.value.type);
1053                             GenerateFun(writer, name, param2, rtype, [&](){
1054                                 OffsetWrapper(writer, offset_val,
1055                                 [&] () {
1056                                     writer += qualified_name +
1057                                     ".__lookup_by_key(obj, __vector(o), key, bb)";
1058                                 },
1059                                 [&]() { writer += "null"; });
1060                             });
1061
1062                             break;
1063                         }
1064                     }
1065                 }
1066             }
1067
1068             if ((value_base_type == BASE_TYPE_VECTOR &&
1069                  IsScalar(field.value.type.VectorType().base_type)) ||
1070                     value_base_type == BASE_TYPE_STRING) {
1071
1072                 auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
1073                                            ? 1
1074                                            : InlineSize(field.value.type.VectorType()));
1075                 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1076                 // e.g.
1077                 // val inventoryByteBuffer: ByteBuffer
1078                 //     get =  __vector_as_bytebuffer(14, 1)
1079
1080                 GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
1081                                       "ByteBuffer", [&](){
1082                     writer.SetValue("end", end_idx);
1083                     writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
1084                 });
1085
1086                 // Generate a ByteBuffer accessor for strings & vectors of scalars.
1087                 // e.g.
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}})";
1094                 });
1095             }
1096
1097             // generate object accessors if is nested_flatbuffer
1098             //fun testnestedflatbufferAsMonster() : Monster?
1099             //{ return testnestedflatbufferAsMonster(new Monster()); }
1100
1101             if (field.nested_flatbuffer) {
1102                 auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
1103                 auto nested_method_name =
1104                         field_name + "As" +
1105                         field.nested_flatbuffer->name;
1106
1107                 GenerateGetterOneLine(writer,
1108                                       nested_method_name,
1109                                       nested_type_name + "?", [&](){
1110                     writer += nested_method_name + "(" + nested_type_name + "())";
1111                 });
1112
1113                 GenerateFun(writer,
1114                             nested_method_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";});
1120                 });
1121             }
1122
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()
1128                         : value_type;
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
1133                 // mutate.
1134                 if (value_base_type == BASE_TYPE_VECTOR)
1135                     params.insert(0, "j: Int, ");
1136
1137                 // Boolean parameters have to be explicitly converted to byte
1138                 // representation.
1139                 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
1140                         ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
1141                         : Esc(field.name);
1142
1143                 auto setter_index = value_base_type == BASE_TYPE_VECTOR
1144                         ? "__vector(o) + j * " + size
1145                         : (struct_def.fixed
1146                            ? "bb_pos + " + offset_val
1147                            : "o + bb_pos");
1148                 if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
1149                          IsScalar(value_type.VectorType().base_type))) {
1150
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}})";
1158                         } else {
1159                             OffsetWrapper(writer, offset_val, [&](){
1160                                 writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
1161                                 writer += "true";
1162                             }, [&](){ writer += "false";});
1163                         }
1164                     };
1165
1166                     if (struct_def.fixed) {
1167                         GenerateFunOneLine(writer, name, params, "ByteBuffer",
1168                                     statements);
1169                     } else {
1170                         GenerateFun(writer, name, params, "Boolean",
1171                                     statements);
1172                     }
1173                 }
1174             }
1175         }
1176         if (struct_def.has_key && !struct_def.fixed) {
1177             // Key Comparison method
1178             GenerateOverrideFun(
1179                         writer,
1180                         "keysCompare",
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)";
1186
1187                 } else {
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";
1193                 }
1194             });
1195         }
1196     }
1197
1198     static std::string CastToUsigned(const FieldDef &field) {
1199         return CastToUsigned(field.value.type);
1200     }
1201
1202     static std::string CastToUsigned(const Type type) {
1203         switch (type.base_type) {
1204         case BASE_TYPE_UINT:
1205             return ".toUInt()";
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());
1215         default:
1216             return "";
1217         }
1218     }
1219
1220     static std::string CastToSigned(const FieldDef &field) {
1221         return CastToSigned(field.value.type);
1222     }
1223
1224     static std::string CastToSigned(const Type type) {
1225         switch (type.base_type) {
1226         case BASE_TYPE_UINT:
1227             return ".toInt()";
1228         case BASE_TYPE_UCHAR:
1229         case BASE_TYPE_UTYPE:
1230             return ".toByte()";
1231         case BASE_TYPE_USHORT:
1232             return ".toShort()";
1233         case BASE_TYPE_ULONG:
1234             return ".toLong()";
1235         case BASE_TYPE_VECTOR:
1236             return CastToSigned(type.VectorType());
1237         default:
1238             return "";
1239         }
1240     }
1241
1242     static std::string LiteralSuffix(const BaseType type) {
1243         switch (type) {
1244         case BASE_TYPE_UINT:
1245         case BASE_TYPE_UCHAR:
1246         case BASE_TYPE_UTYPE:
1247         case BASE_TYPE_USHORT:
1248             return "u";
1249         case BASE_TYPE_ULONG:
1250             return "UL";
1251         case BASE_TYPE_LONG:
1252             return "L";
1253         default:
1254             return "";
1255         }
1256     }
1257
1258     void GenerateCompanionObject(CodeWriter &code,
1259                                  const std::function<void()> &callback) const {
1260         code += "companion object {";
1261         code.IncrementIdentLevel();
1262         callback();
1263         code.DecrementIdentLevel();
1264         code += "}";
1265     }
1266
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.
1272         return;
1273       }
1274
1275       if (config != nullptr && config->first_line != nullptr) {
1276         writer += std::string(config->first_line);
1277       }
1278       std::string line_prefix =
1279           ((config != nullptr && config->content_line_prefix != nullptr)
1280                ? config->content_line_prefix
1281                : "///");
1282       for (auto it = dc.begin(); it != dc.end(); ++it) {
1283         writer += line_prefix + *it;
1284       }
1285       if (config != nullptr && config->last_line != nullptr) {
1286         writer += std::string(config->last_line);
1287       }
1288     }
1289
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);
1296
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}}())";
1300
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();
1310         writer += "}";
1311     }
1312
1313     static void GenerateStaticConstructor(const StructDef &struct_def,
1314                                           CodeWriter &code) {
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()";
1320         });
1321     }
1322
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";
1330         }
1331         for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
1332             auto &field = **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
1337                 // name.
1338                 out << StructConstructorParams(*field.value.type.struct_def,
1339                                               prefix + (Esc(field.name) + "_"));
1340             } else {
1341                 out << ", " << prefix << MakeCamel(Esc(field.name), false)
1342                     << ": "
1343                     << GenTypeBasic(field.value.type.base_type);
1344             }
1345         }
1346         return out.str();
1347     }
1348
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
1354         // e.g.:
1355         // val prop: Mytype = x
1356         writer.SetValue("_name", name);
1357         writer.SetValue("_type", type);
1358         writer += "val {{_name}} : {{_type}} = \\";
1359         body();
1360     }
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
1366         // e.g.:
1367         // val prop: Mytype get() = x
1368         writer.SetValue("_name", name);
1369         writer.SetValue("_type", type);
1370         writer += "val {{_name}} : {{_type}} get() = \\";
1371         body();
1372     }
1373
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
1379         // e.g.:
1380         // val prop: Mytype
1381         //     get() = {
1382         //       return x
1383         //     }
1384         writer.SetValue("name", name);
1385         writer.SetValue("type", type);
1386         writer += "val {{name}} : {{type}}";
1387         writer.IncrementIdentLevel();
1388         writer += "get() {";
1389         writer.IncrementIdentLevel();
1390         body();
1391         writer.DecrementIdentLevel();
1392         writer += "}";
1393         writer.DecrementIdentLevel();
1394     }
1395
1396     static void GenerateFun(CodeWriter &writer,
1397                             const std::string &name,
1398                             const std::string &params,
1399                             const std::string &returnType,
1400                             const std::function<void()> &body) {
1401         // Generates Kotlin function
1402         // e.g.:
1403         // fun path(j: Int): Vec3 {
1404         //     return path(Vec3(), j)
1405         // }
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();
1412         body();
1413         writer.DecrementIdentLevel();
1414         writer += "}";
1415     }
1416
1417     static void GenerateFunOneLine(CodeWriter &writer,
1418                                    const std::string &name,
1419                                    const std::string &params,
1420                                    const std::string &returnType,
1421                                    const std::function<void()> &body) {
1422         // Generates Kotlin function
1423         // e.g.:
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}} = \\";
1430         body();
1431     }
1432
1433     static void GenerateOverrideFun(CodeWriter &writer,
1434                                    const std::string &name,
1435                                    const std::string &params,
1436                                    const std::string &returnType,
1437                                    const std::function<void()> &body) {
1438         // Generates Kotlin function
1439         // e.g.:
1440         // override fun path(j: Int): Vec3 = return path(Vec3(), j)
1441         writer += "override \\";
1442         GenerateFun(writer, name, params, returnType, body);
1443     }
1444
1445     static void GenerateOverrideFunOneLine(CodeWriter &writer,
1446                                    const std::string &name,
1447                                    const std::string &params,
1448                                    const std::string &returnType,
1449                                    const std::string &statement) {
1450         // Generates Kotlin function
1451         // e.g.:
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;
1459     }
1460
1461     static std::string OffsetWrapperOneLine(const std::string &offset,
1462                                             const std::string &found,
1463                                             const std::string &not_found) {
1464         return "val o = __offset(" + offset + "); return if (o != 0) " + found +
1465                 " else " + not_found;
1466     }
1467
1468     static void OffsetWrapper(CodeWriter &code,
1469                        const std::string &offset,
1470                        const std::function<void()> &found,
1471                        const std::function<void()> &not_found) {
1472         code += "val o = __offset(" + offset + ")";
1473         code +="return if (o != 0) {";
1474         code.IncrementIdentLevel();
1475         found();
1476         code.DecrementIdentLevel();
1477         code += "} else {";
1478         code.IncrementIdentLevel();
1479         not_found();
1480         code.DecrementIdentLevel();
1481         code += "}";
1482     }
1483
1484     static std::string Indirect(const std::string &index, bool fixed) {
1485         // We apply __indirect() and struct is not fixed.
1486         if (!fixed)
1487             return "__indirect(" + index + ")";
1488         return index;
1489     }
1490
1491     static std::string NotFoundReturn(BaseType el) {
1492         switch (el) {
1493         case BASE_TYPE_FLOAT:
1494            return "0.0f";
1495          case BASE_TYPE_DOUBLE:
1496             return "0.0";
1497         case BASE_TYPE_BOOL:
1498             return "false";
1499         case BASE_TYPE_LONG:
1500         case BASE_TYPE_INT:
1501         case BASE_TYPE_CHAR:
1502         case BASE_TYPE_SHORT:
1503             return "0";
1504         case BASE_TYPE_UINT:
1505         case BASE_TYPE_UCHAR:
1506         case BASE_TYPE_USHORT:
1507         case BASE_TYPE_UTYPE:
1508             return "0u";
1509         case BASE_TYPE_ULONG:
1510             return "0uL";
1511         default:
1512             return "null";
1513         }
1514     }
1515
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_;
1519 };
1520 }  // namespace kotlin
1521
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();
1526 }
1527 }  // namespace flatbuffers