2 * Copyright 2018 Google Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <unordered_set>
20 #include "flatbuffers/code_generators.h"
21 #include "flatbuffers/flatbuffers.h"
22 #include "flatbuffers/idl.h"
23 #include "flatbuffers/util.h"
25 namespace flatbuffers {
28 class LobsterGenerator : public BaseGenerator {
30 LobsterGenerator(const Parser &parser, const std::string &path,
31 const std::string &file_name)
32 : BaseGenerator(parser, path, file_name, "" /* not used */, "_") {
33 static const char *const keywords[] = {
34 "nil", "true", "false", "return", "struct", "class",
35 "import", "int", "float", "string", "any", "def",
36 "is", "from", "program", "private", "coroutine", "resource",
37 "enum", "typeof", "var", "let", "pakfile", "switch",
38 "case", "default", "namespace", "not", "and", "or",
41 keywords_.insert(std::begin(keywords), std::end(keywords));
44 std::string EscapeKeyword(const std::string &name) const {
45 return keywords_.find(name) == keywords_.end() ? name : name + "_";
48 std::string NormalizedName(const Definition &definition) const {
49 return EscapeKeyword(definition.name);
52 std::string NormalizedName(const EnumVal &ev) const {
53 return EscapeKeyword(ev.name);
56 std::string NamespacedName(const Definition &def) {
57 return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
60 std::string GenTypeName(const Type &type) {
61 auto bits = NumToString(SizeOf(type.base_type) * 8);
62 if (IsInteger(type.base_type)) return "int" + bits;
63 if (IsFloat(type.base_type)) return "float" + bits;
64 if (type.base_type == BASE_TYPE_STRING) return "string";
65 if (type.base_type == BASE_TYPE_STRUCT) return "table";
69 std::string LobsterType(const Type &type) {
70 if (IsFloat(type.base_type)) return "float";
71 if (IsScalar(type.base_type) && type.enum_def)
72 return NormalizedName(*type.enum_def);
73 if (!IsScalar(type.base_type)) return "flatbuffers_offset";
77 // Returns the method name for use with add/put calls.
78 std::string GenMethod(const Type &type) {
79 return IsScalar(type.base_type)
80 ? MakeCamel(GenTypeBasic(type))
81 : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
84 // This uses Python names for now..
85 std::string GenTypeBasic(const Type &type) {
86 static const char *ctypename[] = {
88 #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
89 CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
91 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
95 return ctypename[type.base_type];
98 // Generate a struct field, conditioned on its child type(s).
99 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
100 std::string *code_ptr) {
101 GenComment(field.doc_comment, code_ptr, nullptr, " ");
102 std::string &code = *code_ptr;
103 auto offsets = NumToString(field.value.offset);
104 auto def = " def " + NormalizedName(field);
105 if (IsScalar(field.value.type.base_type)) {
107 if (struct_def.fixed) {
108 acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " +
112 acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) +
113 "(pos_, " + offsets + ", " + field.value.constant + ")";
115 if (field.value.type.enum_def)
116 acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
117 code += def + "():\n return " + acc + "\n";
120 switch (field.value.type.base_type) {
121 case BASE_TYPE_STRUCT: {
122 auto name = NamespacedName(*field.value.type.struct_def);
123 code += def + "():\n ";
124 if (struct_def.fixed) {
125 code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
127 code += std::string("let o = buf_.flatbuffers_field_") +
128 (field.value.type.struct_def->fixed ? "struct" : "table") +
129 "(pos_, " + offsets + ")\n return if o: " + name +
130 " { buf_, o } else: nil\n";
134 case BASE_TYPE_STRING:
136 "():\n return buf_.flatbuffers_field_string(pos_, " +
139 case BASE_TYPE_VECTOR: {
140 auto vectortype = field.value.type.VectorType();
141 code += def + "(i:int):\n return ";
142 if (vectortype.base_type == BASE_TYPE_STRUCT) {
143 auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
144 ") + i * " + NumToString(InlineSize(vectortype));
145 if (!(vectortype.struct_def->fixed)) {
146 start = "buf_.flatbuffers_indirect(" + start + ")";
148 code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
151 if (vectortype.base_type == BASE_TYPE_STRING)
152 code += "buf_.flatbuffers_string";
154 code += "buf_.read_" + GenTypeName(vectortype) + "_le";
155 code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
156 ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
160 case BASE_TYPE_UNION: {
161 for (auto it = field.value.type.enum_def->Vals().begin();
162 it != field.value.type.enum_def->Vals().end(); ++it) {
164 if (ev.IsNonZero()) {
165 code += def + "_as_" + ev.name + "():\n return " +
166 NamespacedName(*ev.union_type.struct_def) +
167 " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
173 default: FLATBUFFERS_ASSERT(0);
175 if (field.value.type.base_type == BASE_TYPE_VECTOR) {
177 "_length():\n return "
178 "buf_.flatbuffers_field_vector_len(pos_, " +
183 // Generate table constructors, conditioned on its members' types.
184 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
185 std::string &code = *code_ptr;
186 code += "struct " + NormalizedName(struct_def) +
187 "Builder:\n b_:flatbuffers_builder\n";
188 code += " def start():\n b_.StartObject(" +
189 NumToString(struct_def.fields.vec.size()) +
191 for (auto it = struct_def.fields.vec.begin();
192 it != struct_def.fields.vec.end(); ++it) {
194 if (field.deprecated) continue;
195 auto offset = it - struct_def.fields.vec.begin();
196 code += " def add_" + NormalizedName(field) + "(" +
197 NormalizedName(field) + ":" + LobsterType(field.value.type) +
198 "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
199 NumToString(offset) + ", " + NormalizedName(field);
200 if (IsScalar(field.value.type.base_type))
201 code += ", " + field.value.constant;
202 code += ")\n return this\n";
204 code += " def end():\n return b_.EndObject()\n\n";
205 for (auto it = struct_def.fields.vec.begin();
206 it != struct_def.fields.vec.end(); ++it) {
208 if (field.deprecated) continue;
209 if (field.value.type.base_type == BASE_TYPE_VECTOR) {
210 code += "def " + NormalizedName(struct_def) + "Start" +
211 MakeCamel(NormalizedName(field)) +
212 "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
213 auto vector_type = field.value.type.VectorType();
214 auto alignment = InlineAlignment(vector_type);
215 auto elem_size = InlineSize(vector_type);
217 NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n";
218 if (vector_type.base_type != BASE_TYPE_STRUCT ||
219 !vector_type.struct_def->fixed) {
220 code += "def " + NormalizedName(struct_def) + "Create" +
221 MakeCamel(NormalizedName(field)) +
222 "Vector(b_:flatbuffers_builder, v_:[" +
223 LobsterType(vector_type) + "]):\n b_.StartVector(" +
224 NumToString(elem_size) + ", v_.length, " +
225 NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" +
226 GenMethod(vector_type) +
227 "(e_)\n return b_.EndVector(v_.length)\n";
234 void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
235 if (struct_def.generated) return;
236 std::string &code = *code_ptr;
237 CheckNameSpace(struct_def, &code);
238 code += "class " + NormalizedName(struct_def) + "\n\n";
241 // Generate struct or table methods.
242 void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
243 if (struct_def.generated) return;
244 std::string &code = *code_ptr;
245 CheckNameSpace(struct_def, &code);
246 GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
247 code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
248 for (auto it = struct_def.fields.vec.begin();
249 it != struct_def.fields.vec.end(); ++it) {
251 if (field.deprecated) continue;
252 GenStructAccessor(struct_def, field, code_ptr);
255 if (!struct_def.fixed) {
256 // Generate a special accessor for the table that has been declared as
258 code += "def GetRootAs" + NormalizedName(struct_def) +
259 "(buf:string): return " + NormalizedName(struct_def) +
260 " { buf, buf.flatbuffers_indirect(0) }\n\n";
262 if (struct_def.fixed) {
263 // create a struct constructor function
264 GenStructBuilder(struct_def, code_ptr);
266 // Create a set of functions that allow table construction.
267 GenTableBuilders(struct_def, code_ptr);
271 // Generate enum declarations.
272 void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
273 if (enum_def.generated) return;
274 std::string &code = *code_ptr;
275 CheckNameSpace(enum_def, &code);
276 GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
277 code += "enum " + NormalizedName(enum_def) + ":\n";
278 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
280 GenComment(ev.doc_comment, code_ptr, nullptr, " ");
281 code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
282 enum_def.ToString(ev) + "\n";
287 // Recursively generate arguments for a constructor, to deal with nested
289 void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
290 std::string *code_ptr) {
291 for (auto it = struct_def.fields.vec.begin();
292 it != struct_def.fields.vec.end(); ++it) {
294 if (IsStruct(field.value.type)) {
295 // Generate arguments for a struct inside a struct. To ensure names
296 // don't clash, and to make it obvious these arguments are constructing
297 // a nested struct, prefix the name with the field name.
298 StructBuilderArgs(*field.value.type.struct_def,
299 (nameprefix + (NormalizedName(field) + "_")).c_str(),
302 std::string &code = *code_ptr;
303 code += ", " + (nameprefix + NormalizedName(field)) + ":" +
304 LobsterType(field.value.type);
309 // Recursively generate struct construction statements and instert manual
311 void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
312 std::string *code_ptr) {
313 std::string &code = *code_ptr;
314 code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
315 NumToString(struct_def.bytesize) + ")\n";
316 for (auto it = struct_def.fields.vec.rbegin();
317 it != struct_def.fields.vec.rend(); ++it) {
320 code += " b_.Pad(" + NumToString(field.padding) + ")\n";
321 if (IsStruct(field.value.type)) {
322 StructBuilderBody(*field.value.type.struct_def,
323 (nameprefix + (NormalizedName(field) + "_")).c_str(),
326 code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
327 nameprefix + NormalizedName(field) + ")\n";
332 // Create a struct with a builder and the struct's arguments.
333 void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
334 std::string &code = *code_ptr;
336 "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder";
337 StructBuilderArgs(struct_def, "", code_ptr);
339 StructBuilderBody(struct_def, "", code_ptr);
340 code += " return b_.Offset()\n\n";
343 void CheckNameSpace(const Definition &def, std::string *code_ptr) {
344 auto ns = GetNameSpace(def);
345 if (ns == current_namespace_) return;
346 current_namespace_ = ns;
347 std::string &code = *code_ptr;
348 code += "namespace " + ns + "\n\n";
353 code += std::string("// ") + FlatBuffersGeneratedWarning() +
354 "\nimport flatbuffers\n\n";
355 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
357 auto &enum_def = **it;
358 GenEnum(enum_def, &code);
360 for (auto it = parser_.structs_.vec.begin();
361 it != parser_.structs_.vec.end(); ++it) {
362 auto &struct_def = **it;
363 GenStructPreDecl(struct_def, &code);
365 for (auto it = parser_.structs_.vec.begin();
366 it != parser_.structs_.vec.end(); ++it) {
367 auto &struct_def = **it;
368 GenStruct(struct_def, &code);
370 return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(), code,
375 std::unordered_set<std::string> keywords_;
376 std::string current_namespace_;
379 } // namespace lobster
381 bool GenerateLobster(const Parser &parser, const std::string &path,
382 const std::string &file_name) {
383 lobster::LobsterGenerator generator(parser, path, file_name);
384 return generator.generate();
387 } // namespace flatbuffers