blob: c1e78adfee1c9ccb522261ba0521f39ad2234492 [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 Schuh272c6132020-11-14 16:37:52 -080075 if (IsScalar(type.base_type) && type.enum_def)
76 return NormalizedName(*type.enum_def);
Austin Schuhe89fa2d2019-08-14 20:24:23 -070077 if (!IsScalar(type.base_type)) return "flatbuffers_offset";
78 return "int";
79 }
80
81 // Returns the method name for use with add/put calls.
82 std::string GenMethod(const Type &type) {
83 return IsScalar(type.base_type)
James Kuszmaul8e62b022022-03-22 09:33:25 -070084 ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
Austin Schuh272c6132020-11-14 16:37:52 -080085 : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
Austin Schuhe89fa2d2019-08-14 20:24:23 -070086 }
87
88 // This uses Python names for now..
89 std::string GenTypeBasic(const Type &type) {
Austin Schuh272c6132020-11-14 16:37:52 -080090 // clang-format off
Austin Schuhe89fa2d2019-08-14 20:24:23 -070091 static const char *ctypename[] = {
Austin Schuhe89fa2d2019-08-14 20:24:23 -070092 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
Austin Schuh272c6132020-11-14 16:37:52 -080093 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
Austin Schuhe89fa2d2019-08-14 20:24:23 -070094 #PTYPE,
Austin Schuh272c6132020-11-14 16:37:52 -080095 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 #undef FLATBUFFERS_TD
Austin Schuhe89fa2d2019-08-14 20:24:23 -070097 };
Austin Schuh272c6132020-11-14 16:37:52 -080098 // clang-format on
Austin Schuhe89fa2d2019-08-14 20:24:23 -070099 return ctypename[type.base_type];
100 }
101
102 // Generate a struct field, conditioned on its child type(s).
Austin Schuh272c6132020-11-14 16:37:52 -0800103 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
104 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700105 GenComment(field.doc_comment, code_ptr, nullptr, " ");
106 std::string &code = *code_ptr;
107 auto offsets = NumToString(field.value.offset);
108 auto def = " def " + NormalizedName(field);
109 if (IsScalar(field.value.type.base_type)) {
110 std::string acc;
111 if (struct_def.fixed) {
Austin Schuh272c6132020-11-14 16:37:52 -0800112 acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
113 offsets + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700114
115 } else {
James Kuszmaul8e62b022022-03-22 09:33:25 -0700116 auto defval = field.IsOptional() ? "0" : field.value.constant;
Austin Schuh272c6132020-11-14 16:37:52 -0800117 acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
118 "(pos_, " + offsets + ", " + defval + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700119 }
120 if (field.value.type.enum_def)
121 acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
James Kuszmaul8e62b022022-03-22 09:33:25 -0700122 if (field.IsOptional())
Austin Schuh272c6132020-11-14 16:37:52 -0800123 acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700124 code += def + "():\n return " + acc + "\n";
125 return;
126 }
127 switch (field.value.type.base_type) {
128 case BASE_TYPE_STRUCT: {
129 auto name = NamespacedName(*field.value.type.struct_def);
130 code += def + "():\n ";
131 if (struct_def.fixed) {
132 code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
133 } else {
134 code += std::string("let o = buf_.flatbuffers_field_") +
135 (field.value.type.struct_def->fixed ? "struct" : "table") +
136 "(pos_, " + offsets + ")\n return if o: " + name +
137 " { buf_, o } else: nil\n";
138 }
139 break;
140 }
141 case BASE_TYPE_STRING:
Austin Schuh272c6132020-11-14 16:37:52 -0800142 code += def +
143 "():\n return buf_.flatbuffers_field_string(pos_, " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700144 offsets + ")\n";
145 break;
146 case BASE_TYPE_VECTOR: {
147 auto vectortype = field.value.type.VectorType();
148 code += def + "(i:int):\n return ";
149 if (vectortype.base_type == BASE_TYPE_STRUCT) {
150 auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
151 ") + i * " + NumToString(InlineSize(vectortype));
152 if (!(vectortype.struct_def->fixed)) {
153 start = "buf_.flatbuffers_indirect(" + start + ")";
154 }
155 code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
156 start + " }\n";
157 } else {
Austin Schuh272c6132020-11-14 16:37:52 -0800158 if (IsString(vectortype))
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700159 code += "buf_.flatbuffers_string";
160 else
161 code += "buf_.read_" + GenTypeName(vectortype) + "_le";
162 code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
163 ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
164 }
165 break;
166 }
167 case BASE_TYPE_UNION: {
168 for (auto it = field.value.type.enum_def->Vals().begin();
169 it != field.value.type.enum_def->Vals().end(); ++it) {
170 auto &ev = **it;
171 if (ev.IsNonZero()) {
172 code += def + "_as_" + ev.name + "():\n return " +
173 NamespacedName(*ev.union_type.struct_def) +
174 " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
175 ") }\n";
176 }
177 }
178 break;
179 }
180 default: FLATBUFFERS_ASSERT(0);
181 }
Austin Schuh272c6132020-11-14 16:37:52 -0800182 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700183 code += def +
Austin Schuh272c6132020-11-14 16:37:52 -0800184 "_length():\n return "
185 "buf_.flatbuffers_field_vector_len(pos_, " +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700186 offsets + ")\n";
187 }
188 }
189
190 // Generate table constructors, conditioned on its members' types.
Austin Schuh272c6132020-11-14 16:37:52 -0800191 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700192 std::string &code = *code_ptr;
193 code += "struct " + NormalizedName(struct_def) +
194 "Builder:\n b_:flatbuffers_builder\n";
195 code += " def start():\n b_.StartObject(" +
Austin Schuh272c6132020-11-14 16:37:52 -0800196 NumToString(struct_def.fields.vec.size()) +
197 ")\n return this\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700198 for (auto it = struct_def.fields.vec.begin();
199 it != struct_def.fields.vec.end(); ++it) {
200 auto &field = **it;
201 if (field.deprecated) continue;
202 auto offset = it - struct_def.fields.vec.begin();
203 code += " def add_" + NormalizedName(field) + "(" +
204 NormalizedName(field) + ":" + LobsterType(field.value.type) +
205 "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
206 NumToString(offset) + ", " + NormalizedName(field);
James Kuszmaul8e62b022022-03-22 09:33:25 -0700207 if (IsScalar(field.value.type.base_type) && !field.IsOptional())
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700208 code += ", " + field.value.constant;
209 code += ")\n return this\n";
210 }
211 code += " def end():\n return b_.EndObject()\n\n";
212 for (auto it = struct_def.fields.vec.begin();
213 it != struct_def.fields.vec.end(); ++it) {
214 auto &field = **it;
215 if (field.deprecated) continue;
Austin Schuh272c6132020-11-14 16:37:52 -0800216 if (IsVector(field.value.type)) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700217 code += "def " + NormalizedName(struct_def) + "Start" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700218 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700219 "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
220 auto vector_type = field.value.type.VectorType();
221 auto alignment = InlineAlignment(vector_type);
222 auto elem_size = InlineSize(vector_type);
Austin Schuh272c6132020-11-14 16:37:52 -0800223 code +=
224 NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700225 if (vector_type.base_type != BASE_TYPE_STRUCT ||
226 !vector_type.struct_def->fixed) {
227 code += "def " + NormalizedName(struct_def) + "Create" +
James Kuszmaul8e62b022022-03-22 09:33:25 -0700228 ConvertCase(NormalizedName(field), Case::kUpperCamel) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700229 "Vector(b_:flatbuffers_builder, v_:[" +
230 LobsterType(vector_type) + "]):\n b_.StartVector(" +
231 NumToString(elem_size) + ", v_.length, " +
Austin Schuh272c6132020-11-14 16:37:52 -0800232 NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700233 GenMethod(vector_type) +
234 "(e_)\n return b_.EndVector(v_.length)\n";
235 }
236 code += "\n";
237 }
238 }
239 }
240
241 void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
242 if (struct_def.generated) return;
243 std::string &code = *code_ptr;
244 CheckNameSpace(struct_def, &code);
245 code += "class " + NormalizedName(struct_def) + "\n\n";
246 }
247
248 // Generate struct or table methods.
249 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
250 if (struct_def.generated) return;
251 std::string &code = *code_ptr;
252 CheckNameSpace(struct_def, &code);
253 GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
254 code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
255 for (auto it = struct_def.fields.vec.begin();
Austin Schuh272c6132020-11-14 16:37:52 -0800256 it != struct_def.fields.vec.end(); ++it) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700257 auto &field = **it;
258 if (field.deprecated) continue;
259 GenStructAccessor(struct_def, field, code_ptr);
260 }
261 code += "\n";
262 if (!struct_def.fixed) {
263 // Generate a special accessor for the table that has been declared as
264 // the root type.
Austin Schuh272c6132020-11-14 16:37:52 -0800265 code += "def GetRootAs" + NormalizedName(struct_def) +
266 "(buf:string): return " + NormalizedName(struct_def) +
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700267 " { buf, buf.flatbuffers_indirect(0) }\n\n";
268 }
269 if (struct_def.fixed) {
270 // create a struct constructor function
271 GenStructBuilder(struct_def, code_ptr);
272 } else {
273 // Create a set of functions that allow table construction.
274 GenTableBuilders(struct_def, code_ptr);
275 }
276 }
277
278 // Generate enum declarations.
279 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
280 if (enum_def.generated) return;
281 std::string &code = *code_ptr;
282 CheckNameSpace(enum_def, &code);
283 GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
284 code += "enum " + NormalizedName(enum_def) + ":\n";
285 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
286 auto &ev = **it;
287 GenComment(ev.doc_comment, code_ptr, nullptr, " ");
288 code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
289 enum_def.ToString(ev) + "\n";
290 }
291 code += "\n";
292 }
293
294 // Recursively generate arguments for a constructor, to deal with nested
295 // structs.
Austin Schuh272c6132020-11-14 16:37:52 -0800296 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
297 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700298 for (auto it = struct_def.fields.vec.begin();
299 it != struct_def.fields.vec.end(); ++it) {
300 auto &field = **it;
301 if (IsStruct(field.value.type)) {
302 // Generate arguments for a struct inside a struct. To ensure names
303 // don't clash, and to make it obvious these arguments are constructing
304 // a nested struct, prefix the name with the field name.
305 StructBuilderArgs(*field.value.type.struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800306 (nameprefix + (NormalizedName(field) + "_")).c_str(),
307 code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700308 } else {
309 std::string &code = *code_ptr;
310 code += ", " + (nameprefix + NormalizedName(field)) + ":" +
311 LobsterType(field.value.type);
312 }
313 }
314 }
315
316 // Recursively generate struct construction statements and instert manual
317 // padding.
Austin Schuh272c6132020-11-14 16:37:52 -0800318 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
319 std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700320 std::string &code = *code_ptr;
321 code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
322 NumToString(struct_def.bytesize) + ")\n";
323 for (auto it = struct_def.fields.vec.rbegin();
324 it != struct_def.fields.vec.rend(); ++it) {
325 auto &field = **it;
326 if (field.padding)
327 code += " b_.Pad(" + NumToString(field.padding) + ")\n";
328 if (IsStruct(field.value.type)) {
329 StructBuilderBody(*field.value.type.struct_def,
Austin Schuh272c6132020-11-14 16:37:52 -0800330 (nameprefix + (NormalizedName(field) + "_")).c_str(),
331 code_ptr);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700332 } else {
333 code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
334 nameprefix + NormalizedName(field) + ")\n";
335 }
336 }
337 }
338
339 // Create a struct with a builder and the struct's arguments.
Austin Schuh272c6132020-11-14 16:37:52 -0800340 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700341 std::string &code = *code_ptr;
Austin Schuh272c6132020-11-14 16:37:52 -0800342 code +=
343 "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700344 StructBuilderArgs(struct_def, "", code_ptr);
345 code += "):\n";
346 StructBuilderBody(struct_def, "", code_ptr);
347 code += " return b_.Offset()\n\n";
348 }
349
350 void CheckNameSpace(const Definition &def, std::string *code_ptr) {
351 auto ns = GetNameSpace(def);
352 if (ns == current_namespace_) return;
353 current_namespace_ = ns;
354 std::string &code = *code_ptr;
355 code += "namespace " + ns + "\n\n";
356 }
357
358 bool generate() {
359 std::string code;
360 code += std::string("// ") + FlatBuffersGeneratedWarning() +
361 "\nimport flatbuffers\n\n";
362 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
363 ++it) {
364 auto &enum_def = **it;
365 GenEnum(enum_def, &code);
366 }
367 for (auto it = parser_.structs_.vec.begin();
368 it != parser_.structs_.vec.end(); ++it) {
369 auto &struct_def = **it;
370 GenStructPreDecl(struct_def, &code);
371 }
372 for (auto it = parser_.structs_.vec.begin();
373 it != parser_.structs_.vec.end(); ++it) {
374 auto &struct_def = **it;
375 GenStruct(struct_def, &code);
376 }
Austin Schuh272c6132020-11-14 16:37:52 -0800377 return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(),
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700378 code, false);
379 }
380
381 private:
382 std::unordered_set<std::string> keywords_;
383 std::string current_namespace_;
384};
385
386} // namespace lobster
387
388bool GenerateLobster(const Parser &parser, const std::string &path,
Austin Schuh272c6132020-11-14 16:37:52 -0800389 const std::string &file_name) {
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700390 lobster::LobsterGenerator generator(parser, path, file_name);
391 return generator.generate();
392}
393
394} // namespace flatbuffers