...

Text file src/github.com/google/flatbuffers/src/idl_gen_lobster.cpp

Documentation: github.com/google/flatbuffers/src

     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