blob: 67830f3bb321a08556a95f0967cba7ee0a1a68ff [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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 <string>
18#include <unordered_set>
19
20#include "flatbuffers/code_generators.h"
21#include "flatbuffers/flatbuffers.h"
22#include "flatbuffers/idl.h"
23#include "flatbuffers/util.h"
24
25namespace flatbuffers {
26namespace lobster {
27
28class LobsterGenerator : public BaseGenerator {
29 public:
Austin Schuh272c6132020-11-14 16:37:52 -080030 LobsterGenerator(const Parser &parser, const std::string &path,
31 const std::string &file_name)
32 : BaseGenerator(parser, path, file_name, "" /* not used */, "_",
33 "lobster") {
34 static const char *const keywords[] = {
35 "nil", "true", "false", "return", "struct", "class",
36 "import", "int", "float", "string", "any", "def",
37 "is", "from", "program", "private", "coroutine", "resource",
38 "enum", "typeof", "var", "let", "pakfile", "switch",
39 "case", "default", "namespace", "not", "and", "or",
40 "bool",
Austin Schuhe89fa2d2019-08-14 20:24:23 -070041 };
42 keywords_.insert(std::begin(keywords), std::end(keywords));
43 }
44
45 std::string EscapeKeyword(const std::string &name) const {
46 return keywords_.find(name) == keywords_.end() ? name : name + "_";
47 }
48
49 std::string NormalizedName(const Definition &definition) const {
50 return EscapeKeyword(definition.name);
51 }
52
53 std::string NormalizedName(const EnumVal &ev) const {
54 return EscapeKeyword(ev.name);
55 }
56
57 std::string NamespacedName(const Definition &def) {
58 return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
59 }
60
61 std::string GenTypeName(const Type &type) {
62 auto bits = NumToString(SizeOf(type.base_type) * 8);
James Kuszmaul8e62b022022-03-22 09:33:25 -070063 if (IsInteger(type.base_type)) {
64 if (IsUnsigned(type.base_type)) return "uint" + bits;
65 else return "int" + bits;
66 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -070067 if (IsFloat(type.base_type)) return "float" + bits;
Austin Schuh272c6132020-11-14 16:37:52 -080068 if (IsString(type)) return "string";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070069 if (type.base_type == BASE_TYPE_STRUCT) return "table";
70 return "none";
71 }
72
73 std::string LobsterType(const Type &type) {
74 if (IsFloat(type.base_type)) return "float";
Austin Schuh2dd86a92022-09-14 21:19:23 -070075 if (IsBool(type.base_type)) return "bool";
Austin Schuh272c6132020-11-14 16:37:52 -080076 if (IsScalar(type.base_type) && type.enum_def)
77 return NormalizedName(*type.enum_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -070078 if (!IsScalar(type.base_type)) return "flatbuffers_offset";
Austin Schuh2dd86a92022-09-14 21:19:23 -070079 if (IsString(type)) return "string";
Austin Schuhe89fa2d2019-08-14 20:24:23 -070080 return "int";
81 }
82
83 // Returns the method name for use with add/put calls.
84 std::string GenMethod(const Type &type) {
85 return IsScalar(type.base_type)
James Kuszmaul8e62b022022-03-22 09:33:25 -070086 ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
Austin Schuh272c6132020-11-14 16:37:52 -080087 : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
Austin Schuhe89fa2d2019-08-14 20:24:23 -070088 }
89
90 // This uses Python names for now..
91 std::string GenTypeBasic(const Type &type) {
Austin Schuh272c6132020-11-14 16:37:52 -080092 // clang-format off
Austin Schuhe89fa2d2019-08-14 20:24:23 -070093 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070094 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -080095 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 #PTYPE,
Austin Schuh272c6132020-11-14 16:37:52 -080097 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -070098 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -070099 };
Austin Schuh272c6132020-11-14 16:37:52 -0800100 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700101 return ctypename[type.base_type];
102 }
103
104 // Generate a struct field, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800105 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
106 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700107 GenComment(field.doc_comment, code_ptr, nullptr, " ");
108 std::string &code = *code_ptr;
109 auto offsets = NumToString(field.value.offset);
110 auto def = " def " + NormalizedName(field);
111 if (IsScalar(field.value.type.base_type)) {
112 std::string acc;
113 if (struct_def.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -0800114 acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
115 offsets + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700116
117 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700118 auto defval = field.IsOptional() ? "0" : field.value.constant;
Austin Schuh272c6132020-11-14 16:37:52 -0800119 acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
120 "(pos_, " + offsets + ", " + defval + ")";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700121 if (IsBool(field.value.type.base_type))
122 acc = "bool(" + acc + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700123 }
124 if (field.value.type.enum_def)
125 acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700126 if (field.IsOptional()) {
Austin Schuh272c6132020-11-14 16:37:52 -0800127 acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700128 code += def + "() -> " + LobsterType(field.value.type) + ", bool:\n return " + acc + "\n";
129 } else {
130 code += def + "() -> " + LobsterType(field.value.type) + ":\n return " + acc + "\n";
131 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700132 return;
133 }
134 switch (field.value.type.base_type) {
135 case BASE_TYPE_STRUCT: {
136 auto name = NamespacedName(*field.value.type.struct_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700137 if (struct_def.fixed) {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700138 code += def + "() -> " + name + ":\n ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700139 code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
140 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700141 code += def + "() -> " + name + "?:\n ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700142 code += std::string("let o = buf_.flatbuffers_field_") +
143 (field.value.type.struct_def->fixed ? "struct" : "table") +
144 "(pos_, " + offsets + ")\n return if o: " + name +
145 " { buf_, o } else: nil\n";
146 }
147 break;
148 }
149 case BASE_TYPE_STRING:
Austin Schuh272c6132020-11-14 16:37:52 -0800150 code += def +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700151 "() -> string:\n return buf_.flatbuffers_field_string(pos_, " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700152 offsets + ")\n";
153 break;
154 case BASE_TYPE_VECTOR: {
155 auto vectortype = field.value.type.VectorType();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700156 if (vectortype.base_type == BASE_TYPE_STRUCT) {
157 auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
158 ") + i * " + NumToString(InlineSize(vectortype));
159 if (!(vectortype.struct_def->fixed)) {
160 start = "buf_.flatbuffers_indirect(" + start + ")";
161 }
Austin Schuh2dd86a92022-09-14 21:19:23 -0700162 code += def + "(i:int) -> " + NamespacedName(*field.value.type.struct_def) + ":\n return ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700163 code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
164 start + " }\n";
165 } else {
Austin Schuh2dd86a92022-09-14 21:19:23 -0700166 if (IsString(vectortype)) {
167 code += def + "(i:int) -> string:\n return ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700168 code += "buf_.flatbuffers_string";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700169 } else {
170 code += def + "(i:int) -> " + LobsterType(vectortype) + ":\n return ";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700171 code += "buf_.read_" + GenTypeName(vectortype) + "_le";
Austin Schuh2dd86a92022-09-14 21:19:23 -0700172 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700173 code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
174 ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
175 }
176 break;
177 }
178 case BASE_TYPE_UNION: {
179 for (auto it = field.value.type.enum_def->Vals().begin();
180 it != field.value.type.enum_def->Vals().end(); ++it) {
181 auto &ev = **it;
182 if (ev.IsNonZero()) {
183 code += def + "_as_" + ev.name + "():\n return " +
184 NamespacedName(*ev.union_type.struct_def) +
185 " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
186 ") }\n";
187 }
188 }
189 break;
190 }
191 default: FLATBUFFERS_ASSERT(0);
192 }
Austin Schuh272c6132020-11-14 16:37:52 -0800193 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700194 code += def +
Austin Schuh2dd86a92022-09-14 21:19:23 -0700195 "_length() -> int:\n return "
Austin Schuh272c6132020-11-14 16:37:52 -0800196 "buf_.flatbuffers_field_vector_len(pos_, " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700197 offsets + ")\n";
198 }
199 }
200
201 // Generate table constructors, conditioned on its members' types.
Austin Schuh272c6132020-11-14 16:37:52 -0800202 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700203 std::string &code = *code_ptr;
204 code += "struct " + NormalizedName(struct_def) +
205 "Builder:\n b_:flatbuffers_builder\n";
206 code += " def start():\n b_.StartObject(" +
Austin Schuh272c6132020-11-14 16:37:52 -0800207 NumToString(struct_def.fields.vec.size()) +
208 ")\n return this\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700209 for (auto it = struct_def.fields.vec.begin();
210 it != struct_def.fields.vec.end(); ++it) {
211 auto &field = **it;
212 if (field.deprecated) continue;
213 auto offset = it - struct_def.fields.vec.begin();
214 code += " def add_" + NormalizedName(field) + "(" +
215 NormalizedName(field) + ":" + LobsterType(field.value.type) +
216 "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
217 NumToString(offset) + ", " + NormalizedName(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700218 if (IsScalar(field.value.type.base_type) && !field.IsOptional())
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700219 code += ", " + field.value.constant;
220 code += ")\n return this\n";
221 }
222 code += " def end():\n return b_.EndObject()\n\n";
223 for (auto it = struct_def.fields.vec.begin();
224 it != struct_def.fields.vec.end(); ++it) {
225 auto &field = **it;
226 if (field.deprecated) continue;
Austin Schuh272c6132020-11-14 16:37:52 -0800227 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700228 code += "def " + NormalizedName(struct_def) + "Start" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700229 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700230 "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
231 auto vector_type = field.value.type.VectorType();
232 auto alignment = InlineAlignment(vector_type);
233 auto elem_size = InlineSize(vector_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800234 code +=
235 NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700236 if (vector_type.base_type != BASE_TYPE_STRUCT ||
237 !vector_type.struct_def->fixed) {
238 code += "def " + NormalizedName(struct_def) + "Create" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700239 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700240 "Vector(b_:flatbuffers_builder, v_:[" +
241 LobsterType(vector_type) + "]):\n b_.StartVector(" +
242 NumToString(elem_size) + ", v_.length, " +
Austin Schuh272c6132020-11-14 16:37:52 -0800243 NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700244 GenMethod(vector_type) +
245 "(e_)\n return b_.EndVector(v_.length)\n";
246 }
247 code += "\n";
248 }
249 }
250 }
251
252 void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
253 if (struct_def.generated) return;
254 std::string &code = *code_ptr;
255 CheckNameSpace(struct_def, &code);
256 code += "class " + NormalizedName(struct_def) + "\n\n";
257 }
258
259 // Generate struct or table methods.
260 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
261 if (struct_def.generated) return;
262 std::string &code = *code_ptr;
263 CheckNameSpace(struct_def, &code);
264 GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
265 code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
266 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800267 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700268 auto &field = **it;
269 if (field.deprecated) continue;
270 GenStructAccessor(struct_def, field, code_ptr);
271 }
272 code += "\n";
273 if (!struct_def.fixed) {
274 // Generate a special accessor for the table that has been declared as
275 // the root type.
Austin Schuh272c6132020-11-14 16:37:52 -0800276 code += "def GetRootAs" + NormalizedName(struct_def) +
277 "(buf:string): return " + NormalizedName(struct_def) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700278 " { buf, buf.flatbuffers_indirect(0) }\n\n";
279 }
280 if (struct_def.fixed) {
281 // create a struct constructor function
282 GenStructBuilder(struct_def, code_ptr);
283 } else {
284 // Create a set of functions that allow table construction.
285 GenTableBuilders(struct_def, code_ptr);
286 }
287 }
288
289 // Generate enum declarations.
290 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
291 if (enum_def.generated) return;
292 std::string &code = *code_ptr;
293 CheckNameSpace(enum_def, &code);
294 GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
295 code += "enum " + NormalizedName(enum_def) + ":\n";
296 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
297 auto &ev = **it;
298 GenComment(ev.doc_comment, code_ptr, nullptr, " ");
299 code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
300 enum_def.ToString(ev) + "\n";
301 }
302 code += "\n";
303 }
304
305 // Recursively generate arguments for a constructor, to deal with nested
306 // structs.
Austin Schuh272c6132020-11-14 16:37:52 -0800307 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
308 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700309 for (auto it = struct_def.fields.vec.begin();
310 it != struct_def.fields.vec.end(); ++it) {
311 auto &field = **it;
312 if (IsStruct(field.value.type)) {
313 // Generate arguments for a struct inside a struct. To ensure names
314 // don't clash, and to make it obvious these arguments are constructing
315 // a nested struct, prefix the name with the field name.
316 StructBuilderArgs(*field.value.type.struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800317 (nameprefix + (NormalizedName(field) + "_")).c_str(),
318 code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700319 } else {
320 std::string &code = *code_ptr;
321 code += ", " + (nameprefix + NormalizedName(field)) + ":" +
322 LobsterType(field.value.type);
323 }
324 }
325 }
326
327 // Recursively generate struct construction statements and instert manual
328 // padding.
Austin Schuh272c6132020-11-14 16:37:52 -0800329 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
330 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700331 std::string &code = *code_ptr;
332 code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
333 NumToString(struct_def.bytesize) + ")\n";
334 for (auto it = struct_def.fields.vec.rbegin();
335 it != struct_def.fields.vec.rend(); ++it) {
336 auto &field = **it;
337 if (field.padding)
338 code += " b_.Pad(" + NumToString(field.padding) + ")\n";
339 if (IsStruct(field.value.type)) {
340 StructBuilderBody(*field.value.type.struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800341 (nameprefix + (NormalizedName(field) + "_")).c_str(),
342 code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700343 } else {
344 code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
345 nameprefix + NormalizedName(field) + ")\n";
346 }
347 }
348 }
349
350 // Create a struct with a builder and the struct's arguments.
Austin Schuh272c6132020-11-14 16:37:52 -0800351 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700352 std::string &code = *code_ptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800353 code +=
354 "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700355 StructBuilderArgs(struct_def, "", code_ptr);
356 code += "):\n";
357 StructBuilderBody(struct_def, "", code_ptr);
358 code += " return b_.Offset()\n\n";
359 }
360
361 void CheckNameSpace(const Definition &def, std::string *code_ptr) {
362 auto ns = GetNameSpace(def);
363 if (ns == current_namespace_) return;
364 current_namespace_ = ns;
365 std::string &code = *code_ptr;
366 code += "namespace " + ns + "\n\n";
367 }
368
369 bool generate() {
370 std::string code;
371 code += std::string("// ") + FlatBuffersGeneratedWarning() +
372 "\nimport flatbuffers\n\n";
373 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
374 ++it) {
375 auto &enum_def = **it;
376 GenEnum(enum_def, &code);
377 }
378 for (auto it = parser_.structs_.vec.begin();
379 it != parser_.structs_.vec.end(); ++it) {
380 auto &struct_def = **it;
381 GenStructPreDecl(struct_def, &code);
382 }
383 for (auto it = parser_.structs_.vec.begin();
384 it != parser_.structs_.vec.end(); ++it) {
385 auto &struct_def = **it;
386 GenStruct(struct_def, &code);
387 }
Austin Schuh272c6132020-11-14 16:37:52 -0800388 return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700389 code, false);
390 }
391
392 private:
393 std::unordered_set<std::string> keywords_;
394 std::string current_namespace_;
395};
396
397} // namespace lobster
398
399bool GenerateLobster(const Parser &parser, const std::string &path,
Austin Schuh272c6132020-11-14 16:37:52 -0800400 const std::string &file_name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700401 lobster::LobsterGenerator generator(parser, path, file_name);
402 return generator.generate();
403}
404
405} // namespace flatbuffers