• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #include <unordered_set>
18 
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23 
24 namespace flatbuffers {
25 
26 namespace swift {
27 
GenIndirect(const std::string & reading)28 inline std::string GenIndirect(const std::string &reading) {
29   return "{{ACCESS}}.indirect(" + reading + ")";
30 }
31 
GenArrayMainBody(const std::string & optional)32 inline std::string GenArrayMainBody(const std::string &optional) {
33   return "\tpublic func {{VALUENAME}}(at index: Int32) -> {{VALUETYPE}}" +
34          optional + " { ";
35 }
36 
LowerCase(char c)37 inline char LowerCase(char c) {
38   return static_cast<char>(::tolower(static_cast<unsigned char>(c)));
39 }
40 
41 class SwiftGenerator : public BaseGenerator {
42  private:
43   const Namespace *cur_name_space_;
44   CodeWriter code_;
45   std::unordered_set<std::string> keywords_;
46   std::set<std::string> namespaces_;
47   int namespace_depth;
48 
49  public:
SwiftGenerator(const Parser & parser,const std::string & path,const std::string & file_name)50   SwiftGenerator(const Parser &parser, const std::string &path,
51                  const std::string &file_name)
52       : BaseGenerator(parser, path, file_name, "", ".", "swift"),
53         cur_name_space_(nullptr) {
54     namespace_depth = 0;
55     static const char *const keywords[] = {
56       "associatedtype",
57       "class",
58       "deinit",
59       "enum",
60       "extension",
61       "fileprivate",
62       "func",
63       "import",
64       "init",
65       "inout",
66       "internal",
67       "let",
68       "open",
69       "operator",
70       "private",
71       "protocol",
72       "public",
73       "rethrows",
74       "static",
75       "struct",
76       "subscript",
77       "typealias",
78       "var",
79       "break",
80       "case",
81       "continue",
82       "default",
83       "defer",
84       "do",
85       "else",
86       "fallthrough",
87       "for",
88       "guard",
89       "if",
90       "in",
91       "repeat",
92       "return",
93       "switch",
94       "where",
95       "while",
96       "Any",
97       "catch",
98       "false",
99       "is",
100       "nil",
101       "super",
102       "self",
103       "Self",
104       "throw",
105       "throws",
106       "true",
107       "try",
108       "associativity",
109       "convenience",
110       "dynamic",
111       "didSet",
112       "final",
113       "get",
114       "infix",
115       "indirect",
116       "lazy",
117       "left",
118       "mutating",
119       "none",
120       "nonmutating",
121       "optional",
122       "override",
123       "postfix",
124       "precedence",
125       "prefix",
126       "Protocol",
127       "required",
128       "right",
129       "set",
130       "Type",
131       "unowned",
132       "weak",
133       "willSet",
134       nullptr,
135     };
136     for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
137   }
138 
generate()139   bool generate() {
140     code_.Clear();
141     code_.SetValue("ACCESS", "_accessor");
142     code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n";
143     code_ += "import FlatBuffers\n";
144     // Generate code for all the enum declarations.
145 
146     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
147          ++it) {
148       const auto &enum_def = **it;
149       if (!enum_def.generated) {
150         SetNameSpace(enum_def.defined_namespace);
151         GenEnum(enum_def);
152       }
153     }
154 
155     for (auto it = parser_.structs_.vec.begin();
156          it != parser_.structs_.vec.end(); ++it) {
157       const auto &struct_def = **it;
158       if (struct_def.fixed && !struct_def.generated) {
159         SetNameSpace(struct_def.defined_namespace);
160         GenStructReader(struct_def);
161       }
162     }
163 
164     for (auto it = parser_.structs_.vec.begin();
165          it != parser_.structs_.vec.end(); ++it) {
166       const auto &struct_def = **it;
167       if (struct_def.fixed && !struct_def.generated) {
168         SetNameSpace(struct_def.defined_namespace);
169         GenStructWriter(struct_def);
170       }
171     }
172 
173     for (auto it = parser_.structs_.vec.begin();
174          it != parser_.structs_.vec.end(); ++it) {
175       const auto &struct_def = **it;
176       if (!struct_def.fixed && !struct_def.generated) {
177         SetNameSpace(struct_def.defined_namespace);
178         GenTable(struct_def);
179       }
180     }
181 
182     if (cur_name_space_) SetNameSpace(nullptr);
183 
184     const auto filename = GeneratedFileName(path_, file_name_, parser_.opts);
185     const auto final_code = code_.ToString();
186     return SaveFile(filename.c_str(), final_code, false);
187   }
188 
mark(const std::string & str)189   void mark(const std::string &str) {
190     code_.SetValue("MARKVALUE", str);
191     code_ += "\n// MARK: - {{MARKVALUE}}\n";
192   }
193 
194   // Generates the create function for swift
GenStructWriter(const StructDef & struct_def)195   void GenStructWriter(const StructDef &struct_def) {
196     code_.SetValue("STRUCTNAME", Name(struct_def));
197     std::string static_type = this->namespace_depth == 0 ? "" : "static ";
198     code_ += "public " + static_type + "func create{{STRUCTNAME}}(\\";
199     std::string func_header = "";
200     GenerateStructArgs(struct_def, &func_header, "");
201     code_ += func_header.substr(0, func_header.size() - 2) + "\\";
202     code_ += ") -> UnsafeMutableRawPointer {";
203     code_ +=
204         "\tlet memory = UnsafeMutableRawPointer.allocate(byteCount: "
205         "{{STRUCTNAME}}.size, alignment: {{STRUCTNAME}}.alignment)";
206     code_ +=
207         "\tmemory.initializeMemory(as: UInt8.self, repeating: 0, count: "
208         "{{STRUCTNAME}}.size)";
209     GenerateStructBody(struct_def, "");
210     code_ += "\treturn memory";
211     code_ += "}\n";
212   }
213 
GenerateStructBody(const StructDef & struct_def,const std::string & nameprefix,int offset=0)214   void GenerateStructBody(const StructDef &struct_def,
215                           const std::string &nameprefix, int offset = 0) {
216     for (auto it = struct_def.fields.vec.begin();
217          it != struct_def.fields.vec.end(); ++it) {
218       auto &field = **it;
219       if (field.deprecated) continue;
220       auto name = nameprefix + Name(field);
221       const auto &field_type = field.value.type;
222       auto type = GenTypeBasic(field_type, false);
223       if (IsStruct(field.value.type)) {
224         GenerateStructBody(*field_type.struct_def, (nameprefix + field.name),
225                            static_cast<int>(field.value.offset));
226       } else {
227         auto off = NumToString(offset + field.value.offset);
228         code_ += "\tmemory.storeBytes(of: " + name +
229                  (field_type.enum_def ? ".rawValue" : "") +
230                  ", toByteOffset: " + off + ", as: " + type + ".self)";
231       }
232     }
233   }
234 
GenerateStructArgs(const StructDef & struct_def,std::string * code_ptr,const std::string & nameprefix)235   void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr,
236                           const std::string &nameprefix) {
237     auto &code = *code_ptr;
238     for (auto it = struct_def.fields.vec.begin();
239          it != struct_def.fields.vec.end(); ++it) {
240       auto &field = **it;
241       if (field.deprecated) continue;
242       const auto &field_type = field.value.type;
243       if (IsStruct(field.value.type)) {
244         GenerateStructArgs(*field_type.struct_def, code_ptr,
245                            (nameprefix + field.name));
246       } else {
247         auto name = Name(field);
248         auto type = GenType(field.value.type);
249         code += nameprefix + name + ": " + type;
250         code += ", ";
251       }
252     }
253   }
254 
GenObjectHeader(const StructDef & struct_def)255   void GenObjectHeader(const StructDef &struct_def) {
256     GenComment(struct_def.doc_comment);
257     code_.SetValue("STRUCTNAME", Name(struct_def));
258     code_.SetValue("PROTOCOL",
259                    struct_def.fixed ? "Readable" : "FlatBufferObject");
260     code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
261     code_ += "public struct {{STRUCTNAME}}: {{PROTOCOL}} {\n";
262     code_ += ValidateFunc();
263     code_ += "\tpublic var __buffer: ByteBuffer! { return {{ACCESS}}.bb }";
264     code_ += "\n\tprivate var {{ACCESS}}: {{OBJECTTYPE}}";
265     if (struct_def.fixed) {
266       code_.SetValue("BYTESIZE", NumToString(struct_def.bytesize));
267       code_.SetValue("MINALIGN", NumToString(struct_def.minalign));
268       code_ += "\tpublic static var size = {{BYTESIZE}}";
269       code_ += "\tpublic static var alignment = {{MINALIGN}}\t";
270     } else {
271       if (parser_.file_identifier_.length()) {
272         code_.SetValue("FILENAME", parser_.file_identifier_);
273         code_ +=
274             "\tpublic static func finish(_ fbb: FlatBufferBuilder, end: "
275             "Offset<UOffset>, prefix: Bool = false) { fbb.finish(offset: end, "
276             "fileId: "
277             "\"{{FILENAME}}\", addPrefix: prefix) }";
278       }
279       code_ +=
280           "\tpublic static func getRootAs{{STRUCTNAME}}(bb: ByteBuffer) -> "
281           "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: "
282           "Int32(bb.read(def: UOffset.self, position: bb.reader)) + "
283           "Int32(bb.reader))) }\n";
284       code_ += "\tprivate init(_ t: Table) { {{ACCESS}} = t }";
285     }
286     code_ +=
287         "\tpublic init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = "
288         "{{OBJECTTYPE}}(bb: "
289         "bb, position: o) }";
290     code_ += "";
291   }
292 
293   // Generates the reader for swift
GenTable(const StructDef & struct_def)294   void GenTable(const StructDef &struct_def) {
295     GenObjectHeader(struct_def);
296     GenTableReader(struct_def);
297     GenTableWriter(struct_def);
298     code_ += "}\n";
299   }
300 
GenTableReader(const StructDef & struct_def)301   void GenTableReader(const StructDef &struct_def) {
302     for (auto it = struct_def.fields.vec.begin();
303          it != struct_def.fields.vec.end(); ++it) {
304       auto &field = **it;
305       if (field.deprecated) continue;
306       GenTableReaderFields(field);
307     }
308   }
309 
GenTableWriter(const StructDef & struct_def)310   void GenTableWriter(const StructDef &struct_def) {
311     flatbuffers::FieldDef *key_field = nullptr;
312     std::vector<std::string> require_fields;
313     std::string create_func_body;
314     std::string create_func_header;
315     auto should_generate_create = struct_def.fields.vec.size() != 0;
316 
317     code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size()));
318     code_ +=
319         "\tpublic static func start{{STRUCTNAME}}(_ fbb: FlatBufferBuilder) -> "
320         "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }";
321 
322     for (auto it = struct_def.fields.vec.begin();
323          it != struct_def.fields.vec.end(); ++it) {
324       auto &field = **it;
325       if (field.deprecated) continue;
326       if (field.key) key_field = &field;
327       if (field.required)
328         require_fields.push_back(NumToString(field.value.offset));
329 
330       GenTableWriterFields(
331           field, &create_func_body, &create_func_header,
332           static_cast<int>(it - struct_def.fields.vec.begin()));
333     }
334     code_ +=
335         "\tpublic static func end{{STRUCTNAME}}(_ fbb: FlatBufferBuilder, "
336         "start: "
337         "UOffset) -> Offset<UOffset> { let end = Offset<UOffset>(offset: "
338         "fbb.endTable(at: start))\\";
339     if (require_fields.capacity() != 0) {
340       std::string fields = "";
341       for (auto it = require_fields.begin(); it != require_fields.end(); ++it)
342         fields += *it + ", ";
343       code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2));
344       code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\";
345     }
346     code_ += "; return end }";
347 
348     code_ +=
349         "\tpublic static func create{{STRUCTNAME}}(_ fbb: FlatBufferBuilder\\";
350     if (should_generate_create)
351       code_ += ",\n" +
352                create_func_header.substr(0, create_func_header.size() - 2) +
353                "\\";
354     code_ += ") -> Offset<UOffset> {";
355     code_ += "\t\tlet __start = {{STRUCTNAME}}.start{{STRUCTNAME}}(fbb)";
356     if (should_generate_create)
357       code_ += create_func_body.substr(0, create_func_body.size() - 1);
358     code_ += "\t\treturn {{STRUCTNAME}}.end{{STRUCTNAME}}(fbb, start: __start)";
359     code_ += "\t}";
360 
361     std::string spacing = "\t\t";
362 
363     if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) {
364       code_.SetValue("VALUENAME", struct_def.name);
365       code_.SetValue("VOFFSET", NumToString(key_field->value.offset));
366 
367       code_ +=
368           "\tpublic static func "
369           "sortVectorOf{{VALUENAME}}(offsets:[Offset<UOffset>], "
370           "_ fbb: FlatBufferBuilder) -> Offset<UOffset> {";
371       code_ += spacing + "var off = offsets";
372       code_ +=
373           spacing +
374           "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: "
375           "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: "
376           "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } ";
377       code_ += spacing + "return fbb.createVector(ofOffsets: off)";
378       code_ += "\t}";
379       GenLookup(*key_field);
380     }
381   }
382 
GenTableWriterFields(const FieldDef & field,std::string * create_body,std::string * create_header,const int position)383   void GenTableWriterFields(const FieldDef &field, std::string *create_body,
384                             std::string *create_header, const int position) {
385     std::string builder_string = ", _ fbb: FlatBufferBuilder) { fbb.add(";
386     auto &create_func_body = *create_body;
387     auto &create_func_header = *create_header;
388     auto name = Name(field);
389     auto type = GenType(field.value.type);
390     code_.SetValue("VALUENAME", name);
391     code_.SetValue("VALUETYPE", type);
392     code_.SetValue("OFFSET", NumToString(position));
393     code_.SetValue("CONSTANT", field.value.constant);
394     std::string check_if_vector =
395         (field.value.type.base_type == BASE_TYPE_VECTOR ||
396          field.value.type.base_type == BASE_TYPE_ARRAY)
397             ? "VectorOf("
398             : "(";
399     std::string body = "add" + check_if_vector + name + ": ";
400     code_ += "\tpublic static func " + body + "\\";
401 
402     create_func_body += "\t\t{{STRUCTNAME}}." + body + name + ", fbb)\n";
403 
404     if (IsScalar(field.value.type.base_type) &&
405         !IsBool(field.value.type.base_type)) {
406       auto default_value = IsEnum(field.value.type) ? GenEnumDefaultValue(field)
407                                                     : field.value.constant;
408       auto is_enum = IsEnum(field.value.type) ? ".rawValue" : "";
409       code_ += "{{VALUETYPE}}" + builder_string + "element: {{VALUENAME}}" +
410                is_enum + ", def: {{CONSTANT}}, at: {{OFFSET}}) }";
411       create_func_header +=
412           "\t\t" + name + ": " + type + " = " + default_value + ",\n";
413       return;
414     }
415 
416     if (IsBool(field.value.type.base_type)) {
417       std::string default_value =
418           "0" == field.value.constant ? "false" : "true";
419       code_.SetValue("VALUETYPE", "Bool");
420       code_.SetValue("CONSTANT", default_value);
421       code_ += "{{VALUETYPE}}" + builder_string +
422                "condition: {{VALUENAME}}, def: {{CONSTANT}}, at: {{OFFSET}}) }";
423       create_func_header +=
424           "\t\t" + name + ": " + type + " = " + default_value + ",\n";
425       return;
426     }
427 
428     auto offset_type = field.value.type.base_type == BASE_TYPE_STRING
429                            ? "Offset<String>"
430                            : "Offset<UOffset>";
431     auto camel_case_name =
432         (field.value.type.base_type == BASE_TYPE_VECTOR ||
433                  field.value.type.base_type == BASE_TYPE_ARRAY
434              ? "vectorOf"
435              : "offsetOf") +
436         MakeCamel(name, true);
437     create_func_header += "\t\t" + camel_case_name + " " + name + ": " +
438                           offset_type + " = Offset(),\n";
439     auto reader_type =
440         IsStruct(field.value.type) && field.value.type.struct_def->fixed
441             ? "structOffset: {{OFFSET}}) }"
442             : "offset: {{VALUENAME}}, at: {{OFFSET}})  }";
443     code_ += offset_type + builder_string + reader_type;
444   }
445 
GenTableReaderFields(const FieldDef & field)446   void GenTableReaderFields(const FieldDef &field) {
447     auto offset = NumToString(field.value.offset);
448     auto name = Name(field);
449     auto type = GenType(field.value.type);
450     code_.SetValue("VALUENAME", name);
451     code_.SetValue("VALUETYPE", type);
452     code_.SetValue("OFFSET", offset);
453     code_.SetValue("CONSTANT", field.value.constant);
454     std::string const_string = "return o == 0 ? {{CONSTANT}} : ";
455     GenComment(field.doc_comment, "\t");
456     if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) &&
457         !IsBool(field.value.type.base_type)) {
458       code_ += GenReaderMainBody() + GenOffset() + const_string +
459                GenReader("VALUETYPE", "o") + " }";
460       if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
461       return;
462     }
463 
464     if (IsBool(field.value.type.base_type)) {
465       code_.SetValue("VALUETYPE", "Bool");
466       code_ += GenReaderMainBody() + "\\";
467       code_.SetValue("VALUETYPE", "Byte");
468       code_ += GenOffset() +
469                "return o == 0 ? false : 0 != " + GenReader("VALUETYPE", "o") +
470                " }";
471       if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset());
472       return;
473     }
474 
475     if (IsEnum(field.value.type)) {
476       auto default_value = GenEnumDefaultValue(field);
477       code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
478       code_ += GenReaderMainBody() + "\\";
479       code_ += GenOffset() + "return o == 0 ? " + default_value + " : " +
480                GenEnumConstructor("o") + "?? " + default_value + " }";
481       if (parser_.opts.mutable_buffer && !IsUnion(field.value.type))
482         code_ += GenMutate("o", GenOffset(), true);
483       return;
484     }
485 
486     if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) {
487       code_.SetValue("VALUETYPE", GenType(field.value.type));
488       code_.SetValue("CONSTANT", "nil");
489       code_ += GenReaderMainBody("?") + GenOffset() + const_string +
490                GenConstructor("o + {{ACCESS}}.postion");
491       return;
492     }
493     switch (field.value.type.base_type) {
494       case BASE_TYPE_STRUCT:
495         code_.SetValue("VALUETYPE", GenType(field.value.type));
496         code_.SetValue("CONSTANT", "nil");
497         code_ += GenReaderMainBody("?") + GenOffset() + const_string +
498                  GenConstructor(GenIndirect("o + {{ACCESS}}.postion"));
499         break;
500 
501       case BASE_TYPE_STRING:
502         code_.SetValue("VALUETYPE", GenType(field.value.type));
503         code_.SetValue("CONSTANT", "nil");
504         code_ += GenReaderMainBody("?") + GenOffset() + const_string +
505                  "{{ACCESS}}.string(at: o) }";
506         code_ +=
507             "\tpublic var {{VALUENAME}}SegmentArray: [UInt8]? { return "
508             "{{ACCESS}}.getVector(at: {{OFFSET}}) }";
509         break;
510 
511       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
512       case BASE_TYPE_VECTOR:
513         GenTableReaderVectorFields(field, const_string);
514         break;
515       case BASE_TYPE_UNION:
516         code_.SetValue("CONSTANT", "nil");
517         code_ +=
518             "\tpublic func {{VALUENAME}}<T: FlatBufferObject>(type: "
519             "T.Type) -> T? { " +
520             GenOffset() + const_string + "{{ACCESS}}.union(o) }";
521         break;
522       default: FLATBUFFERS_ASSERT(0);
523     }
524   }
525 
GenTableReaderVectorFields(const FieldDef & field,const std::string & const_string)526   void GenTableReaderVectorFields(const FieldDef &field,
527                                   const std::string &const_string) {
528     auto vectortype = field.value.type.VectorType();
529     code_.SetValue("SIZE", NumToString(InlineSize(vectortype)));
530     code_ += "\tpublic var {{VALUENAME}}Count: Int32 { " + GenOffset() +
531              const_string + "{{ACCESS}}.vector(count: o) }";
532     code_.SetValue("CONSTANT", IsScalar(vectortype.base_type) == true
533                                    ? field.value.constant
534                                    : "nil");
535     auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?";
536     nullable = IsEnum(vectortype) == true ? "?" : nullable;
537     if (vectortype.base_type != BASE_TYPE_UNION) {
538       code_ += GenArrayMainBody(nullable) + GenOffset() + "\\";
539     } else {
540       code_ +=
541           "\tpublic func {{VALUENAME}}<T: FlatBufferObject>(at index: "
542           "Int32, type: T.Type) -> T? { " +
543           GenOffset() + "\\";
544     }
545 
546     if (IsBool(vectortype.base_type)) {
547       code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true");
548       code_.SetValue("VALUETYPE", "Byte");
549     }
550     if (!IsEnum(vectortype))
551       code_ +=
552           const_string + (IsBool(vectortype.base_type) ? "0 != " : "") + "\\";
553 
554     if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) &&
555         !IsBool(field.value.type.base_type)) {
556       code_ +=
557           "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: "
558           "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
559       code_ +=
560           "\tpublic var {{VALUENAME}}: [{{VALUETYPE}}] { return "
561           "{{ACCESS}}.getVector(at: {{OFFSET}}) ?? [] }";
562       if (parser_.opts.mutable_buffer) code_ += GenMutateArray();
563       return;
564     }
565     if (vectortype.base_type == BASE_TYPE_STRUCT &&
566         field.value.type.struct_def->fixed) {
567       code_ += GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}");
568       return;
569     }
570 
571     if (vectortype.base_type == BASE_TYPE_STRING) {
572       code_ +=
573           "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + "
574           "index * {{SIZE}}) }";
575       return;
576     }
577 
578     if (IsEnum(vectortype)) {
579       code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false));
580       code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) +
581                " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: "
582                "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + "
583                "index * {{SIZE}})) }";
584       return;
585     }
586     if (vectortype.base_type == BASE_TYPE_UNION) {
587       code_ +=
588           "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + "
589           "index * {{SIZE}}) }";
590       return;
591     }
592 
593     if (vectortype.base_type == BASE_TYPE_STRUCT &&
594         !field.value.type.struct_def->fixed) {
595       code_ += GenConstructor(
596           "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * "
597           "{{SIZE}})");
598       auto &sd = *field.value.type.struct_def;
599       auto &fields = sd.fields.vec;
600       for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
601         auto &key_field = **kit;
602         if (key_field.key) {
603           GenByKeyFunctions(key_field);
604           break;
605         }
606       }
607     }
608   }
609 
GenByKeyFunctions(const FieldDef & key_field)610   void GenByKeyFunctions(const FieldDef &key_field) {
611     code_.SetValue("TYPE", GenType(key_field.value.type));
612     code_ +=
613         "\tpublic func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? { \\";
614     code_ += GenOffset() +
615              "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: "
616              "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }";
617   }
618 
619   // Generates the reader for swift
GenStructReader(const StructDef & struct_def)620   void GenStructReader(const StructDef &struct_def) {
621     GenObjectHeader(struct_def);
622     for (auto it = struct_def.fields.vec.begin();
623          it != struct_def.fields.vec.end(); ++it) {
624       auto &field = **it;
625       if (field.deprecated) continue;
626       auto offset = NumToString(field.value.offset);
627       auto name = Name(field);
628       auto type = GenType(field.value.type);
629       code_.SetValue("VALUENAME", name);
630       code_.SetValue("VALUETYPE", type);
631       code_.SetValue("OFFSET", offset);
632       GenComment(field.doc_comment, "\t");
633       if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) {
634         code_ +=
635             GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }";
636         if (parser_.opts.mutable_buffer) code_ += GenMutate("{{OFFSET}}", "");
637       } else if (IsEnum(field.value.type)) {
638         code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false));
639         code_ += GenReaderMainBody() + "return " +
640                  GenEnumConstructor("{{OFFSET}}") + "?? " +
641                  GenEnumDefaultValue(field) + " }";
642       } else if (IsStruct(field.value.type)) {
643         code_.SetValue("VALUETYPE", GenType(field.value.type));
644         code_ += GenReaderMainBody() + "return " +
645                  GenConstructor("{{ACCESS}}.postion + {{OFFSET}}");
646       }
647     }
648 
649     code_ += "}\n";
650   }
651 
GenEnum(const EnumDef & enum_def)652   void GenEnum(const EnumDef &enum_def) {
653     if (enum_def.generated) return;
654     code_.SetValue("ENUM_NAME", Name(enum_def));
655     code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
656     GenComment(enum_def.doc_comment);
657     code_ += "public enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum { ";
658     code_ += "\tpublic typealias T = {{BASE_TYPE}}";
659     code_ +=
660         "\tpublic static var byteSize: Int { return "
661         "MemoryLayout<{{BASE_TYPE}}>.size "
662         "}";
663     code_ += "\tpublic var value: {{BASE_TYPE}} { return self.rawValue }";
664 
665     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
666       const auto &ev = **it;
667       auto name = Name(ev);
668       std::transform(name.begin(), name.end(), name.begin(), LowerCase);
669       code_.SetValue("KEY", name);
670       code_.SetValue("VALUE", enum_def.ToString(ev));
671       GenComment(ev.doc_comment, "\t");
672       code_ += "\tcase {{KEY}} = {{VALUE}}";
673     }
674     code_ += "\n";
675     AddMinOrMaxEnumValue(enum_def.MaxValue()->name, "max");
676     AddMinOrMaxEnumValue(enum_def.MinValue()->name, "min");
677     code_ += "}\n";
678   }
679 
AddMinOrMaxEnumValue(const std::string & str,const std::string & type)680   void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) {
681     auto current_value = str;
682     std::transform(current_value.begin(), current_value.end(),
683                    current_value.begin(), LowerCase);
684     code_.SetValue(type, current_value);
685     code_ += "\tpublic static var " + type + ": {{ENUM_NAME}} { return .{{" +
686              type + "}} }";
687   }
688 
GenLookup(const FieldDef & key_field)689   void GenLookup(const FieldDef &key_field) {
690     code_.SetValue("OFFSET", NumToString(key_field.value.offset));
691     auto offset_reader =
692         "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, "
693         "fbb: fbb)";
694     std::string spacing = "\t\t";
695     std::string double_spacing = spacing + "\t";
696 
697     code_.SetValue("TYPE", GenType(key_field.value.type));
698     code_ +=
699         "\tfileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, "
700         "fbb: "
701         "ByteBuffer) -> {{VALUENAME}}? {";
702 
703     if (key_field.value.type.base_type == BASE_TYPE_STRING)
704       code_ += spacing + "let key = key.utf8.map { $0 }";
705     code_ += spacing +
706              "var span = fbb.read(def: Int32.self, position: Int(vector - 4))";
707     code_ += spacing + "var start: Int32 = 0";
708     code_ += spacing + "while span != 0 {";
709     code_ += double_spacing + "var middle = span / 2";
710     code_ +=
711         double_spacing +
712         "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)";
713     if (key_field.value.type.base_type == BASE_TYPE_STRING) {
714       code_ += double_spacing + "let comp = Table.compare(" + offset_reader +
715                ", key, fbb: fbb)";
716     } else {
717       code_ += double_spacing +
718                "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" +
719                offset_reader + "))";
720     }
721 
722     code_ += double_spacing + "if comp > 0 {";
723     code_ += double_spacing + "\tspan = middle";
724     code_ += double_spacing + "} else if comp < 0 {";
725     code_ += double_spacing + "\tmiddle += 1";
726     code_ += double_spacing + "\tstart += middle";
727     code_ += double_spacing + "\tspan -= middle";
728     code_ += double_spacing + "} else {";
729     code_ += double_spacing + "\treturn {{VALUENAME}}(fbb, o: tableOffset)";
730     code_ += double_spacing + "}";
731     code_ += spacing + "}";
732     code_ += spacing + "return nil";
733     code_ += "\t}";
734   }
735 
GenComment(const std::vector<std::string> & dc,const char * prefix="")736   void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
737     std::string text;
738     ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
739     code_ += text + "\\";
740   }
741 
GenOffset()742   std::string GenOffset() { return "let o = {{ACCESS}}.offset({{OFFSET}}); "; }
743 
GenReaderMainBody(const std::string & optional="")744   std::string GenReaderMainBody(const std::string &optional = "") {
745     return "\tpublic var {{VALUENAME}}: {{VALUETYPE}}" + optional + " { ";
746   }
747 
GenReader(const std::string & type,const std::string & at="{{OFFSET}}")748   std::string GenReader(const std::string &type,
749                         const std::string &at = "{{OFFSET}}") {
750     return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")";
751   }
752 
GenConstructor(const std::string & offset)753   std::string GenConstructor(const std::string &offset) {
754     return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }";
755   }
756 
GenMutate(const std::string & offset,const std::string & get_offset,bool isRaw=false)757   std::string GenMutate(const std::string &offset,
758                         const std::string &get_offset, bool isRaw = false) {
759     return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}) -> Bool {" +
760            get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" +
761            (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }";
762   }
763 
GenMutateArray()764   std::string GenMutateArray() {
765     return "\tpublic func mutate({{VALUENAME}}: {{VALUETYPE}}, at index: "
766            "Int32) -> Bool { " +
767            GenOffset() +
768            "return {{ACCESS}}.directMutate({{VALUENAME}}, index: "
769            "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }";
770   }
771 
GenEnumDefaultValue(const FieldDef & field)772   std::string GenEnumDefaultValue(const FieldDef &field) {
773     auto &value = field.value;
774     FLATBUFFERS_ASSERT(value.type.enum_def);
775     auto &enum_def = *value.type.enum_def;
776     auto enum_val = enum_def.FindByValue(value.constant);
777     std::string name;
778     if (enum_val) {
779       name = enum_val->name;
780     } else {
781       const auto &ev = **enum_def.Vals().begin();
782       name = ev.name;
783     }
784     std::transform(name.begin(), name.end(), name.begin(), LowerCase);
785     return "." + name;
786   }
787 
GenEnumConstructor(const std::string & at)788   std::string GenEnumConstructor(const std::string &at) {
789     return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") ";
790   }
791 
ValidateFunc()792   std::string ValidateFunc() {
793     return "\tstatic func validateVersion() { FlatBuffersVersion_1_12_0() }";
794   }
795 
GenType(const Type & type) const796   std::string GenType(const Type &type) const {
797     return IsScalar(type.base_type)
798                ? GenTypeBasic(type)
799                : (IsArray(type) ? GenType(type.VectorType())
800                                 : GenTypePointer(type));
801   }
802 
GenTypePointer(const Type & type) const803   std::string GenTypePointer(const Type &type) const {
804     switch (type.base_type) {
805       case BASE_TYPE_STRING: return "String";
806       case BASE_TYPE_VECTOR: return GenType(type.VectorType());
807       case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
808       case BASE_TYPE_UNION:
809       default: return "FlatBufferObject";
810     }
811   }
812 
GenTypeBasic(const Type & type) const813   std::string GenTypeBasic(const Type &type) const {
814     return GenTypeBasic(type, true);
815   }
816 
GenTypeBasic(const Type & type,bool can_override) const817   std::string GenTypeBasic(const Type &type, bool can_override) const {
818     // clang-format off
819     static const char * const swift_type[] = {
820       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
821               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \
822         #STYPE,
823         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
824       #undef FLATBUFFERS_TD
825     };
826     // clang-format on
827     if (can_override) {
828       if (type.enum_def)
829         return WrapInNameSpace(type.enum_def->defined_namespace,
830                                Name(*type.enum_def));
831       if (type.base_type == BASE_TYPE_BOOL) return "Bool";
832     }
833     return swift_type[static_cast<int>(type.base_type)];
834   }
835 
EscapeKeyword(const std::string & name) const836   std::string EscapeKeyword(const std::string &name) const {
837     return keywords_.find(name) == keywords_.end() ? name : name + "_";
838   }
839 
Name(const EnumVal & ev) const840   std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
841 
Name(const Definition & def) const842   std::string Name(const Definition &def) const {
843     return EscapeKeyword(MakeCamel(def.name, false));
844   }
845 
846   // MARK: - Copied from the cpp implementation, needs revisiting
SetNameSpace(const Namespace * ns)847   void SetNameSpace(const Namespace *ns) {
848     if (cur_name_space_ == ns) { return; }
849     // Compute the size of the longest common namespace prefix.
850     // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
851     // the common prefix is A::B:: and we have old_size = 4, new_size = 5
852     // and common_prefix_size = 2
853     size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
854     size_t new_size = ns ? ns->components.size() : 0;
855 
856     size_t common_prefix_size = 0;
857     while (common_prefix_size < old_size && common_prefix_size < new_size &&
858            ns->components[common_prefix_size] ==
859                cur_name_space_->components[common_prefix_size]) {
860       common_prefix_size++;
861     }
862 
863     // Close cur_name_space in reverse order to reach the common prefix.
864     // In the previous example, D then C are closed.
865     for (size_t j = old_size; j > common_prefix_size; --j) {
866       if (namespace_depth != 0) {
867         code_ += "}";
868         namespace_depth -= 1;
869       }
870       mark(cur_name_space_->components[j - 1]);
871     }
872     if (old_size != common_prefix_size) { code_ += ""; }
873 
874     // open namespace parts to reach the ns namespace
875     // in the previous example, E, then F, then G are opened
876     bool is_extension = false;
877     for (auto j = common_prefix_size; j < new_size; ++j) {
878       std::string name = ns->components[j];
879       if (namespaces_.find(name) == namespaces_.end()) {
880         code_ += "public enum " + name + " {";
881         namespace_depth += 1;
882         namespaces_.insert(name);
883       } else {
884         code_ += "}";
885         is_extension = true;
886       }
887     }
888     if (is_extension) {
889       code_.SetValue("EXTENSION", FullNamespace(".", *ns));
890       code_ += "extension {{EXTENSION}} {";
891     }
892     if (new_size != common_prefix_size) { code_ += ""; }
893     cur_name_space_ = ns;
894   }
895 };
896 }  // namespace swift
GenerateSwift(const Parser & parser,const std::string & path,const std::string & file_name)897 bool GenerateSwift(const Parser &parser, const std::string &path,
898                    const std::string &file_name) {
899   swift::SwiftGenerator generator(parser, path, file_name);
900   return generator.generate();
901 }
902 }  // namespace flatbuffers
903