1/*
2 * Copyright 2018 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 "idl_gen_lobster.h"
18
19#include <string>
20#include <unordered_set>
21
22#include "flatbuffers/code_generators.h"
23#include "flatbuffers/flatbuffers.h"
24#include "flatbuffers/idl.h"
25#include "flatbuffers/util.h"
26
27namespace flatbuffers {
28namespace lobster {
29
30class LobsterGenerator : public BaseGenerator {
31 public:
32 LobsterGenerator(const Parser &parser, const std::string &path,
33 const std::string &file_name)
34 : BaseGenerator(parser, path, file_name, "" /* not used */, "_",
35 "lobster") {
36 static const char *const keywords[] = {
37 "nil", "true", "false", "return", "struct", "class",
38 "import", "int", "float", "string", "any", "def",
39 "is", "from", "program", "private", "coroutine", "resource",
40 "enum", "typeof", "var", "let", "pakfile", "switch",
41 "case", "default", "namespace", "not", "and", "or",
42 "bool",
43 };
44 keywords_.insert(std::begin(keywords), std::end(keywords));
45 }
46
47 std::string EscapeKeyword(const std::string &name) const {
48 return keywords_.find(name) == keywords_.end() ? name : name + "_";
49 }
50
51 std::string NormalizedName(const Definition &definition) const {
52 return EscapeKeyword(definition.name);
53 }
54
55 std::string NormalizedName(const EnumVal &ev) const {
56 return EscapeKeyword(ev.name);
57 }
58
59 std::string NamespacedName(const Definition &def) {
60 return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
61 }
62
63 std::string GenTypeName(const Type &type) {
64 auto bits = NumToString(SizeOf(type.base_type) * 8);
65 if (IsInteger(type.base_type)) {
66 if (IsUnsigned(type.base_type))
67 return "uint" + bits;
68 else
69 return "int" + bits;
70 }
71 if (IsFloat(type.base_type)) return "float" + bits;
72 if (IsString(type)) return "string";
73 if (type.base_type == BASE_TYPE_STRUCT) return "table";
74 return "none";
75 }
76
77 std::string LobsterType(const Type &type) {
78 if (IsFloat(type.base_type)) return "float";
79 if (IsBool(type.base_type)) return "bool";
80 if (IsScalar(type.base_type) && type.enum_def)
81 return NormalizedName(*type.enum_def);
82 if (!IsScalar(type.base_type)) return "flatbuffers_offset";
83 if (IsString(type)) return "string";
84 return "int";
85 }
86
87 // Returns the method name for use with add/put calls.
88 std::string GenMethod(const Type &type) {
89 return IsScalar(type.base_type)
90 ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
91 : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
92 }
93
94 // This uses Python names for now..
95 std::string GenTypeBasic(const Type &type) {
96 // clang-format off
97 static const char *ctypename[] = {
98 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
99 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
100 #PTYPE,
101 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
102 #undef FLATBUFFERS_TD
103 };
104 // clang-format on
105 return ctypename[type.base_type];
106 }
107
108 // Generate a struct field, conditioned on its child type(s).
109 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
110 std::string *code_ptr) {
111 GenComment(field.doc_comment, code_ptr, nullptr, " ");
112 std::string &code = *code_ptr;
113 auto offsets = NumToString(field.value.offset);
114 auto def = " def " + NormalizedName(field);
115 if (IsScalar(field.value.type.base_type)) {
116 std::string acc;
117 if (struct_def.fixed) {
118 acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
119 offsets + ")";
120
121 } else {
122 auto defval = field.IsOptional() ? "0" : field.value.constant;
123 acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
124 "(pos_, " + offsets + ", " + defval + ")";
125 if (IsBool(field.value.type.base_type)) acc = "bool(" + acc + ")";
126 }
127 if (field.value.type.enum_def)
128 acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
129 if (field.IsOptional()) {
130 acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
131 code += def + "() -> " + LobsterType(field.value.type) +
132 ", bool:\n return " + acc + "\n";
133 } else {
134 code += def + "() -> " + LobsterType(field.value.type) +
135 ":\n return " + acc + "\n";
136 }
137 return;
138 }
139 switch (field.value.type.base_type) {
140 case BASE_TYPE_STRUCT: {
141 auto name = NamespacedName(*field.value.type.struct_def);
142 if (struct_def.fixed) {
143 code += def + "() -> " + name + ":\n ";
144 code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
145 } else {
146 code += def + "() -> " + name + "?:\n ";
147 code += std::string("let o = buf_.flatbuffers_field_") +
148 (field.value.type.struct_def->fixed ? "struct" : "table") +
149 "(pos_, " + offsets + ")\n return if o: " + name +
150 " { buf_, o } else: nil\n";
151 }
152 break;
153 }
154 case BASE_TYPE_STRING:
155 code += def +
156 "() -> string:\n return "
157 "buf_.flatbuffers_field_string(pos_, " +
158 offsets + ")\n";
159 break;
160 case BASE_TYPE_VECTOR: {
161 auto vectortype = field.value.type.VectorType();
162 if (vectortype.base_type == BASE_TYPE_STRUCT) {
163 auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
164 ") + i * " + NumToString(InlineSize(vectortype));
165 if (!(vectortype.struct_def->fixed)) {
166 start = "buf_.flatbuffers_indirect(" + start + ")";
167 }
168 code += def + "(i:int) -> " +
169 NamespacedName(*field.value.type.struct_def) +
170 ":\n return ";
171 code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
172 start + " }\n";
173 } else {
174 if (IsString(vectortype)) {
175 code += def + "(i:int) -> string:\n return ";
176 code += "buf_.flatbuffers_string";
177 } else {
178 code += def + "(i:int) -> " + LobsterType(vectortype) +
179 ":\n return ";
180 code += "buf_.read_" + GenTypeName(vectortype) + "_le";
181 }
182 code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
183 ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
184 }
185 break;
186 }
187 case BASE_TYPE_UNION: {
188 for (auto it = field.value.type.enum_def->Vals().begin();
189 it != field.value.type.enum_def->Vals().end(); ++it) {
190 auto &ev = **it;
191 if (ev.IsNonZero()) {
192 code += def + "_as_" + ev.name + "():\n return " +
193 NamespacedName(*ev.union_type.struct_def) +
194 " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
195 ") }\n";
196 }
197 }
198 break;
199 }
200 default: FLATBUFFERS_ASSERT(0);
201 }
202 if (IsVector(field.value.type)) {
203 code += def +
204 "_length() -> int:\n return "
205 "buf_.flatbuffers_field_vector_len(pos_, " +
206 offsets + ")\n";
207 }
208 }
209
210 // Generate table constructors, conditioned on its members' types.
211 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
212 std::string &code = *code_ptr;
213 code += "struct " + NormalizedName(struct_def) +
214 "Builder:\n b_:flatbuffers_builder\n";
215 code += " def start():\n b_.StartObject(" +
216 NumToString(struct_def.fields.vec.size()) +
217 ")\n return this\n";
218 for (auto it = struct_def.fields.vec.begin();
219 it != struct_def.fields.vec.end(); ++it) {
220 auto &field = **it;
221 if (field.deprecated) continue;
222 auto offset = it - struct_def.fields.vec.begin();
223 code += " def add_" + NormalizedName(field) + "(" +
224 NormalizedName(field) + ":" + LobsterType(field.value.type) +
225 "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
226 NumToString(offset) + ", " + NormalizedName(field);
227 if (IsScalar(field.value.type.base_type) && !field.IsOptional())
228 code += ", " + field.value.constant;
229 code += ")\n return this\n";
230 }
231 code += " def end():\n return b_.EndObject()\n\n";
232 for (auto it = struct_def.fields.vec.begin();
233 it != struct_def.fields.vec.end(); ++it) {
234 auto &field = **it;
235 if (field.deprecated) continue;
236 if (IsVector(field.value.type)) {
237 code += "def " + NormalizedName(struct_def) + "Start" +
238 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
239 "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
240 auto vector_type = field.value.type.VectorType();
241 auto alignment = InlineAlignment(vector_type);
242 auto elem_size = InlineSize(vector_type);
243 code +=
244 NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
245 if (vector_type.base_type != BASE_TYPE_STRUCT ||
246 !vector_type.struct_def->fixed) {
247 code += "def " + NormalizedName(struct_def) + "Create" +
248 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
249 "Vector(b_:flatbuffers_builder, v_:[" +
250 LobsterType(vector_type) + "]):\n b_.StartVector(" +
251 NumToString(elem_size) + ", v_.length, " +
252 NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
253 GenMethod(vector_type) +
254 "(e_)\n return b_.EndVector(v_.length)\n";
255 }
256 code += "\n";
257 }
258 }
259 }
260
261 void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
262 if (struct_def.generated) return;
263 std::string &code = *code_ptr;
264 CheckNameSpace(struct_def, &code);
265 code += "class " + NormalizedName(struct_def) + "\n\n";
266 }
267
268 // Generate struct or table methods.
269 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
270 if (struct_def.generated) return;
271 std::string &code = *code_ptr;
272 CheckNameSpace(struct_def, &code);
273 GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
274 code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
275 for (auto it = struct_def.fields.vec.begin();
276 it != struct_def.fields.vec.end(); ++it) {
277 auto &field = **it;
278 if (field.deprecated) continue;
279 GenStructAccessor(struct_def, field, code_ptr);
280 }
281 code += "\n";
282 if (!struct_def.fixed) {
283 // Generate a special accessor for the table that has been declared as
284 // the root type.
285 code += "def GetRootAs" + NormalizedName(struct_def) +
286 "(buf:string): return " + NormalizedName(struct_def) +
287 " { buf, buf.flatbuffers_indirect(0) }\n\n";
288 }
289 if (struct_def.fixed) {
290 // create a struct constructor function
291 GenStructBuilder(struct_def, code_ptr);
292 } else {
293 // Create a set of functions that allow table construction.
294 GenTableBuilders(struct_def, code_ptr);
295 }
296 }
297
298 // Generate enum declarations.
299 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
300 if (enum_def.generated) return;
301 std::string &code = *code_ptr;
302 CheckNameSpace(enum_def, &code);
303 GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
304 code += "enum " + NormalizedName(enum_def) + ":\n";
305 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
306 auto &ev = **it;
307 GenComment(ev.doc_comment, code_ptr, nullptr, " ");
308 code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
309 enum_def.ToString(ev) + "\n";
310 }
311 code += "\n";
312 }
313
314 // Recursively generate arguments for a constructor, to deal with nested
315 // structs.
316 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
317 std::string *code_ptr) {
318 for (auto it = struct_def.fields.vec.begin();
319 it != struct_def.fields.vec.end(); ++it) {
320 auto &field = **it;
321 if (IsStruct(field.value.type)) {
322 // Generate arguments for a struct inside a struct. To ensure names
323 // don't clash, and to make it obvious these arguments are constructing
324 // a nested struct, prefix the name with the field name.
325 StructBuilderArgs(*field.value.type.struct_def,
326 (nameprefix + (NormalizedName(field) + "_")).c_str(),
327 code_ptr);
328 } else {
329 std::string &code = *code_ptr;
330 code += ", " + (nameprefix + NormalizedName(field)) + ":" +
331 LobsterType(field.value.type);
332 }
333 }
334 }
335
336 // Recursively generate struct construction statements and instert manual
337 // padding.
338 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
339 std::string *code_ptr) {
340 std::string &code = *code_ptr;
341 code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
342 NumToString(struct_def.bytesize) + ")\n";
343 for (auto it = struct_def.fields.vec.rbegin();
344 it != struct_def.fields.vec.rend(); ++it) {
345 auto &field = **it;
346 if (field.padding)
347 code += " b_.Pad(" + NumToString(field.padding) + ")\n";
348 if (IsStruct(field.value.type)) {
349 StructBuilderBody(*field.value.type.struct_def,
350 (nameprefix + (NormalizedName(field) + "_")).c_str(),
351 code_ptr);
352 } else {
353 code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
354 nameprefix + NormalizedName(field) + ")\n";
355 }
356 }
357 }
358
359 // Create a struct with a builder and the struct's arguments.
360 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
361 std::string &code = *code_ptr;
362 code +=
363 "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
364 StructBuilderArgs(struct_def, "", code_ptr);
365 code += "):\n";
366 StructBuilderBody(struct_def, "", code_ptr);
367 code += " return b_.Offset()\n\n";
368 }
369
370 void CheckNameSpace(const Definition &def, std::string *code_ptr) {
371 auto ns = GetNameSpace(def);
372 if (ns == current_namespace_) return;
373 current_namespace_ = ns;
374 std::string &code = *code_ptr;
375 code += "namespace " + ns + "\n\n";
376 }
377
378 bool generate() {
379 std::string code;
380 code += std::string("// ") + FlatBuffersGeneratedWarning() +
381 "\nimport flatbuffers\n\n";
382 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
383 ++it) {
384 auto &enum_def = **it;
385 GenEnum(enum_def, &code);
386 }
387 for (auto it = parser_.structs_.vec.begin();
388 it != parser_.structs_.vec.end(); ++it) {
389 auto &struct_def = **it;
390 GenStructPreDecl(struct_def, &code);
391 }
392 for (auto it = parser_.structs_.vec.begin();
393 it != parser_.structs_.vec.end(); ++it) {
394 auto &struct_def = **it;
395 GenStruct(struct_def, &code);
396 }
397 return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
398 code, false);
399 }
400
401 private:
402 std::unordered_set<std::string> keywords_;
403 std::string current_namespace_;
404};
405
406} // namespace lobster
407
408static bool GenerateLobster(const Parser &parser, const std::string &path,
409 const std::string &file_name) {
410 lobster::LobsterGenerator generator(parser, path, file_name);
411 return generator.generate();
412}
413
414namespace {
415
416class LobsterCodeGenerator : public CodeGenerator {
417 public:
418 Status GenerateCode(const Parser &parser, const std::string &path,
419 const std::string &filename) override {
420 if (!GenerateLobster(parser, path, filename)) { return Status::ERROR; }
421 return Status::OK;
422 }
423
424 Status GenerateCode(const uint8_t *, int64_t,
425 const CodeGenOptions &) override {
426 return Status::NOT_IMPLEMENTED;
427 }
428
429 Status GenerateMakeRule(const Parser &parser, const std::string &path,
430 const std::string &filename,
431 std::string &output) override {
432 (void)parser;
433 (void)path;
434 (void)filename;
435 (void)output;
436 return Status::NOT_IMPLEMENTED;
437 }
438
439 Status GenerateGrpcCode(const Parser &parser, const std::string &path,
440 const std::string &filename) override {
441 (void)parser;
442 (void)path;
443 (void)filename;
444 return Status::NOT_IMPLEMENTED;
445 }
446
447 Status GenerateRootFile(const Parser &parser,
448 const std::string &path) override {
449 (void)parser;
450 (void)path;
451 return Status::NOT_IMPLEMENTED;
452 }
453
454 bool IsSchemaOnly() const override { return true; }
455
456 bool SupportsBfbsGeneration() const override { return false; }
457
458 bool SupportsRootFileGeneration() const override { return false; }
459
460 IDLOptions::Language Language() const override {
461 return IDLOptions::kLobster;
462 }
463
464 std::string LanguageName() const override { return "Lobster"; }
465};
466} // namespace
467
468std::unique_ptr<CodeGenerator> NewLobsterCodeGenerator() {
469 return std::unique_ptr<LobsterCodeGenerator>(new LobsterCodeGenerator());
470}
471
472} // namespace flatbuffers
View as plain text