Squashed 'third_party/flatbuffers/' content from commit acc9990ab

Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/src/idl_gen_lobster.cpp b/src/idl_gen_lobster.cpp
new file mode 100644
index 0000000..ef9e474
--- /dev/null
+++ b/src/idl_gen_lobster.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace lobster {
+
+class LobsterGenerator : public BaseGenerator {
+ public:
+ LobsterGenerator(const Parser &parser, const std::string &path,
+                  const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "" /* not used */, "_") {
+    static const char * const keywords[] = {
+      "nil", "true", "false", "return", "struct", "class", "import", "int",
+      "float", "string", "any", "def", "is", "from", "program", "private",
+      "coroutine", "resource", "enum", "typeof", "var", "let", "pakfile",
+      "switch", "case", "default", "namespace", "not", "and", "or", "bool",
+    };
+    keywords_.insert(std::begin(keywords), std::end(keywords));
+  }
+
+  std::string EscapeKeyword(const std::string &name) const {
+    return keywords_.find(name) == keywords_.end() ? name : name + "_";
+  }
+
+  std::string NormalizedName(const Definition &definition) const {
+    return EscapeKeyword(definition.name);
+  }
+
+  std::string NormalizedName(const EnumVal &ev) const {
+    return EscapeKeyword(ev.name);
+  }
+
+  std::string NamespacedName(const Definition &def) {
+    return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
+  }
+
+  std::string GenTypeName(const Type &type) {
+    auto bits = NumToString(SizeOf(type.base_type) * 8);
+    if (IsInteger(type.base_type)) return "int" + bits;
+    if (IsFloat(type.base_type)) return "float" + bits;
+    if (type.base_type == BASE_TYPE_STRING) return "string";
+    if (type.base_type == BASE_TYPE_STRUCT) return "table";
+    return "none";
+  }
+
+  std::string LobsterType(const Type &type) {
+    if (IsFloat(type.base_type)) return "float";
+    if (IsScalar(type.base_type) && type.enum_def) return NormalizedName(*type.enum_def);
+    if (!IsScalar(type.base_type)) return "flatbuffers_offset";
+    return "int";
+  }
+
+  // Returns the method name for use with add/put calls.
+  std::string GenMethod(const Type &type) {
+    return IsScalar(type.base_type)
+      ? MakeCamel(GenTypeBasic(type))
+      : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
+  }
+
+  // This uses Python names for now..
+  std::string GenTypeBasic(const Type &type) {
+    static const char *ctypename[] = {
+      // clang-format off
+      #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+        #PTYPE,
+      FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+      #undef FLATBUFFERS_TD
+      // clang-format on
+    };
+    return ctypename[type.base_type];
+  }
+
+  // Generate a struct field, conditioned on its child type(s).
+  void GenStructAccessor(const StructDef &struct_def,
+                         const FieldDef &field, std::string *code_ptr) {
+    GenComment(field.doc_comment, code_ptr, nullptr, "    ");
+    std::string &code = *code_ptr;
+    auto offsets = NumToString(field.value.offset);
+    auto def = "    def " + NormalizedName(field);
+    if (IsScalar(field.value.type.base_type)) {
+      std::string acc;
+      if (struct_def.fixed) {
+        acc = "buf_.read_" + GenTypeName(field.value.type) +
+              "_le(pos_ + " + offsets + ")";
+
+      } else {
+        acc = "buf_.flatbuffers_field_" +
+              GenTypeName(field.value.type) + "(pos_, " + offsets + ", " +
+              field.value.constant + ")";
+      }
+      if (field.value.type.enum_def)
+        acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
+      code += def + "():\n        return " + acc + "\n";
+      return;
+    }
+    switch (field.value.type.base_type) {
+      case BASE_TYPE_STRUCT: {
+        auto name = NamespacedName(*field.value.type.struct_def);
+        code += def + "():\n        ";
+        if (struct_def.fixed) {
+          code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
+        } else {
+          code += std::string("let o = buf_.flatbuffers_field_") +
+                  (field.value.type.struct_def->fixed ? "struct" : "table") +
+                  "(pos_, " + offsets + ")\n        return if o: " + name +
+                  " { buf_, o } else: nil\n";
+        }
+        break;
+      }
+      case BASE_TYPE_STRING:
+        code += def + "():\n        return buf_.flatbuffers_field_string(pos_, " +
+                offsets + ")\n";
+        break;
+      case BASE_TYPE_VECTOR: {
+        auto vectortype = field.value.type.VectorType();
+        code += def + "(i:int):\n        return ";
+        if (vectortype.base_type == BASE_TYPE_STRUCT) {
+          auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
+                       ") + i * " + NumToString(InlineSize(vectortype));
+          if (!(vectortype.struct_def->fixed)) {
+            start = "buf_.flatbuffers_indirect(" + start + ")";
+          }
+          code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
+                  start + " }\n";
+        } else {
+          if (vectortype.base_type == BASE_TYPE_STRING)
+            code += "buf_.flatbuffers_string";
+          else
+            code += "buf_.read_" + GenTypeName(vectortype) + "_le";
+          code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
+                  ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
+        }
+        break;
+      }
+      case BASE_TYPE_UNION: {
+        for (auto it = field.value.type.enum_def->Vals().begin();
+             it != field.value.type.enum_def->Vals().end(); ++it) {
+          auto &ev = **it;
+          if (ev.IsNonZero()) {
+            code += def + "_as_" + ev.name + "():\n        return " +
+                    NamespacedName(*ev.union_type.struct_def) +
+                    " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
+                    ") }\n";
+          }
+        }
+        break;
+      }
+      default: FLATBUFFERS_ASSERT(0);
+    }
+    if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+      code += def +
+              "_length():\n        return buf_.flatbuffers_field_vector_len(pos_, " +
+              offsets + ")\n";
+    }
+  }
+
+  // Generate table constructors, conditioned on its members' types.
+  void GenTableBuilders(const StructDef &struct_def,
+                        std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "struct " + NormalizedName(struct_def) +
+            "Builder:\n    b_:flatbuffers_builder\n";
+    code += "    def start():\n        b_.StartObject(" +
+            NumToString(struct_def.fields.vec.size()) + ")\n        return this\n";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      auto offset = it - struct_def.fields.vec.begin();
+      code += "    def add_" + NormalizedName(field) + "(" +
+              NormalizedName(field) + ":" + LobsterType(field.value.type) +
+              "):\n        b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
+              NumToString(offset) + ", " + NormalizedName(field);
+      if (IsScalar(field.value.type.base_type))
+        code += ", " + field.value.constant;
+      code += ")\n        return this\n";
+    }
+    code += "    def end():\n        return b_.EndObject()\n\n";
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+        code += "def " + NormalizedName(struct_def) + "Start" +
+                MakeCamel(NormalizedName(field)) +
+                "Vector(b_:flatbuffers_builder, n_:int):\n    b_.StartVector(";
+        auto vector_type = field.value.type.VectorType();
+        auto alignment = InlineAlignment(vector_type);
+        auto elem_size = InlineSize(vector_type);
+        code += NumToString(elem_size) + ", n_, " + NumToString(alignment) +
+                ")\n";
+        if (vector_type.base_type != BASE_TYPE_STRUCT ||
+            !vector_type.struct_def->fixed) {
+          code += "def " + NormalizedName(struct_def) + "Create" +
+                  MakeCamel(NormalizedName(field)) +
+                  "Vector(b_:flatbuffers_builder, v_:[" +
+                  LobsterType(vector_type) + "]):\n    b_.StartVector(" +
+                  NumToString(elem_size) + ", v_.length, " +
+                  NumToString(alignment) +
+                  ")\n    reverse(v_) e_: b_.Prepend" +
+                  GenMethod(vector_type) +
+                  "(e_)\n    return b_.EndVector(v_.length)\n";
+        }
+        code += "\n";
+      }
+    }
+  }
+
+  void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
+    if (struct_def.generated) return;
+    std::string &code = *code_ptr;
+    CheckNameSpace(struct_def, &code);
+    code += "class " + NormalizedName(struct_def) + "\n\n";
+  }
+
+  // Generate struct or table methods.
+  void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+    if (struct_def.generated) return;
+    std::string &code = *code_ptr;
+    CheckNameSpace(struct_def, &code);
+    GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
+    code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
+    for (auto it = struct_def.fields.vec.begin();
+        it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (field.deprecated) continue;
+      GenStructAccessor(struct_def, field, code_ptr);
+    }
+    code += "\n";
+    if (!struct_def.fixed) {
+      // Generate a special accessor for the table that has been declared as
+      // the root type.
+      code += "def GetRootAs" + NormalizedName(struct_def) + "(buf:string): return " +
+              NormalizedName(struct_def) +
+              " { buf, buf.flatbuffers_indirect(0) }\n\n";
+    }
+    if (struct_def.fixed) {
+      // create a struct constructor function
+      GenStructBuilder(struct_def, code_ptr);
+    } else {
+      // Create a set of functions that allow table construction.
+      GenTableBuilders(struct_def, code_ptr);
+    }
+  }
+
+  // Generate enum declarations.
+  void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+    if (enum_def.generated) return;
+    std::string &code = *code_ptr;
+    CheckNameSpace(enum_def, &code);
+    GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
+    code += "enum " + NormalizedName(enum_def) + ":\n";
+    for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+      auto &ev = **it;
+      GenComment(ev.doc_comment, code_ptr, nullptr, "    ");
+      code += "    " + enum_def.name + "_" + NormalizedName(ev) + " = " +
+              enum_def.ToString(ev) + "\n";
+    }
+    code += "\n";
+  }
+
+  // Recursively generate arguments for a constructor, to deal with nested
+  // structs.
+  void StructBuilderArgs(const StructDef &struct_def,
+                         const char *nameprefix, std::string *code_ptr) {
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      auto &field = **it;
+      if (IsStruct(field.value.type)) {
+        // Generate arguments for a struct inside a struct. To ensure names
+        // don't clash, and to make it obvious these arguments are constructing
+        // a nested struct, prefix the name with the field name.
+        StructBuilderArgs(*field.value.type.struct_def,
+          (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+      } else {
+        std::string &code = *code_ptr;
+        code += ", " + (nameprefix + NormalizedName(field)) + ":" +
+                LobsterType(field.value.type);
+      }
+    }
+  }
+
+  // Recursively generate struct construction statements and instert manual
+  // padding.
+  void StructBuilderBody(const StructDef &struct_def,
+                         const char *nameprefix, std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "    b_.Prep(" + NumToString(struct_def.minalign) + ", " +
+            NumToString(struct_def.bytesize) + ")\n";
+    for (auto it = struct_def.fields.vec.rbegin();
+         it != struct_def.fields.vec.rend(); ++it) {
+      auto &field = **it;
+      if (field.padding)
+        code += "    b_.Pad(" + NumToString(field.padding) + ")\n";
+      if (IsStruct(field.value.type)) {
+        StructBuilderBody(*field.value.type.struct_def,
+          (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+      } else {
+        code += "    b_.Prepend" + GenMethod(field.value.type) + "(" +
+                nameprefix + NormalizedName(field) + ")\n";
+      }
+    }
+  }
+
+  // Create a struct with a builder and the struct's arguments.
+  void GenStructBuilder(const StructDef &struct_def,
+                              std::string *code_ptr) {
+    std::string &code = *code_ptr;
+    code += "def Create" + NormalizedName(struct_def) +
+            "(b_:flatbuffers_builder";
+    StructBuilderArgs(struct_def, "", code_ptr);
+    code += "):\n";
+    StructBuilderBody(struct_def, "", code_ptr);
+    code += "    return b_.Offset()\n\n";
+  }
+
+  void CheckNameSpace(const Definition &def, std::string *code_ptr) {
+    auto ns = GetNameSpace(def);
+    if (ns == current_namespace_) return;
+    current_namespace_ = ns;
+    std::string &code = *code_ptr;
+    code += "namespace " + ns + "\n\n";
+  }
+
+  bool generate() {
+    std::string code;
+    code += std::string("// ") + FlatBuffersGeneratedWarning() +
+            "\nimport flatbuffers\n\n";
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      auto &enum_def = **it;
+      GenEnum(enum_def, &code);
+    }
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      GenStructPreDecl(struct_def, &code);
+    }
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      auto &struct_def = **it;
+      GenStruct(struct_def, &code);
+    }
+    return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(),
+                    code, false);
+  }
+
+ private:
+  std::unordered_set<std::string> keywords_;
+  std::string current_namespace_;
+};
+
+}  // namespace lobster
+
+bool GenerateLobster(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+  lobster::LobsterGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+
+}  // namespace flatbuffers